From 7b15d4c0522c1efb7111c7fcfaa4b1a13fb5e279 Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Tue, 28 May 2019 19:09:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96demo=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8Cdemo=E6=B7=BB=E5=8A=A0=E4=BB=A3=E7=A0=81=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AppFrame/build.gradle | 39 +- AppFrame/proguard-rules.pro | 8 + .../java/com/lyy/frame/ApplicationTest.java | 13 + AppFrame/src/main/AndroidManifest.xml | 12 +- .../java/com/arialyy/frame/base/BaseApp.java | 13 + .../com/arialyy/frame/base/BaseDialog.java | 108 ++ .../com/arialyy/frame/base/BaseFragment.java | 19 + .../arialyy/frame/base/BaseViewModule.java | 20 + .../arialyy/frame/base/StatusBarCompat.java | 52 + .../frame/base/net/BasicDeserializer.java | 28 + .../arialyy/frame/base/net/HttpCallback.java | 39 + .../arialyy/frame/base/net/INetResponse.java | 20 + .../frame/base/net/JsonCodeAnalysisUtil.java | 23 + .../arialyy/frame/base/net/NetManager.java | 112 ++ .../arialyy/frame/base/net/OkHttpLogger.java | 65 ++ .../com/arialyy/frame/cache/AbsCache.java | 219 ++-- .../com/arialyy/frame/cache/CacheParam.java | 6 +- .../com/arialyy/frame/cache/CacheUtil.java | 96 +- .../com/arialyy/frame/cache/DiskLruCache.java | 968 ++++++++++++++++++ .../arialyy/frame/cache/PathConstaant.java | 21 + .../arialyy/frame/config/CommonConstant.java | 9 + .../com/arialyy/frame/config/NetConstant.java | 9 + .../com/arialyy/frame/core/AbsActivity.java | 38 +- .../arialyy/frame/core/AbsAlertDialog.java | 15 +- .../com/arialyy/frame/core/AbsDialog.java | 3 - .../arialyy/frame/core/AbsDialogFragment.java | 9 +- .../com/arialyy/frame/core/AbsFragment.java | 1 - .../java/com/arialyy/frame/core/AbsFrame.java | 55 +- .../arialyy/frame/core/AbsPopupWindow.java | 10 +- .../arialyy/frame/core/BindingFactory.java | 6 +- .../com/arialyy/frame/core/CrashHandler.java | 12 +- .../frame/core/DialogSimpleModule.java | 6 +- .../com/arialyy/frame/core/ModuleFactory.java | 4 +- .../java/com/arialyy/frame/http/HttpUtil.java | 62 +- .../com/arialyy/frame/module/AbsModule.java | 21 +- .../com/arialyy/frame/module/IOCProxy.java | 11 +- .../arialyy/frame/module/ModuleFactory.java | 3 +- .../frame/permission/PermissionManager.java | 10 +- .../frame/permission/PermissionUtil.java | 8 +- .../com/arialyy/frame/temp/AbsTempView.java | 4 +- .../java/com/arialyy/frame/temp/TempView.java | 18 +- .../com/arialyy/frame/util/AESEncryption.java | 4 +- .../com/arialyy/frame/util/AndroidUtils.java | 86 +- .../java/com/arialyy/frame/util/AppUtils.java | 6 +- .../com/arialyy/frame/util/DensityUtils.java | 10 +- .../com/arialyy/frame/util/DrawableUtil.java | 9 +- .../java/com/arialyy/frame/util/FileUtil.java | 29 +- .../com/arialyy/frame/util/KeyBoardUtils.java | 11 +- .../com/arialyy/frame/util/MediaUtil.java | 83 ++ .../java/com/arialyy/frame/util/NetUtils.java | 7 +- .../arialyy/frame/util/RegularExpression.java | 5 +- .../com/arialyy/frame/util/ScreenUtil.java | 36 +- .../com/arialyy/frame/util/ShellUtils.java | 3 +- .../com/arialyy/frame/util/StringUtil.java | 2 +- .../java/com/arialyy/frame/util/show/FL.java | 26 +- .../java/com/arialyy/frame/util/show/L.java | 68 +- .../java/com/arialyy/frame/util/show/T.java | 24 +- .../main/res/drawable/selector_green_bt.xml | 24 +- .../src/main/res/layout/layout_error_temp.xml | 4 +- AppFrame/src/main/res/values/color.xml | 6 +- AppFrame/src/main/res/values/strings.xml | 2 +- AppFrame/src/main/res/values/style.xml | 22 +- .../aria/core/download/DownloadEntity.java | 8 + .../com/arialyy/annotations/Download.java | 8 +- README.md | 2 +- app/build.gradle | 5 +- app/src/main/AndroidManifest.xml | 5 + .../main/assets/help_code/FtpDownload.java | 90 ++ app/src/main/assets/help_code/FtpUpload.java | 127 +++ .../main/assets/help_code/HttpDownload.java | 119 +++ .../assets/help_code/KotlinHttpDownload.kt | 170 +++ .../com/arialyy/simple/base/BaseActivity.java | 8 +- .../arialyy/simple/base/BaseApplication.java | 13 +- .../arialyy/simple/common/DialogModule.java | 58 ++ .../simple/common/DirChooseDialog.java | 177 ++++ .../simple/common/ModifyPathDialog.java | 93 ++ .../simple/common/ModifyUrlDialog.java | 4 +- .../simple/core/FullScreenCodeActivity.java | 68 ++ .../simple/core/download/DownloadModule1.java | 95 ++ .../core/download/KotlinDownloadActivity.kt | 311 ++++-- .../core/download/SingleTaskActivity.java | 220 ++-- .../simple/core/test/TestFTPActivity.java | 55 +- .../simple/core/upload/FtpUploadActivity.java | 80 +- .../simple/core/upload/UploadModule.java | 74 ++ .../java/com/arialyy/simple/util/AppUtil.java | 106 ++ .../com/arialyy/simple/widget/CodeView.java | 76 ++ .../arialyy/simple/widget/SvgTextView.java | 5 +- app/src/main/res/drawable/ic_choose_file.xml | 19 +- app/src/main/res/drawable/ic_dir.xml | 6 + app/src/main/res/drawable/ic_full_screen.xml | 4 + app/src/main/res/drawable/ic_modify.xml | 2 +- .../main/res/layout/activity_ftp_upload.xml | 8 + .../res/layout/activity_full_screen_code.xml | 17 + app/src/main/res/layout/activity_single.xml | 61 +- .../res/layout/activity_single_kotlin.xml | 86 ++ app/src/main/res/layout/dialog_choose_dir.xml | 81 ++ .../main/res/layout/dialog_modify_path.xml | 120 +++ app/src/main/res/layout/dialog_modify_url.xml | 3 +- app/src/main/res/layout/item_choose_dir.xml | 31 + app/src/main/res/layout/layout_code_demo.xml | 44 + .../main/res/layout/layout_content_single.xml | 7 - app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/help_code_string.xml | 12 + app/src/main/res/values/strings.xml | 21 +- app/src/main/res/values/styles.xml | 9 +- build.gradle | 9 +- 107 files changed, 4338 insertions(+), 843 deletions(-) create mode 100644 AppFrame/src/androidTest/java/com/lyy/frame/ApplicationTest.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/BaseApp.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/BaseDialog.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/BaseFragment.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/BaseViewModule.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/StatusBarCompat.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/net/BasicDeserializer.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/net/HttpCallback.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/net/INetResponse.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/net/JsonCodeAnalysisUtil.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/net/NetManager.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/base/net/OkHttpLogger.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/cache/DiskLruCache.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/cache/PathConstaant.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/config/CommonConstant.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/config/NetConstant.java create mode 100644 AppFrame/src/main/java/com/arialyy/frame/util/MediaUtil.java create mode 100644 app/src/main/assets/help_code/FtpDownload.java create mode 100644 app/src/main/assets/help_code/FtpUpload.java create mode 100644 app/src/main/assets/help_code/HttpDownload.java create mode 100644 app/src/main/assets/help_code/KotlinHttpDownload.kt create mode 100644 app/src/main/java/com/arialyy/simple/common/DialogModule.java create mode 100644 app/src/main/java/com/arialyy/simple/common/DirChooseDialog.java create mode 100644 app/src/main/java/com/arialyy/simple/common/ModifyPathDialog.java create mode 100644 app/src/main/java/com/arialyy/simple/core/FullScreenCodeActivity.java create mode 100644 app/src/main/java/com/arialyy/simple/core/download/DownloadModule1.java create mode 100644 app/src/main/java/com/arialyy/simple/core/upload/UploadModule.java create mode 100644 app/src/main/java/com/arialyy/simple/util/AppUtil.java create mode 100644 app/src/main/java/com/arialyy/simple/widget/CodeView.java create mode 100644 app/src/main/res/drawable/ic_dir.xml create mode 100644 app/src/main/res/drawable/ic_full_screen.xml create mode 100644 app/src/main/res/layout/activity_full_screen_code.xml create mode 100644 app/src/main/res/layout/activity_single_kotlin.xml create mode 100644 app/src/main/res/layout/dialog_choose_dir.xml create mode 100644 app/src/main/res/layout/dialog_modify_path.xml create mode 100644 app/src/main/res/layout/item_choose_dir.xml create mode 100644 app/src/main/res/layout/layout_code_demo.xml create mode 100644 app/src/main/res/values/help_code_string.xml diff --git a/AppFrame/build.gradle b/AppFrame/build.gradle index e75d329e..af486223 100644 --- a/AppFrame/build.gradle +++ b/AppFrame/build.gradle @@ -1,5 +1,5 @@ apply plugin: 'com.android.library' -//apply plugin: 'com.neenbedankt.android-apt' + android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion @@ -7,8 +7,10 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 61 + versionCode 1 versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -22,18 +24,25 @@ android { } 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' + compile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + testCompile 'junit:junit:4.12' + api "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}" + api 'com.google.code.gson:gson:2.8.2' + api 'io.reactivex:rxandroid:1.2.0' + api 'io.reactivex:rxjava:1.1.5' 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' -} + implementation 'com.squareup.retrofit2:retrofit:2.1.0' + implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0' + implementation 'com.squareup.retrofit2:converter-gson:2.1.0' + implementation 'com.squareup.okhttp3:logging-interceptor:3.2.0' + implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1' + implementation 'com.android.support:multidex:1.0.3' -//apply from: 'jcenter.gradle' + api "android.arch.lifecycle:runtime:${rootProject.ext.lifecycleVersion}" + api "android.arch.lifecycle:extensions:${rootProject.ext.lifecycleVersion}" + annotationProcessor "android.arch.lifecycle:compiler:${rootProject.ext.lifecycleVersion}" + +} diff --git a/AppFrame/proguard-rules.pro b/AppFrame/proguard-rules.pro index e1c786ed..36df18ca 100644 --- a/AppFrame/proguard-rules.pro +++ b/AppFrame/proguard-rules.pro @@ -15,3 +15,11 @@ #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/AppFrame/src/androidTest/java/com/lyy/frame/ApplicationTest.java b/AppFrame/src/androidTest/java/com/lyy/frame/ApplicationTest.java new file mode 100644 index 00000000..f3e7fccd --- /dev/null +++ b/AppFrame/src/androidTest/java/com/lyy/frame/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.lyy.frame; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/AppFrame/src/main/AndroidManifest.xml b/AppFrame/src/main/AndroidManifest.xml index 20730e69..7ae02ec2 100644 --- a/AppFrame/src/main/AndroidManifest.xml +++ b/AppFrame/src/main/AndroidManifest.xml @@ -1,14 +1,12 @@ + package="com.lyy.frame"> - - + android:allowBackup="true" + android:label="@string/app_name" + android:supportsRtl="true"> - + diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/BaseApp.java b/AppFrame/src/main/java/com/arialyy/frame/base/BaseApp.java new file mode 100644 index 00000000..544e0fa3 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/BaseApp.java @@ -0,0 +1,13 @@ +package com.arialyy.frame.base; + +import android.app.Application; +import android.content.Context; + +/** + * Created by AriaL on 2017/11/26. + */ + +public class BaseApp { + public static Context context; + public static Application app; +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/BaseDialog.java b/AppFrame/src/main/java/com/arialyy/frame/base/BaseDialog.java new file mode 100644 index 00000000..215a96c4 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/BaseDialog.java @@ -0,0 +1,108 @@ +package com.arialyy.frame.base; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.IntEvaluator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.app.Dialog; +import android.databinding.ViewDataBinding; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.view.animation.BounceInterpolator; +import com.arialyy.frame.core.AbsDialogFragment; +import com.arialyy.frame.util.AndroidUtils; + +/** + * Created by Aria.Lao on 2017/12/4. + */ + +public abstract class BaseDialog extends AbsDialogFragment { + private WindowManager.LayoutParams mWpm; + private Window mWindow; + protected boolean useDefaultAnim = true; + + @Override protected void init(Bundle savedInstanceState) { + mWindow = getDialog().getWindow(); + if (mWindow != null) { + mWpm = mWindow.getAttributes(); + } + if (mWpm != null && mWindow != null) { + //mView = mWindow.getDecorView(); + mRootView.setBackgroundColor(Color.WHITE); + mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + //in(); + if (useDefaultAnim) { + in1(); + } + } + } + + @Override public void dismiss() { + if (mWpm != null && mWindow != null) { + if (useDefaultAnim) { + out(); + } + } else { + super.dismiss(); + } + } + + @Override protected void dataCallback(int result, Object data) { + + } + + /** + * 进场动画 + */ + private void in() { + int height = AndroidUtils.getScreenParams(getContext())[1]; + ValueAnimator animator = ValueAnimator.ofObject(new IntEvaluator(), -height / 2, 0); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override public void onAnimationUpdate(ValueAnimator animation) { + mWpm.y = (int) animation.getAnimatedValue(); + mWindow.setAttributes(mWpm); + } + }); + animator.setInterpolator(new BounceInterpolator()); //弹跳 + Animator alpha = ObjectAnimator.ofFloat(mRootView, "alpha", 0f, 1f); + AnimatorSet set = new AnimatorSet(); + set.play(animator).with(alpha); + set.setDuration(2000).start(); + } + + private void in1() { + Animator alpha = ObjectAnimator.ofFloat(mRootView, "alpha", 0f, 1f); + alpha.setDuration(800); + alpha.start(); + } + + /** + * 重力动画 + */ + private void out() { + int height = AndroidUtils.getScreenParams(getContext())[1]; + ValueAnimator animator = ValueAnimator.ofObject(new IntEvaluator(), 0, height / 3); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override public void onAnimationUpdate(ValueAnimator animation) { + mWpm.y = (int) animation.getAnimatedValue(); + mWindow.setAttributes(mWpm); + } + }); + Animator alpha = ObjectAnimator.ofFloat(mRootView, "alpha", 1f, 0f); + AnimatorSet set = new AnimatorSet(); + set.play(animator).with(alpha); + set.addListener(new AnimatorListenerAdapter() { + @Override public void onAnimationEnd(Animator animation) { + BaseDialog.super.dismiss(); + } + }); + set.setDuration(600).start(); + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/BaseFragment.java b/AppFrame/src/main/java/com/arialyy/frame/base/BaseFragment.java new file mode 100644 index 00000000..304ffb90 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/BaseFragment.java @@ -0,0 +1,19 @@ +package com.arialyy.frame.base; + +import android.databinding.ViewDataBinding; +import com.arialyy.frame.core.AbsFragment; + +/** + * Created by Aria.Lao on 2017/12/1. + */ +public abstract class BaseFragment extends AbsFragment { + public int color; + + @Override protected void dataCallback(int result, Object obj) { + + } + + @Override protected void onDelayLoad() { + + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/BaseViewModule.java b/AppFrame/src/main/java/com/arialyy/frame/base/BaseViewModule.java new file mode 100644 index 00000000..10523c88 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/BaseViewModule.java @@ -0,0 +1,20 @@ +package com.arialyy.frame.base; + +import android.arch.lifecycle.ViewModel; +import com.arialyy.frame.base.net.NetManager; +import com.arialyy.frame.util.StringUtil; + +/** + * Created by AriaL on 2017/11/26. + * ViewModule只能是public + */ + +public class BaseViewModule extends ViewModel { + protected NetManager mNetManager; + protected String TAG = ""; + + public BaseViewModule() { + mNetManager = NetManager.getInstance(); + TAG = StringUtil.getClassName(this); + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/StatusBarCompat.java b/AppFrame/src/main/java/com/arialyy/frame/base/StatusBarCompat.java new file mode 100644 index 00000000..e808cbb3 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/StatusBarCompat.java @@ -0,0 +1,52 @@ +package com.arialyy.frame.base; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Build; +import android.view.View; +import android.view.ViewGroup; + +public class StatusBarCompat { + private static final int INVALID_VAL = -1; + private static final int COLOR_DEFAULT = Color.parseColor("#20000000"); + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public static void compat(Activity activity, int statusColor) { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (statusColor != INVALID_VAL) { + activity.getWindow().setStatusBarColor(statusColor); + } + return; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT + && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + int color = COLOR_DEFAULT; + ViewGroup contentView = activity.findViewById(android.R.id.content); + if (statusColor != INVALID_VAL) { + color = statusColor; + } + View statusBarView = new View(activity); + ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + getStatusBarHeight(activity)); + statusBarView.setBackgroundColor(color); + contentView.addView(statusBarView, lp); + } + } + + public static void compat(Activity activity) { + compat(activity, INVALID_VAL); + } + + 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; + } +} \ No newline at end of file diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/net/BasicDeserializer.java b/AppFrame/src/main/java/com/arialyy/frame/base/net/BasicDeserializer.java new file mode 100644 index 00000000..0eebed47 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/net/BasicDeserializer.java @@ -0,0 +1,28 @@ +package com.arialyy.frame.base.net; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import java.lang.reflect.Type; + +/** + * 自定义Gson描述 + * Created by “Aria.Lao” on 2016/10/26. + * + * @param 服务器数据实体 + */ +public class BasicDeserializer implements JsonDeserializer { + @Override + public T deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + JsonObject root = element.getAsJsonObject(); + if (JsonCodeAnalysisUtil.isSuccess(root)) { + return new Gson().fromJson(root.get("object"), typeOfT); + } else { + throw new IllegalStateException(root.get("rltmsg").getAsString()); + } + } +} \ No newline at end of file diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/net/HttpCallback.java b/AppFrame/src/main/java/com/arialyy/frame/base/net/HttpCallback.java new file mode 100644 index 00000000..b1def39a --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/net/HttpCallback.java @@ -0,0 +1,39 @@ +package com.arialyy.frame.base.net; + +import com.arialyy.frame.util.show.FL; +import com.arialyy.frame.util.show.L; +import rx.Observable; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Func1; +import rx.schedulers.Schedulers; + +/** + * Created by “Aria.Lao” on 2016/10/26. + * HTTP数据回调 + */ +public abstract class HttpCallback implements INetResponse, Observable.Transformer { + + @Override public void onFailure(Throwable e) { + L.e("HttpCallback", FL.getExceptionString(e)); + } + + @Override public Observable call(Observable observable) { + Observable tObservable = observable.subscribeOn(Schedulers.io()) + .unsubscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .map(new Func1() { + @Override public T call(T t) { + onResponse(t); + return t; + } + }) + .onErrorReturn(new Func1() { + @Override public T call(Throwable throwable) { + onFailure(throwable); + return null; + } + }); + tObservable.subscribe(); + return tObservable; + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/net/INetResponse.java b/AppFrame/src/main/java/com/arialyy/frame/base/net/INetResponse.java new file mode 100644 index 00000000..4aba4e33 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/net/INetResponse.java @@ -0,0 +1,20 @@ +package com.arialyy.frame.base.net; + +/** + * Created by “Aria.Lao” on 2016/10/25. + * 网络响应接口,所有的网络回调都要继承该接口 + * + * @param 数据实体结构 + */ +public interface INetResponse { + + /** + * 网络请求成功 + */ + public void onResponse(T response); + + /** + * 请求失败 + */ + public void onFailure(Throwable e); +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/net/JsonCodeAnalysisUtil.java b/AppFrame/src/main/java/com/arialyy/frame/base/net/JsonCodeAnalysisUtil.java new file mode 100644 index 00000000..4cc6eeb0 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/net/JsonCodeAnalysisUtil.java @@ -0,0 +1,23 @@ +package com.arialyy.frame.base.net; + +import com.google.gson.JsonObject; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Created by AriaL on 2017/11/26. + */ + +public class JsonCodeAnalysisUtil { + + public static boolean isSuccess(JsonObject obj) { + JSONObject object = null; + try { + object = new JSONObject(obj.toString()); + return object.optBoolean("success"); + } catch (JSONException e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/net/NetManager.java b/AppFrame/src/main/java/com/arialyy/frame/base/net/NetManager.java new file mode 100644 index 00000000..71d2f144 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/net/NetManager.java @@ -0,0 +1,112 @@ +package com.arialyy.frame.base.net; + +import android.util.SparseArray; +import com.arialyy.frame.base.BaseApp; +import com.arialyy.frame.config.CommonConstant; +import com.arialyy.frame.config.NetConstant; +import com.franmontiel.persistentcookiejar.ClearableCookieJar; +import com.franmontiel.persistentcookiejar.PersistentCookieJar; +import com.franmontiel.persistentcookiejar.cache.SetCookieCache; +import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor; +import com.google.gson.Gson; +import java.util.concurrent.TimeUnit; +import okhttp3.OkHttpClient; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * Created by “Aria.Lao” on 2016/10/25. + * 网络管理器 + */ +public class NetManager { + private static final Object LOCK = new Object(); + private static volatile NetManager INSTANCE = null; + private static final long TIME_OUT = 8 * 1000; + private Retrofit mRetrofit; + private Retrofit.Builder mBuilder; + private SparseArray mConverterFactorys = new SparseArray<>(); + private ClearableCookieJar mCookieJar; + + private NetManager() { + init(); + } + + public static NetManager getInstance() { + if (INSTANCE == null) { + synchronized (LOCK) { + INSTANCE = new NetManager(); + } + } + return INSTANCE; + } + + OkHttpClient okHttpClient; + + private void init() { + mCookieJar = new PersistentCookieJar(new SetCookieCache(), + new SharedPrefsCookiePersistor(BaseApp.context)); + //OkHttpClient okHttpClient = provideOkHttpClient(); + okHttpClient = provideOkHttpClient(); + } + + public ClearableCookieJar getCookieJar() { + return mCookieJar; + } + + /** + * 执行网络请求 + * + * @param service 服务器返回的实体类型 + * @param gson gson 为传入的数据解析器,ENTITY 为 网络实体 + *

+   *   Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken() {
+   *      }.getType(), new BasicDeserializer()).create();
+   *
+   *   //如启动图,需要将‘ENTITY’替换为启动图实体‘LauncherImgEntity’
+   *   Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken() {
+   *   }.getType(), new BasicDeserializer()).create();
+   *
+   * 
+ */ + public SERVICE request(Class service, Gson gson) { + GsonConverterFactory f = null; + if (gson == null) { + f = GsonConverterFactory.create(); + } else { + f = GsonConverterFactory.create(gson); + } + ; + final Retrofit.Builder builder = new Retrofit.Builder().client(okHttpClient) + .baseUrl(NetConstant.BASE_URL) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()); + builder.addConverterFactory(f); + return builder.build().create(service); + } + + /** + * 创建OKHTTP + */ + private OkHttpClient provideOkHttpClient() { + final OkHttpClient.Builder builder = new OkHttpClient.Builder(); + if (CommonConstant.DEBUG) { + //HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); + //logging.setLevel(HttpLoggingInterceptor.Level.BODY); + //builder.addInterceptor(logging); + builder.addInterceptor(new OkHttpLogger()); + } + builder.connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS) + .readTimeout(TIME_OUT, TimeUnit.MILLISECONDS); + builder.cookieJar(mCookieJar); + //builder.addInterceptor(chain -> { + // //String cookies = CookieUtil.getCookies(); + // Request request = chain.request().newBuilder() + // //.addHeader("Content-Type", "application/x-www-form-urlencoded") + // //.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") + // //.addHeader("Cookie", cookies) + // .build(); + // return chain.proceed(request); + //}); + return builder.build(); + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/base/net/OkHttpLogger.java b/AppFrame/src/main/java/com/arialyy/frame/base/net/OkHttpLogger.java new file mode 100644 index 00000000..f6f023da --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/base/net/OkHttpLogger.java @@ -0,0 +1,65 @@ +package com.arialyy.frame.base.net; + +import com.arialyy.frame.util.show.FL; +import com.arialyy.frame.util.show.L; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.concurrent.TimeUnit; +import okhttp3.Headers; +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.Buffer; +import okio.BufferedSource; + +/** + * Created by Lyy on 2016/9/19. + * 自定义的 OKHTTP 日志 + */ +public class OkHttpLogger implements Interceptor { + final static String TAG = "OKHTTP"; + + @Override public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + long startNs = System.nanoTime(); + Response response = chain.proceed(request); + long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); + ResponseBody responseBody = response.body(); + long contentLength = responseBody.contentLength(); + String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length"; + L.d(TAG, "<-- " + + response.code() + + ' ' + + response.message() + + ' ' + + response.request().url() + + " (" + + tookMs + + "ms" + + (", " + bodySize + " body") + + ')'); + //Headers headers = response.headers(); + //for (int i = 0, count = headers.size(); i < count; i++) { + // FL.d(TAG, headers.name(i) + ": " + headers.value(i)); + //} + BufferedSource source = responseBody.source(); + source.request(Long.MAX_VALUE); // Buffer the entire body. + Buffer buffer = source.buffer(); + Charset UTF8 = Charset.forName("UTF-8"); + Charset charset = UTF8; + MediaType contentType = responseBody.contentType(); + if (contentType != null) { + charset = contentType.charset(UTF8); + } + if (contentLength != 0) { + //FL.j(TAG, buffer.clone().readString(charset)); + L.j(buffer.clone().readString(charset)); + } + + L.d(TAG, "<-- END HTTP (" + buffer.size() + "-byte body)"); + + return response; + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/cache/AbsCache.java b/AppFrame/src/main/java/com/arialyy/frame/cache/AbsCache.java index a9936f09..15ae613c 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/cache/AbsCache.java +++ b/AppFrame/src/main/java/com/arialyy/frame/cache/AbsCache.java @@ -4,25 +4,26 @@ 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.FileUtil; 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. + * Created by Lyy on 2015/4/9. * 缓存抽象类,封装了缓存的读写操作 */ -abstract class AbsCache implements CacheParam { +public abstract class AbsCache implements CacheParam { private static final String TAG = "AbsCache"; - private static final Object LOCK = new Object(); /** * 磁盘缓存工具 */ @@ -35,34 +36,30 @@ abstract class AbsCache implements CacheParam { * 是否使用内存缓存 */ private boolean useMemory = false; - /** - * 是否使用磁盘缓存 - */ - private boolean useDisk = false; - /** - * 最大的内存 - */ - private int mMaxMemoryCacheSize; - /** - * 最大的磁盘大小 - */ - private long mMaxDiskCacheSize; + private int mMaxMemory; private Context mContext; + private static final Object mDiskCacheLock = new Object(); /** * 默认使用默认路径 + * + * @param useMemory 是否使用内存缓存 */ - protected AbsCache(Context context) { - this(context, DEFAULT_DIR); + protected AbsCache(Context context, boolean useMemory) { + this.mContext = context; + this.useMemory = useMemory; + init(DEFAULT_DIR, 1, SMALL_DISK_CACHE_CAPACITY); } /** * 指定缓存文件夹 * + * @param useMemory 是否使用内存缓存 * @param cacheDir 缓存文件夹 */ - AbsCache(Context context, @NonNull String cacheDir) { + protected AbsCache(Context context, boolean useMemory, @NonNull String cacheDir) { this.mContext = context; + this.useMemory = useMemory; init(cacheDir, 1, SMALL_DISK_CACHE_CAPACITY); } @@ -74,7 +71,7 @@ abstract class AbsCache implements CacheParam { /** * 初始化磁盘缓存 */ - private void initDiskCache(String cacheDir, int valueCount, long cacheSize) { + protected void initDiskCache(String cacheDir, int valueCount, long cacheSize) { try { File dir = getDiskCacheDir(mContext, cacheDir); if (!dir.exists()) { @@ -90,35 +87,29 @@ abstract class AbsCache implements CacheParam { /** * 初始化内存缓存 */ - private void initMemoryCache() { - if (!useMemory) return; + protected void initMemoryCache() { + if (!useMemory) { + return; + } // 获取应用程序最大可用内存 - mMaxMemoryCacheSize = (int) Runtime.getRuntime().maxMemory(); + mMaxMemory = (int) Runtime.getRuntime().maxMemory(); // 设置图片缓存大小为程序最大可用内存的1/8 - mMemoryCache = new LruCache<>(mMaxMemoryCacheSize / 8); + mMemoryCache = new LruCache<>(mMaxMemory / 8); } /** * 是否使用内存缓存 */ - void setUseMemory(boolean useMemory) { + protected void setUseMemory(boolean useMemory) { this.useMemory = useMemory; - } - - /** - * 是否使用磁盘缓存 - */ - void setUseDisk(boolean useDisk) { - this.useDisk = useDisk; + initMemoryCache(); } /** * 设置内存缓存大小 */ - void setMemoryCacheSize(int size) { - if (useMemory && mMemoryCache != null) { - mMemoryCache.resize(size); - } + protected void setMemoryCache(int size) { + mMemoryCache.resize(size); } /** @@ -129,8 +120,8 @@ abstract class AbsCache implements CacheParam { * @param cacheSize 缓存大小 * @see CacheParam */ - void openDiskCache(@NonNull String cacheDir, int valueCount, long cacheSize) { - synchronized (LOCK) { + protected void openDiskCache(@NonNull String cacheDir, int valueCount, long cacheSize) { + synchronized (mDiskCacheLock) { if (mDiskLruCache != null && mDiskLruCache.isClosed()) { try { File dir = getDiskCacheDir(mContext, cacheDir); @@ -152,41 +143,35 @@ abstract class AbsCache implements CacheParam { * @param key 缓存的key,通过该key来读写缓存,一般是URL * @param data 缓存的数据 */ - void writeDiskCache(@NonNull String key, @NonNull byte[] data) { + protected 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(); - } + synchronized (mDiskCacheLock) { + 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(); } } } @@ -200,7 +185,7 @@ abstract class AbsCache implements CacheParam { * @param key 缓存的key,一般是原来的url * @return 缓存数据 */ - byte[] readDiskCache(@NonNull String key) { + protected byte[] readDiskCache(@NonNull String key) { if (TextUtils.isEmpty(key)) { return null; } @@ -211,32 +196,37 @@ abstract class AbsCache implements CacheParam { 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(); - } + synchronized (mDiskCacheLock) { + 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 (IOException e) { + FL.e(this, "readDiskCacheFailed[key:" + + key + + ",hashKey:" + + hashKey + + "]\n" + + FL.getExceptionString(e)); + } 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(); } } } @@ -254,7 +244,7 @@ abstract class AbsCache implements CacheParam { if (mMemoryCache != null) { mMemoryCache.remove(hashKey); } - synchronized (LOCK) { + synchronized (mDiskCacheLock) { if (mDiskLruCache != null) { try { mDiskLruCache.remove(hashKey); @@ -270,23 +260,14 @@ abstract class AbsCache implements CacheParam { } } - /** - * 关闭内存缓存 - */ - void closeMemoryCache() { - if (mMemoryCache != null) { - mMemoryCache.evictAll(); - } - } - /** * 清除所有缓存 */ - void clearCache() { + protected void clearCache() { if (mMemoryCache != null) { mMemoryCache.evictAll(); } - synchronized (LOCK) { + synchronized (mDiskCacheLock) { if (mDiskLruCache != null) { try { mDiskLruCache.delete(); @@ -303,8 +284,8 @@ abstract class AbsCache implements CacheParam { * 关闭掉了之后就不能再调用DiskLruCache中任何操作缓存数据的方法, * 通常只应该在Activity的onDestroy()方法中去调用close()方法。 */ - void closeDiskCache() { - synchronized (LOCK) { + protected void closeDiskCache() { + synchronized (mDiskCacheLock) { if (mDiskLruCache != null) { try { mDiskLruCache.close(); @@ -320,8 +301,8 @@ abstract class AbsCache implements CacheParam { * 注意:在写入缓存时需要flush同步一次,并不是每次写入缓存都要调用一次flush()方法的,频繁地调用并不会带来任何好处, * 只会额外增加同步journal文件的时间。比较标准的做法就是在Activity的onPause()方法中去调用一次flush()方法就可以了 */ - void flushDiskCache() { - synchronized (LOCK) { + protected void flushDiskCache() { + synchronized (mDiskCacheLock) { if (mDiskLruCache != null) { try { mDiskLruCache.flush(); @@ -339,16 +320,6 @@ abstract class AbsCache implements CacheParam { 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 */ @@ -364,4 +335,14 @@ abstract class AbsCache implements CacheParam { } return sb.toString(); } + + /** + * 生成缓存文件夹 + * + * @param uniqueName 缓存文件夹名 + * @return 缓存文件夹 + */ + public static File getDiskCacheDir(Context context, String uniqueName) { + return new File(AndroidUtils.getDiskCacheDir(context) + File.separator + uniqueName); + } } diff --git a/AppFrame/src/main/java/com/arialyy/frame/cache/CacheParam.java b/AppFrame/src/main/java/com/arialyy/frame/cache/CacheParam.java index c243b642..783bab70 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/cache/CacheParam.java +++ b/AppFrame/src/main/java/com/arialyy/frame/cache/CacheParam.java @@ -1,10 +1,10 @@ package com.arialyy.frame.cache; /** - * Created by “AriaLyy@outlook.com” on 2015/4/9. + * Created by Lyy on 2015/4/9. * 缓存参数 */ -interface CacheParam { +public interface CacheParam { /** * 磁盘缓存 @@ -17,7 +17,7 @@ interface CacheParam { /** * 内存缓存 */ - public static final int MEMORY_CACHE_SIZE = 4 * 1024 * 1024; + public static final int MEMORY_CACHE_SIZE = 1; /** * 小容量磁盘缓存 */ diff --git a/AppFrame/src/main/java/com/arialyy/frame/cache/CacheUtil.java b/AppFrame/src/main/java/com/arialyy/frame/cache/CacheUtil.java index 84873664..5a1dad4b 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/cache/CacheUtil.java +++ b/AppFrame/src/main/java/com/arialyy/frame/cache/CacheUtil.java @@ -3,13 +3,15 @@ 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. + * Created by AriaLyy on 2015/4/9. * 缓存工具 */ public class CacheUtil extends AbsCache { @@ -17,32 +19,28 @@ public class CacheUtil extends AbsCache { /** * 默认使用默认路径 + * + * @param useMemory 是否使用内存缓存 */ - private CacheUtil(Context context) { - this(context, DEFAULT_DIR); + public CacheUtil(Context context, boolean useMemory) { + super(context, useMemory); } /** * 指定缓存文件夹 * - * @param cacheDir 缓存文件夹名 - */ - private CacheUtil(Context context, @NonNull String cacheDir) { - super(context, cacheDir); - } - - /** - * 是否使用内存缓存 + * @param useMemory 是否使用内存缓存 + * @param cacheDir 缓存文件夹 */ - private void setUseMemoryCache(boolean openMemoryCache) { - setUseMemory(openMemoryCache); + public CacheUtil(Context context, boolean useMemory, @NonNull String cacheDir) { + super(context, useMemory, cacheDir); } /** - * 是否使用磁场缓存 + * 设置是否使用内存缓存 */ - private void setUseDiskCache(boolean openDiskCache) { - setUseMemory(openDiskCache); + public void setUseMemoryCache(boolean useMemoryCache) { + setUseMemory(useMemoryCache); } /** @@ -180,15 +178,14 @@ public class CacheUtil extends AbsCache { /** * 删除所有缓存 */ - public void clearCache() { - super.clearCache(); + public void removeAll() { + clearCache(); } /** * 关闭磁盘缓存 */ public void close() { - closeMemoryCache(); closeDiskCache(); } @@ -198,65 +195,4 @@ public class CacheUtil extends AbsCache { 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); - } - } } diff --git a/AppFrame/src/main/java/com/arialyy/frame/cache/DiskLruCache.java b/AppFrame/src/main/java/com/arialyy/frame/cache/DiskLruCache.java new file mode 100644 index 00000000..48c60fb0 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/cache/DiskLruCache.java @@ -0,0 +1,968 @@ +/* + * 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; + +import java.io.BufferedInputStream; +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.FileWriter; +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.Reader; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Array; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * ***************************************************************************** + * Taken from the JB source code, can be found in: + * libcore/luni/src/main/java/libcore/io/DiskLruCache.java + * or direct link: + * https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java + * ***************************************************************************** + * + * 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. Values are byte + * sequences, accessible as streams or files. Each value must be between {@code + * 0} and {@code Integer.MAX_VALUE} bytes in length. + * + * 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. + * + * 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. + * + * 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. + * + * When an entry is being created it is necessary to + * supply a full set of values; the empty value should be used as a + * placeholder if necessary. + * When an entry is being edited, it is not necessary + * to supply data for every value; values default to their previous + * value. + * + * 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. + * + * 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_TMP = "journal.tmp"; + static final String MAGIC = "libcore.io.DiskLruCache"; + static final String VERSION_1 = "1"; + static final long ANY_SEQUENCE_NUMBER = -1; + private static final String CLEAN = "CLEAN"; + private static final String DIRTY = "DIRTY"; + private static final String REMOVE = "REMOVE"; + private static final String READ = "READ"; + + private static final Charset UTF_8 = Charset.forName("UTF-8"); + private static final int IO_BUFFER_SIZE = 8 * 1024; + + /* + * 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 int appVersion; + private final long maxSize; + private final int valueCount; + private long size = 0; + private Writer journalWriter; + private final LinkedHashMap lruEntries = + new LinkedHashMap(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; + + /* From java.util.Arrays */ + @SuppressWarnings("unchecked") + private static T[] copyOfRange(T[] original, int start, int end) { + final int originalLength = original.length; // For exception priority compatibility. + if (start > end) { + throw new IllegalArgumentException(); + } + if (start < 0 || start > originalLength) { + throw new ArrayIndexOutOfBoundsException(); + } + final int resultLength = end - start; + final int copyLength = Math.min(resultLength, originalLength - start); + final T[] result = + (T[]) Array.newInstance(original.getClass().getComponentType(), resultLength); + System.arraycopy(original, start, result, 0, copyLength); + return result; + } + + /** + * Returns the remainder of 'reader' as a string, closing it when done. + */ + public 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(); + } + } + + /** + * Returns the ASCII characters up to but not including the next "\r\n", or + * "\n". + * + * @throws EOFException if the stream is exhausted before the next newline + * character. + */ + public static String readAsciiLine(InputStream in) throws IOException { + + StringBuilder result = new StringBuilder(80); + while (true) { + int c = in.read(); + if (c == -1) { + throw new EOFException(); + } else if (c == '\n') { + break; + } + + result.append((char) c); + } + int length = result.length(); + if (length > 0 && result.charAt(length - 1) == '\r') { + result.setLength(length - 1); + } + return result.toString(); + } + + /** + * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. + */ + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + + /** + * Recursively delete everything in {@code dir}. + */ + // TODO: this should specify paths as Strings rather than as Files + public static void deleteContents(File dir) throws IOException { + File[] files = dir.listFiles(); + if (files == null) { + throw new IllegalArgumentException("not a directory: " + dir); + } + for (File file : files) { + if (file.isDirectory()) { + deleteContents(file); + } + if (!file.delete()) { + throw new IOException("failed to delete file: " + file); + } + } + } + + /** + * This cache uses a single background thread to evict entries. + */ + private final ExecutorService executorService = + new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue()); + private final Callable cleanupCallable = new Callable() { + @Override + 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_TMP); + 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"); + } + + // 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(); + cache.journalWriter = + new BufferedWriter(new FileWriter(cache.journalFile, true), IO_BUFFER_SIZE); + return cache; + } catch (IOException journalIsCorrupt) { + // System.logW("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 { + InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE); + try { + String magic = readAsciiLine(in); + String version = readAsciiLine(in); + String appVersionString = readAsciiLine(in); + String valueCountString = readAsciiLine(in); + String blank = readAsciiLine(in); + 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 + + "]"); + } + + while (true) { + try { + readJournalLine(readAsciiLine(in)); + } catch (EOFException endOfJournal) { + break; + } + } + } finally { + closeQuietly(in); + } + } + + private void readJournalLine(String line) throws IOException { + String[] parts = line.split(" "); + if (parts.length < 2) { + throw new IOException("unexpected journal line: " + line); + } + + String key = parts[1]; + if (parts[0].equals(REMOVE) && parts.length == 2) { + lruEntries.remove(key); + return; + } + + Entry entry = lruEntries.get(key); + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } + + if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) { + entry.readable = true; + entry.currentEditor = null; + entry.setLengths(copyOfRange(parts, 2, parts.length)); + } else if (parts[0].equals(DIRTY) && parts.length == 2) { + entry.currentEditor = new Editor(entry); + } else if (parts[0].equals(READ) && parts.length == 2) { + // 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 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 FileWriter(journalFileTmp), IO_BUFFER_SIZE); + 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'); + } + } + + writer.close(); + journalFileTmp.renameTo(journalFile); + journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE); + } + + private static void deleteIfExists(File file) throws IOException { + // try { + // Libcore.os.remove(file.getPath()); + // } catch (ErrnoException errnoException) { + // if (errnoException.errno != OsConstants.ENOENT) { + // throw errnoException.rethrowAsIOException(); + // } + // } + if (file.exists() && !file.delete()) { + 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! + return null; + } + + redundantOpCount++; + journalWriter.append(READ + ' ' + key + '\n'); + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + + return new Snapshot(key, entry.sequenceNumber, ins); + } + + /** + * 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 long maxSize() { + return maxSize; + } + + /** + * 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 (!entry.getDirtyFile(i).exists()) { + editor.abort(); + throw new IllegalStateException("edit didn't create file " + i); + } + } + } + + 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'); + } + + 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 REDUNDANT_OP_COMPACT_THRESHOLD = 2000; + return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD + && 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.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 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(lruEntries.values())) { + if (entry.currentEditor != null) { + entry.currentEditor.abort(); + } + } + trimToSize(); + journalWriter.close(); + journalWriter = null; + } + + private void trimToSize() throws IOException { + while (size > maxSize) { + // Map.Entry toEvict = lruEntries.eldest(); + final Map.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(); + deleteContents(directory); + } + + private void validateKey(String key) { + if (key.contains(" ") || key.contains("\n") || key.contains("\r")) { + throw new IllegalArgumentException( + "keys must not contain spaces or newlines: \"" + key + "\""); + } + } + + private static String inputStreamToString(InputStream in) throws IOException { + return readFully(new InputStreamReader(in, 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 Snapshot(String key, long sequenceNumber, InputStream[] ins) { + this.key = key; + this.sequenceNumber = sequenceNumber; + this.ins = ins; + } + + /** + * 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)); + } + + @Override + public void close() { + for (InputStream in : ins) { + closeQuietly(in); + } + } + } + + /** + * Edits the values for an entry. + */ + public final class Editor { + private final Entry entry; + private boolean hasErrors; + + private Editor(Entry entry) { + this.entry = entry; + } + + /** + * 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; + } + return new FileInputStream(entry.getCleanFile(index)); + } + } + + /** + * 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 { + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index))); + } + } + + /** + * 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), UTF_8); + writer.write(value); + } finally { + 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); + } + } + + /** + * 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); + } + + 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: " + 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"); + } + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/cache/PathConstaant.java b/AppFrame/src/main/java/com/arialyy/frame/cache/PathConstaant.java new file mode 100644 index 00000000..dd17a25e --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/cache/PathConstaant.java @@ -0,0 +1,21 @@ +package com.arialyy.frame.cache; + +import android.os.Environment; + +/** + * Created by AriaL on 2017/11/26. + */ + +public class PathConstaant { + private static final String WP_DIR = "windPath"; + + /** + * 获取APK升级路径 + */ + public static String getWpPath() { + return Environment.getExternalStorageDirectory().getPath() + + "/" + + WP_DIR + + "/update/windPath.apk"; + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/config/CommonConstant.java b/AppFrame/src/main/java/com/arialyy/frame/config/CommonConstant.java new file mode 100644 index 00000000..13ed8690 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/config/CommonConstant.java @@ -0,0 +1,9 @@ +package com.arialyy.frame.config; + +/** + * Created by AriaL on 2017/11/26. + */ + +public interface CommonConstant { + boolean DEBUG = true; +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/config/NetConstant.java b/AppFrame/src/main/java/com/arialyy/frame/config/NetConstant.java new file mode 100644 index 00000000..2d326151 --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/config/NetConstant.java @@ -0,0 +1,9 @@ +package com.arialyy.frame.config; + +/** + * Created by AriaL on 2017/11/26. + */ + +public interface NetConstant { + String BASE_URL = "http://wwww.baidu.com/"; +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/AbsActivity.java b/AppFrame/src/main/java/com/arialyy/frame/core/AbsActivity.java index f2272ba4..19bb0d57 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/AbsActivity.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/AbsActivity.java @@ -8,6 +8,7 @@ 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; @@ -17,25 +18,26 @@ import com.arialyy.frame.util.StringUtil; import com.arialyy.frame.util.show.T; /** - * Created by “AriaLyy@outlook.com” on 2015/11/3. + * Created by lyy on 2015/11/3. * 所有的 Activity都应该继承这个类 */ public abstract class AbsActivity 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; + protected AbsFrame mAm; + protected View mRootView; private ModuleFactory mModuleF; + protected AbsTempView mTempView; + protected boolean useTempView = true; - @Override protected void onCreate(Bundle savedInstanceState) { + @Override + protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initialization(); init(savedInstanceState); @@ -55,12 +57,6 @@ public abstract class AbsActivity extends AppCompatA } } - protected void reNewModule() { - if (mModuleF == null) { - mModuleF = ModuleFactory.newInstance(); - } - } - /** * 获取填充View */ @@ -115,7 +111,8 @@ public abstract class AbsActivity extends AppCompatA */ protected void hintTempView(int delay) { new Handler().postDelayed(new Runnable() { - @Override public void run() { + @Override + public void run() { if (mTempView == null || !useTempView) { return; } @@ -126,11 +123,13 @@ public abstract class AbsActivity extends AppCompatA }, delay); } - @Override public void onBtTempClick(View view, int type) { + @Override + public void onBtTempClick(View view, int type) { } - @Override protected void onDestroy() { + @Override + protected void onDestroy() { super.onDestroy(); } @@ -138,7 +137,8 @@ public abstract class AbsActivity extends AppCompatA } - @Override public void finish() { + @Override + public void finish() { super.finish(); mAm.removeActivity(this); } @@ -228,13 +228,15 @@ public abstract class AbsActivity extends AppCompatA mAm.exitApp(false); } - @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @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) { + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); PermissionHelp.getInstance() .handleSpecialPermissionCallback(this, requestCode, resultCode, data); diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/AbsAlertDialog.java b/AppFrame/src/main/java/com/arialyy/frame/core/AbsAlertDialog.java index 2d854a00..34a5f2c0 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/AbsAlertDialog.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/AbsAlertDialog.java @@ -3,9 +3,9 @@ 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; @@ -34,12 +34,15 @@ public abstract class AbsAlertDialog extends DialogFragment { mObj = obj; } - @Override public void onCreate(Bundle savedInstanceState) { + @Override + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initDialog(); } - @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { return mDialog; } @@ -98,13 +101,15 @@ public abstract class AbsAlertDialog extends DialogFragment { protected abstract void dataCallback(int result, Object obj); - @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @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) { + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); PermissionHelp.getInstance() .handleSpecialPermissionCallback(getContext(), requestCode, resultCode, data); diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/AbsDialog.java b/AppFrame/src/main/java/com/arialyy/frame/core/AbsDialog.java index 7ac41cfc..583f03de 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/AbsDialog.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/AbsDialog.java @@ -2,16 +2,13 @@ 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 diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/AbsDialogFragment.java b/AppFrame/src/main/java/com/arialyy/frame/core/AbsDialogFragment.java index 3e056023..58a97170 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/AbsDialogFragment.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/AbsDialogFragment.java @@ -18,6 +18,7 @@ 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 @@ -61,10 +62,6 @@ public abstract class AbsDialogFragment extends Dial return mRootView; } - public V findViewById(@IdRes int id) { - return mRootView.findViewById(id); - } - @Override public void onAttach(Activity activity) { super.onAttach(activity); if (activity instanceof AbsActivity) { @@ -72,6 +69,10 @@ public abstract class AbsDialogFragment extends Dial } } + public T findViewById(@IdRes int id){ + return mRootView.findViewById(id); + } + private void initFragment() { TAG = StringUtil.getClassName(this); mProxy = IOCProxy.newInstance(this); diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/AbsFragment.java b/AppFrame/src/main/java/com/arialyy/frame/core/AbsFragment.java index 42f20852..c44de757 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/AbsFragment.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/AbsFragment.java @@ -29,7 +29,6 @@ import com.arialyy.frame.util.show.L; import java.lang.reflect.Field; - /** * Created by lyy on 2015/11/4. * 基础Fragment diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/AbsFrame.java b/AppFrame/src/main/java/com/arialyy/frame/core/AbsFrame.java index 39486428..5dc34ee7 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/AbsFrame.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/AbsFrame.java @@ -1,15 +1,16 @@ package com.arialyy.frame.core; import android.app.ActivityManager; +import android.app.Application; import android.content.Context; -import android.os.Process; + +import com.arialyy.frame.base.BaseApp; 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. + * Created by lyy on 2015/11/4. * APP生命周期管理类管理 */ public class AbsFrame { @@ -23,18 +24,20 @@ public class AbsFrame { } - private AbsFrame(Context context) { - mContext = context; + private AbsFrame(Application application) { + mContext = application.getApplicationContext(); + BaseApp.context = mContext; + BaseApp.app = application; } /** * 初始化框架 */ - public static AbsFrame init(Context applicationContext) { + public static AbsFrame init(Application app) { if (mManager == null) { synchronized (LOCK) { if (mManager == null) { - mManager = new AbsFrame(applicationContext); + mManager = new AbsFrame(app); } } } @@ -51,18 +54,6 @@ public class AbsFrame { return mManager; } - /** - * activity 是否存在 - */ - public boolean activityExists(Class clazz) { - for (AbsActivity activity : mActivityStack) { - if (activity.getClass().getName().equals(clazz.getName())) { - return true; - } - } - return false; - } - /** * 获取Activity栈 */ @@ -72,7 +63,7 @@ public class AbsFrame { /** * 开启异常捕获 - * 日志文件位于/data/data/Package Name/cache//crash/2016.10.26_AbsExceptionFile.crash + * 日志文件位于/data/data/Package Name/cache//crash/AbsExceptionFile.crash */ public void openCrashHandler() { openCrashHandler("", ""); @@ -137,6 +128,7 @@ public class AbsFrame { */ public void finishActivity(AbsActivity activity) { if (activity != null) { + mActivityStack.remove(activity); activity.finish(); } } @@ -146,10 +138,7 @@ public class AbsFrame { */ public void removeActivity(AbsActivity activity) { if (activity != null) { - int i = mActivityStack.search(activity); - if (i != -1) { - mActivityStack.remove(activity); - } + mActivityStack.remove(activity); } } @@ -157,12 +146,9 @@ public class AbsFrame { * 结束指定类名的Activity */ public void finishActivity(Class cls) { - Iterator iter = mActivityStack.iterator(); - while (iter.hasNext()) { - AbsActivity activity = iter.next(); - if (activity.getClass().getName().equals(cls.getName())) { - iter.remove(); - activity.finish(); + for (AbsActivity activity : mActivityStack) { + if (activity.getClass().equals(cls)) { + finishActivity(activity); } } } @@ -187,16 +173,15 @@ public class AbsFrame { public void exitApp(Boolean isBackground) { try { finishAllActivity(); - //ActivityManager activityMgr = - // (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); - //activityMgr.restartPackage(mContext.getPackageName()); + 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()); } } } diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/AbsPopupWindow.java b/AppFrame/src/main/java/com/arialyy/frame/core/AbsPopupWindow.java index 7715d50e..053bc285 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/AbsPopupWindow.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/AbsPopupWindow.java @@ -9,12 +9,10 @@ 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悬浮框 @@ -22,7 +20,7 @@ import com.arialyy.frame.util.StringUtil; public abstract class AbsPopupWindow extends PopupWindow { protected String TAG; - private static Context mContext; + private Context mContext; private Drawable mBackground; protected View mView; private Object mObj; @@ -62,14 +60,14 @@ public abstract class AbsPopupWindow extends PopupWindow { TAG = StringUtil.getClassName(this); // 设置SelectPicPopupWindow弹出窗体的宽 setWidth(ViewGroup.LayoutParams.MATCH_PARENT); - // 设置SelectPicPopupWindow弹出窗体的高 - setHeight(ViewGroup.LayoutParams.MATCH_PARENT); + //// 设置SelectPicPopupWindow弹出窗体的高 + setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); setFocusable(true); // 设置SelectPicPopupWindow弹出窗体动画效果 // setAnimationStyle(R.style.wisdom_anim_style); // 实例化一个ColorDrawable颜色为半透明 if (mBackground == null) { - mBackground = new ColorDrawable(Color.parseColor("#7f000000")); + mBackground = new ColorDrawable(Color.parseColor("#4f000000")); } // 设置SelectPicPopupWindow弹出窗体的背景 setBackgroundDrawable(mBackground); diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/BindingFactory.java b/AppFrame/src/main/java/com/arialyy/frame/core/BindingFactory.java index 578f6b28..2b71abe4 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/BindingFactory.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/BindingFactory.java @@ -1,9 +1,9 @@ package com.arialyy.frame.core; - import android.databinding.ViewDataBinding; + +import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; /** * Created by lyy on 2016/9/16. @@ -12,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap; public class BindingFactory { private final String TAG = "BindingFactory"; - private Map mBindings = new ConcurrentHashMap<>(); + private Map mBindings = new HashMap<>(); private BindingFactory() { diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/CrashHandler.java b/AppFrame/src/main/java/com/arialyy/frame/core/CrashHandler.java index 2b02d561..62897f4c 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/CrashHandler.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/CrashHandler.java @@ -2,11 +2,13 @@ package com.arialyy.frame.core; import android.Manifest; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Build; import android.os.Looper; import android.text.TextUtils; import com.arialyy.frame.http.HttpUtil; +import com.arialyy.frame.permission.PermissionManager; import com.arialyy.frame.util.AndroidUtils; import com.arialyy.frame.util.CalendarUtils; import com.arialyy.frame.util.FileUtil; @@ -64,7 +66,8 @@ final class CrashHandler implements Thread.UncaughtExceptionHandler { mPramKey = key; } - @Override public void uncaughtException(Thread thread, Throwable ex) { + @Override + public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex) && mDefaultHandler != null) { mDefaultHandler.uncaughtException(thread, ex); } else { @@ -90,7 +93,8 @@ final class CrashHandler implements Thread.UncaughtExceptionHandler { } //在这里处理崩溃逻辑,将不再显示FC对话框 new Thread() { - @Override public void run() { + @Override + public void run() { Looper.prepare(); T.showLong(mContext, "很抱歉,程序出现异常,即将退出"); Looper.loop(); @@ -111,8 +115,8 @@ final class CrashHandler implements Thread.UncaughtExceptionHandler { 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 (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); diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/DialogSimpleModule.java b/AppFrame/src/main/java/com/arialyy/frame/core/DialogSimpleModule.java index b0af6322..2a868622 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/DialogSimpleModule.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/DialogSimpleModule.java @@ -25,7 +25,8 @@ public class DialogSimpleModule extends AbsModule { /** * 可设置参数和回调名的回调函数 */ - @Deprecated public void onDialog(String methodName, Class param, Object data) { + @Deprecated + public void onDialog(String methodName, Class param, Object data) { callback(methodName, param, data); } @@ -34,7 +35,8 @@ public class DialogSimpleModule extends AbsModule { * * @param b 需要回调的数据 */ - @Deprecated public void onDialog(Bundle b) { + @Deprecated + public void onDialog(Bundle b) { callback("onDialog", Bundle.class, b); } } diff --git a/AppFrame/src/main/java/com/arialyy/frame/core/ModuleFactory.java b/AppFrame/src/main/java/com/arialyy/frame/core/ModuleFactory.java index 0f99fec2..2f16b3f9 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/core/ModuleFactory.java +++ b/AppFrame/src/main/java/com/arialyy/frame/core/ModuleFactory.java @@ -8,7 +8,6 @@ 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. @@ -18,7 +17,7 @@ public class ModuleFactory { private final String TAG = "ModuleFactory"; - private Map mModules = new ConcurrentHashMap<>(); + private Map mModules = new HashMap<>(); private ModuleFactory() { @@ -50,7 +49,6 @@ public class ModuleFactory { Object[] params = { context }; try { Constructor con = clazz.getConstructor(paramTypes); - con.setAccessible(true); T module = con.newInstance(params); mModules.put(clazz.hashCode(), module); return module; diff --git a/AppFrame/src/main/java/com/arialyy/frame/http/HttpUtil.java b/AppFrame/src/main/java/com/arialyy/frame/http/HttpUtil.java index f6cf56a4..3f11c65f 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/http/HttpUtil.java +++ b/AppFrame/src/main/java/com/arialyy/frame/http/HttpUtil.java @@ -36,7 +36,7 @@ import okhttp3.RequestBody; import okhttp3.Response; /** - * Created by “AriaLyy@outlook.com” on 2015/11/5. + * Created by lyy on 2015/11/5. * 网络连接工具 */ public class HttpUtil { @@ -56,7 +56,7 @@ public class HttpUtil { private HttpUtil(Context context) { mContext = context; - mCacheUtil = new CacheUtil.Builder(context).openDiskCache().build(); + mCacheUtil = new CacheUtil(mContext, false); mHandler = new Handler(Looper.getMainLooper()); } @@ -110,10 +110,12 @@ public class HttpUtil { * @param key 上传文件键值 */ public void uploadFile(@NonNull final String url, @NonNull final String filePath, - @NonNull final String key, final String contentType, final Map header, + @NonNull final String key, + final String contentType, final Map header, @NonNull final IResponse absResponse) { new Thread(new Runnable() { - @Override public void run() { + @Override + public void run() { File file = new File(filePath); String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成 String PREFIX = "--", LINE_END = "\r\n"; @@ -131,9 +133,10 @@ public class HttpUtil { conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY); if (header != null && header.size() > 0) { - Set keys = header.keySet(); - for (String key : keys) { - conn.setRequestProperty(key, header.get(key)); + Set set = header.entrySet(); + for (Object aSet : set) { + Map.Entry entry = (Map.Entry) aSet; + conn.setRequestProperty(entry.getKey() + "", entry.getValue() + ""); } } OutputStream outputSteam = conn.getOutputStream(); @@ -193,12 +196,13 @@ public class HttpUtil { L.v(TAG, "请求链接 >>>> " + url); String requestUrl = url; if (params != null && params.size() > 0) { - Set keys = params.keySet(); + Set set = params.entrySet(); int i = 0; requestUrl += "?"; - for (String key : keys) { + for (Object aSet : set) { i++; - requestUrl += key + "=" + params.get(key) + (i < params.size() ? "&" : ""); + Map.Entry entry = (Map.Entry) aSet; + requestUrl += entry.getKey() + "=" + entry.getValue() + (i < params.size() ? "&" : ""); } L.v(TAG, "请求参数为 >>>> "); L.m(params); @@ -213,7 +217,8 @@ public class HttpUtil { //请求加入调度 call.enqueue(new Callback() { - @Override public void onFailure(Call call, IOException e) { + @Override + public void onFailure(Call call, IOException e) { L.e(TAG, "请求链接【" + url + "】失败"); String data = null; if (useCache) { @@ -228,7 +233,8 @@ public class HttpUtil { } } - @Override public void onResponse(Call call, Response response) throws IOException { + @Override + public void onResponse(Call call, Response response) throws IOException { String data = response.body().string(); L.d(TAG, "数据获取成功,获取到的数据为 >>>> "); L.j(data); @@ -256,18 +262,20 @@ public class HttpUtil { //头数据 Headers.Builder hb = new Headers.Builder(); if (header != null && header.size() > 0) { - Set keys = header.keySet(); - for (String key : keys) { - hb.add(key, header.get(key)); + Set set = header.entrySet(); + for (Object aSet : set) { + Map.Entry entry = (Map.Entry) aSet; + hb.add(entry.getKey() + "", entry.getValue() + ""); } L.v(TAG, "请求的头数据为 >>>> "); L.m(header); } //请求参数 if (params != null && params.size() > 0) { - Set keys = params.keySet(); - for (String key : keys) { - formB.add(key, params.get(key)); + Set set = params.entrySet(); + for (Object aSet : set) { + Map.Entry entry = (Map.Entry) aSet; + formB.add(entry.getKey() + "", entry.getValue() + ""); } L.v(TAG, "请求参数为 >>>> "); L.m(params); @@ -279,7 +287,8 @@ public class HttpUtil { 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) { + @Override + public void onFailure(Call call, IOException e) { L.e(TAG, "请求链接【" + url + "】失败"); String data = null; if (useCache) { @@ -294,7 +303,8 @@ public class HttpUtil { } } - @Override public void onResponse(Call call, Response response) throws IOException { + @Override + public void onResponse(Call call, Response response) throws IOException { String data = response.body().string(); L.d(TAG, "数据获取成功,获取到的数据为 >>>>"); L.j(data); @@ -309,7 +319,8 @@ public class HttpUtil { private void setOnError(final Object error, final IResponse response) { mHandler.post(new Runnable() { - @Override public void run() { + @Override + public void run() { response.onError(error); } }); @@ -317,7 +328,8 @@ public class HttpUtil { private void setOnResponse(final String data, final IResponse response) { mHandler.post(new Runnable() { - @Override public void run() { + @Override + public void run() { response.onResponse(data); } }); @@ -328,11 +340,13 @@ public class HttpUtil { */ public static class AbsResponse implements IResponse { - @Override public void onResponse(String data) { + @Override + public void onResponse(String data) { } - @Override public void onError(Object error) { + @Override + public void onError(Object error) { } } diff --git a/AppFrame/src/main/java/com/arialyy/frame/module/AbsModule.java b/AppFrame/src/main/java/com/arialyy/frame/module/AbsModule.java index 754d90dc..2c0e6d07 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/module/AbsModule.java +++ b/AppFrame/src/main/java/com/arialyy/frame/module/AbsModule.java @@ -1,14 +1,23 @@ package com.arialyy.frame.module; import android.content.Context; - import android.databinding.ViewDataBinding; +import android.text.TextUtils; +import android.util.SparseIntArray; +import android.view.View; + import com.arialyy.frame.core.AbsActivity; import com.arialyy.frame.core.BindingFactory; import com.arialyy.frame.module.inf.ModuleListener; +import com.arialyy.frame.util.ObjUtil; import com.arialyy.frame.util.StringUtil; 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 AriaLyy on 2015/2/3. * 抽象的module @@ -46,7 +55,9 @@ public class AbsModule { * @param moduleListener Module监听 */ public void setModuleListener(ModuleListener moduleListener) { - if (moduleListener == null) throw new NullPointerException("ModuleListener不能为空"); + if (moduleListener == null) { + throw new NullPointerException("ModuleListener不能为空"); + } this.mModuleListener = moduleListener; } @@ -126,7 +137,8 @@ public class AbsModule { * * @param method 回调的方法名 */ - @Deprecated protected void callback(String method) { + @Deprecated + protected void callback(String method) { mModuleListener.callback(method); } @@ -137,7 +149,8 @@ public class AbsModule { * @param dataClassType 回调数据类型 * @param data 回调数据 */ - @Deprecated protected void callback(String method, Class dataClassType, Object data) { + @Deprecated + protected void callback(String method, Class dataClassType, Object data) { mModuleListener.callback(method, dataClassType, data); } } diff --git a/AppFrame/src/main/java/com/arialyy/frame/module/IOCProxy.java b/AppFrame/src/main/java/com/arialyy/frame/module/IOCProxy.java index d5f3a8e7..36cdb2bd 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/module/IOCProxy.java +++ b/AppFrame/src/main/java/com/arialyy/frame/module/IOCProxy.java @@ -50,7 +50,8 @@ public class IOCProxy implements ModuleListener { * @param result 返回码 * @param data 回调数据 */ - @Override public void callback(int result, Object data) { + @Override + public void callback(int result, Object data) { synchronized (this) { try { Method m = ReflectionUtil.getMethod(mObj.getClass(), mMethod, int.class, Object.class); @@ -69,7 +70,9 @@ public class IOCProxy implements ModuleListener { * * @param method 方法名 */ - @Override @Deprecated public void callback(String method) { + @Override + @Deprecated + public void callback(String method) { synchronized (this) { try { Method m = mObj.getClass().getDeclaredMethod(method); @@ -93,7 +96,9 @@ public class IOCProxy implements ModuleListener { * @param dataClassType 参数类型,如 int.class * @param data 数据 */ - @Override @Deprecated public void callback(String method, Class dataClassType, Object data) { + @Override + @Deprecated + public void callback(String method, Class dataClassType, Object data) { synchronized (this) { try { Method m = mObj.getClass().getDeclaredMethod(method, dataClassType); diff --git a/AppFrame/src/main/java/com/arialyy/frame/module/ModuleFactory.java b/AppFrame/src/main/java/com/arialyy/frame/module/ModuleFactory.java index ad4ac3d3..a9797481 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/module/ModuleFactory.java +++ b/AppFrame/src/main/java/com/arialyy/frame/module/ModuleFactory.java @@ -54,8 +54,7 @@ public class ModuleFactory { * @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 + return mKeyIndex.indexOfKey(key) != -1 || mKeyIndex.indexOfValue(callback.hashCode()) != -1 && mKeyIndex.valueAt(callback.hashCode()) == key; } } diff --git a/AppFrame/src/main/java/com/arialyy/frame/permission/PermissionManager.java b/AppFrame/src/main/java/com/arialyy/frame/permission/PermissionManager.java index f20db64b..c85ae01a 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/permission/PermissionManager.java +++ b/AppFrame/src/main/java/com/arialyy/frame/permission/PermissionManager.java @@ -85,8 +85,10 @@ import java.util.List; * @param obj Activity || Fragment * @param permission 权限 */ - public void requestPermission(Object obj, OnPermissionCallback callback, String... permission) { - requestPermission(obj, "", callback, registerCallback(obj, callback, permission)); + public PermissionManager requestPermission(Object obj, OnPermissionCallback callback, + String... permission) { + requestPermissionAndHint(obj, callback, "", registerCallback(obj, callback, permission)); + return this; } /** @@ -96,9 +98,9 @@ import java.util.List; * @param hint 如果框对话框包含“不再询问”选择框的时候的提示用语。 * @param permission 权限 */ - private void requestPermission(Object obj, String hint, OnPermissionCallback callback, + public void requestPermissionAndHint(Object obj, OnPermissionCallback callback, String hint, String... permission) { - mPu.requestPermission(obj, hint, 0, registerCallback(obj, callback, permission)); + mPu.requestPermission(obj, 0, hint, registerCallback(obj, callback, permission)); } private void registerCallback(OnPermissionCallback callback, int hashCode) { diff --git a/AppFrame/src/main/java/com/arialyy/frame/permission/PermissionUtil.java b/AppFrame/src/main/java/com/arialyy/frame/permission/PermissionUtil.java index 72ccd7d1..19857cd3 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/permission/PermissionUtil.java +++ b/AppFrame/src/main/java/com/arialyy/frame/permission/PermissionUtil.java @@ -45,7 +45,7 @@ import java.util.List; if (!AndroidVersionUtil.hasM()) { return; } - requestPermission(obj, "", requestCode, permission); + requestPermission(obj, requestCode, "", permission); } /** @@ -53,7 +53,7 @@ import java.util.List; * * @param hint 如果框对话框包含”不再询问“选择框的时候的提示用语。 */ - public void requestPermission(Object obj, String hint, int requestCode, String... permission) { + public void requestPermission(Object obj, int requestCode, String hint, String... permission) { if (!AndroidVersionUtil.hasM() || permission == null || permission.length == 0) { return; } @@ -72,12 +72,12 @@ import java.util.List; for (String str : permission) { if (fragment != null) { if (fragment.shouldShowRequestPermissionRationale(str)) { - T.showShort(fragment.getContext(), hint); + T.showLong(fragment.getContext(), hint); break; } } else { if (activity.shouldShowRequestPermissionRationale(str)) { - T.showShort(activity, hint); + T.showLong(activity, hint); break; } } diff --git a/AppFrame/src/main/java/com/arialyy/frame/temp/AbsTempView.java b/AppFrame/src/main/java/com/arialyy/frame/temp/AbsTempView.java index 108820b2..52745a60 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/temp/AbsTempView.java +++ b/AppFrame/src/main/java/com/arialyy/frame/temp/AbsTempView.java @@ -10,7 +10,6 @@ import android.widget.LinearLayout; import com.arialyy.frame.util.StringUtil; import com.arialyy.frame.util.show.L; - /** * Created by lyy on 2016/4/27. * 抽象的填充类 @@ -57,7 +56,8 @@ public abstract class AbsTempView extends LinearLayout implements ITempView { } } - @Override public void setType(int type) { + @Override + public void setType(int type) { mType = type; if (type == LOADING) { onLoading(); diff --git a/AppFrame/src/main/java/com/arialyy/frame/temp/TempView.java b/AppFrame/src/main/java/com/arialyy/frame/temp/TempView.java index 83297ece..f12b2b42 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/temp/TempView.java +++ b/AppFrame/src/main/java/com/arialyy/frame/temp/TempView.java @@ -23,37 +23,43 @@ public class TempView extends AbsTempView { super(context); } - @Override protected void init() { + @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) { + @Override + public void onClick(View v) { onTempBtClick(v, mType); } }); } - @Override protected int setLayoutId() { + @Override + protected int setLayoutId() { return R.layout.layout_error_temp; } - @Override public void onError() { + @Override + public void onError() { mErrorContent.setVisibility(VISIBLE); mPb.setVisibility(GONE); mHint.setText("网络错误"); mBt.setText("点击刷新"); } - @Override public void onNull() { + @Override + public void onNull() { mErrorContent.setVisibility(VISIBLE); mPb.setVisibility(GONE); mHint.setText("数据为空"); mBt.setText("点击刷新"); } - @Override public void onLoading() { + @Override + public void onLoading() { mErrorContent.setVisibility(GONE); mPb.setVisibility(VISIBLE); } diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/AESEncryption.java b/AppFrame/src/main/java/com/arialyy/frame/util/AESEncryption.java index 4607f81d..182aa69f 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/AESEncryption.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/AESEncryption.java @@ -140,7 +140,9 @@ public class AESEncryption { * AES算法的秘钥要求16位 */ public static String toHex(byte[] buf) { - if (buf == null) return ""; + if (buf == null) { + return ""; + } StringBuffer result = new StringBuffer(2 * buf.length); for (byte aBuf : buf) { appendHex(result, aBuf); diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/AndroidUtils.java b/AppFrame/src/main/java/com/arialyy/frame/util/AndroidUtils.java index 252a4744..03333054 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/AndroidUtils.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/AndroidUtils.java @@ -1,11 +1,8 @@ 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; @@ -21,13 +18,14 @@ 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.support.v4.content.FileProvider; 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; @@ -48,35 +46,18 @@ public class 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 + * 应用市场是否存在 + * + * @return {@code true}存在 */ - 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); - } + public static boolean hasAnyMarket(Context context) { + Intent intent = new Intent(); + intent.setData(Uri.parse("market://details?id=android.browser")); + List list = context.getPackageManager() + .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); - /** - * 另外一种dp转PX方法 - */ - public static int dp2px(int dp) { - return Math.round(dp * DENSITY); + return list != null && list.size() > 0; } /** @@ -148,6 +129,14 @@ public class AndroidUtils { return ""; } + /** + * 获取未安装软件包的包名 + */ + public static PackageInfo getApkPackageInfo(Context context, String apkPath) { + PackageManager pm = context.getPackageManager(); + return pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES); + } + /** * 判断是否安装 */ @@ -196,8 +185,6 @@ public class AndroidUtils { 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); } @@ -445,8 +432,8 @@ public class AndroidUtils { * 安装APP */ public static void install(Context context, File file) { - L.e(TAG, "install Apk:" + file.getName()); - context.startActivity(getInstallIntent(file)); + FL.e(TAG, "install Apk:" + file.getName()); + context.startActivity(getInstallIntent(context, file)); } /** @@ -464,11 +451,18 @@ public class AndroidUtils { /** * 获取安装应用的Intent */ - public static Intent getInstallIntent(File file) { + public static Intent getInstallIntent(Context context, 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"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + Uri contentUri = + FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider", file); + intent.setDataAndType(contentUri, "application/vnd.android.package-archive"); + } else { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); + } return intent; } @@ -518,22 +512,6 @@ public class AndroidUtils { 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) */ diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/AppUtils.java b/AppFrame/src/main/java/com/arialyy/frame/util/AppUtils.java index 22b609d1..c53b3ab5 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/AppUtils.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/AppUtils.java @@ -93,7 +93,8 @@ public class AppUtils { public static String getAppName(Context context) { try { PackageManager packageManager = context.getPackageManager(); - PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); + PackageInfo packageInfo = packageManager.getPackageInfo( + context.getPackageName(), 0); int labelRes = packageInfo.applicationInfo.labelRes; return context.getResources().getString(labelRes); } catch (NameNotFoundException e) { @@ -110,7 +111,8 @@ public class AppUtils { public static String getVersionName(Context context) { try { PackageManager packageManager = context.getPackageManager(); - PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); + PackageInfo packageInfo = packageManager.getPackageInfo( + context.getPackageName(), 0); return packageInfo.versionName; } catch (NameNotFoundException e) { e.printStackTrace(); diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/DensityUtils.java b/AppFrame/src/main/java/com/arialyy/frame/util/DensityUtils.java index e52e2b30..9ea43b67 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/DensityUtils.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/DensityUtils.java @@ -9,7 +9,7 @@ import android.util.TypedValue; */ public class DensityUtils { private DensityUtils() { - /* cannot be instantiated */ + /* cannot be instantiated */ throw new UnsupportedOperationException("cannot be instantiated"); } @@ -26,16 +26,16 @@ public class DensityUtils { * dp转px */ public static int dp2px(Context context, float dpVal) { - return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, - context.getResources().getDisplayMetrics()); + 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()); + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, + spVal, context.getResources().getDisplayMetrics()); } /** diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/DrawableUtil.java b/AppFrame/src/main/java/com/arialyy/frame/util/DrawableUtil.java index 9d7c531e..c30f1e05 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/DrawableUtil.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/DrawableUtil.java @@ -40,7 +40,8 @@ public class DrawableUtil { 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); + Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, + matrix, true); return new BitmapDrawable(null, newbmp); } @@ -50,9 +51,9 @@ public class DrawableUtil { 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); + 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); diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/FileUtil.java b/AppFrame/src/main/java/com/arialyy/frame/util/FileUtil.java index dbf57705..f0db1066 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/FileUtil.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/FileUtil.java @@ -1,17 +1,19 @@ package com.arialyy.frame.util; 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.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; +import android.media.MediaMetadataRetriever; +import android.net.Uri; 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; @@ -29,6 +31,8 @@ import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Enumeration; +import java.util.Formatter; +import java.util.Locale; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -40,11 +44,22 @@ public class FileUtil { private static final String MB = "MB"; private static final String GB = "GB"; - private FileUtil() { - } - private static final String TAG = "FileUtil"; + //android获取一个用于打开HTML文件的intent + public static Intent getHtmlFileIntent(String Path) { + File file = new File(Path); + Uri uri = Uri.parse(file.toString()) + .buildUpon() + .encodedAuthority("com.android.htmlfileprovider") + .scheme("content") + .encodedPath(file.toString()) + .build(); + Intent intent = new Intent("android.intent.action.VIEW"); + intent.setDataAndType(uri, "text/html"); + return intent; + } + /** * 获取文件夹大小 */ @@ -465,8 +480,8 @@ public class FileUtil { if (dir.isDirectory()) { String[] children = dir.list(); // 递归删除目录中的子目录下 - for (int i = 0; i < children.length; i++) { - boolean success = deleteDir(new File(dir, children[i])); + for (String aChildren : children) { + boolean success = deleteDir(new File(dir, aChildren)); if (!success) { return false; } diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/KeyBoardUtils.java b/AppFrame/src/main/java/com/arialyy/frame/util/KeyBoardUtils.java index c4a77dfd..d71111d4 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/KeyBoardUtils.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/KeyBoardUtils.java @@ -17,10 +17,11 @@ public class KeyBoardUtils { * @param mContext 上下文 */ public static void openKeybord(EditText mEditText, Context mContext) { - InputMethodManager imm = - (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) mContext + .getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN); - imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, + InputMethodManager.HIDE_IMPLICIT_ONLY); } /** @@ -30,8 +31,8 @@ public class KeyBoardUtils { * @param mContext 上下文 */ public static void closeKeybord(EditText mEditText, Context mContext) { - InputMethodManager imm = - (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) mContext + .getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0); } } \ No newline at end of file diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/MediaUtil.java b/AppFrame/src/main/java/com/arialyy/frame/util/MediaUtil.java new file mode 100644 index 00000000..4282d81f --- /dev/null +++ b/AppFrame/src/main/java/com/arialyy/frame/util/MediaUtil.java @@ -0,0 +1,83 @@ +package com.arialyy.frame.util; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.MediaMetadataRetriever; +import android.media.MediaPlayer; +import android.net.Uri; +import java.io.IOException; +import java.util.Formatter; +import java.util.Locale; + +/** + * Created by Aria.Lao on 2018/1/4. + * 多媒体工具 + */ +public class MediaUtil { + private MediaUtil() { + throw new AssertionError(); + } + + /** + * 获取音频、视频播放长度 + */ + public static long getDuration(String path) { + MediaPlayer mediaPlayer = new MediaPlayer(); + try { + mediaPlayer.setDataSource(path); + } catch (IOException e) { + e.printStackTrace(); + return -1; + } + int duration = mediaPlayer.getDuration(); + mediaPlayer.release(); + return duration; + } + + /** + * 格式化视频时间 + */ + public static String convertViewTime(long timeMs) { + int totalSeconds = (int) (timeMs / 1000); + + int seconds = totalSeconds % 60; + int minutes = (totalSeconds / 60) % 60; + int hours = totalSeconds / 3600; + StringBuilder sFormatBuilder = new StringBuilder(); + Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault()); + sFormatBuilder.setLength(0); + if (hours > 0) { + return sFormatter.format("%02d:%02d:%02d", hours, minutes, seconds).toString(); + } else { + return sFormatter.format("%02d:%02d", minutes, seconds).toString(); + } + } + + /** + * 获取音频封面 + */ + public static Bitmap getArtwork(Context context, String url) { + Uri selectedAudio = Uri.parse(url); + MediaMetadataRetriever myRetriever = new MediaMetadataRetriever(); + myRetriever.setDataSource(context, selectedAudio); // the URI of audio file + byte[] artwork; + artwork = myRetriever.getEmbeddedPicture(); + if (artwork != null) { + return BitmapFactory.decodeByteArray(artwork, 0, artwork.length); + } + return null; + } + + public static byte[] getArtworkAsByte(Context context, String url) { + Uri selectedAudio = Uri.parse(url); + MediaMetadataRetriever myRetriever = new MediaMetadataRetriever(); + myRetriever.setDataSource(context, selectedAudio); // the URI of audio file + byte[] artwork; + artwork = myRetriever.getEmbeddedPicture(); + if (artwork != null) { + return artwork; + } + return null; + } +} diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/NetUtils.java b/AppFrame/src/main/java/com/arialyy/frame/util/NetUtils.java index 36c05eb8..1444f0e2 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/NetUtils.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/NetUtils.java @@ -36,7 +36,7 @@ public class NetUtils { public static final int NETWORK_TYPE_WIFI = 4; private NetUtils() { - /* cannot be instantiated */ + /* cannot be instantiated */ throw new UnsupportedOperationException("cannot be instantiated"); } @@ -75,8 +75,9 @@ public class NetUtils { 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; + netWorkType = TextUtils.isEmpty(proxyHost) + ? (isFastMobileNetwork(context) ? NETWORK_TYPE_3G : NETWORK_TYPE_2G) + : NETWORK_TYPE_WAP; } } else { netWorkType = NETWORK_TYPE_INVALID; diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/RegularExpression.java b/AppFrame/src/main/java/com/arialyy/frame/util/RegularExpression.java index fe0a9f57..4b405f48 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/RegularExpression.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/RegularExpression.java @@ -13,8 +13,9 @@ public class RegularExpression { /** * 视频 */ - 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 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)$"; /** * 音频 */ diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/ScreenUtil.java b/AppFrame/src/main/java/com/arialyy/frame/util/ScreenUtil.java index 4a448667..fa458212 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/ScreenUtil.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/ScreenUtil.java @@ -44,7 +44,8 @@ public class ScreenUtil { * * @param greyScale true:灰度 */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void setGreyScale(View v, boolean greyScale) { + @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(); @@ -63,7 +64,8 @@ public class ScreenUtil { * 获得屏幕高度 */ public int getScreenWidth(Context context) { - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + WindowManager wm = (WindowManager) context + .getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); return outMetrics.widthPixels; @@ -73,7 +75,8 @@ public class ScreenUtil { * 获得屏幕宽度 */ public int getScreenHeight(Context context) { - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + WindowManager wm = (WindowManager) context + .getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); return outMetrics.heightPixels; @@ -88,7 +91,8 @@ public class ScreenUtil { 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()); + int height = Integer.parseInt(clazz.getField("status_bar_height") + .get(object).toString()); statusHeight = context.getResources().getDimensionPixelSize(height); } catch (Exception e) { e.printStackTrace(); @@ -134,7 +138,8 @@ public class ScreenUtil { int width = getScreenWidth(activity); int height = getScreenHeight(activity); Bitmap bp = null; - bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight); + bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height + - statusBarHeight); view.destroyDrawingCache(); return bp; } @@ -145,9 +150,9 @@ public class ScreenUtil { 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; + automicBrightness = Settings.System.getInt(aContentResolver, + Settings.System.SCREEN_BRIGHTNESS_MODE) + == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); } @@ -161,7 +166,8 @@ public class ScreenUtil { int nowBrightnessValue = 0; ContentResolver resolver = activity.getContentResolver(); try { - nowBrightnessValue = Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS); + nowBrightnessValue = Settings.System.getInt( + resolver, Settings.System.SCREEN_BRIGHTNESS); } catch (Exception e) { e.printStackTrace(); } @@ -184,7 +190,8 @@ public class ScreenUtil { * 停止自动亮度调节 */ public void stopAutoBrightness(Activity activity) { - Settings.System.putInt(activity.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.putInt(activity.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); } @@ -192,7 +199,8 @@ public class ScreenUtil { * 开启亮度自动调节 */ public void startAutoBrightness(Activity activity) { - Settings.System.putInt(activity.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.putInt(activity.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); } @@ -200,8 +208,10 @@ public class ScreenUtil { * 保存亮度设置状态 */ public void saveBrightness(ContentResolver resolver, int brightness) { - Uri uri = Settings.System.getUriFor("screen_brightness"); - Settings.System.putInt(resolver, "screen_brightness", brightness); + Uri uri = Settings.System + .getUriFor("screen_brightness"); + Settings.System.putInt(resolver, "screen_brightness", + brightness); // resolver.registerContentObserver(uri, true, myContentObserver); resolver.notifyChange(uri, null); } diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/ShellUtils.java b/AppFrame/src/main/java/com/arialyy/frame/util/ShellUtils.java index ec150e0b..61fb2137 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/ShellUtils.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/ShellUtils.java @@ -170,7 +170,8 @@ public class ShellUtils { } } return new CommandResult(result, successMsg == null ? null : successMsg.toString(), - errorMsg == null ? null : errorMsg.toString()); + errorMsg == null ? null + : errorMsg.toString()); } /** diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/StringUtil.java b/AppFrame/src/main/java/com/arialyy/frame/util/StringUtil.java index 0a31f6ec..32d404a2 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/StringUtil.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/StringUtil.java @@ -276,7 +276,7 @@ public class StringUtil { 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 diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/show/FL.java b/AppFrame/src/main/java/com/arialyy/frame/util/show/FL.java index 1665cd57..e0a2a6fe 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/show/FL.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/show/FL.java @@ -1,23 +1,26 @@ 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; +import java.io.File; +import java.io.FileWriter; +import java.io.PrintWriter; + /** - * Created by “AriaLyy@outlook.com” on 2015/4/1. + * Created by Lyy 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; + public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化 + public static String NAME = "AriaFrame"; //log路径 private static String printLine(String tag, boolean isTop) { String top = @@ -53,15 +56,16 @@ public class FL { message = jsonStr; } + writeLogToFile(tag, printLine(tag, true)); message = LINE_SEPARATOR + message; - String temp = "\n" + printLine(tag, true) + "\n"; + String temp = ""; String[] lines = message.split(LINE_SEPARATOR); for (String line : lines) { - temp += "║ " + line + "\n"; + temp += "║ " + line; Log.d(tag, "║ " + line); } - temp += printLine(tag, false); writeLogToFile(tag, temp); + writeLogToFile(tag, printLine(tag, false)); } } @@ -141,8 +145,8 @@ public class FL { * 返回日志路径 */ public static String getLogPath() { - String path = PATH + CalendarUtils.getData() + ".txt"; - return android.os.Environment.getExternalStorageDirectory().getPath() + File.separator + path; + String name = NAME + "_" + CalendarUtils.getData() + ".log"; + return android.os.Environment.getExternalStorageDirectory().getPath() + File.separator + name; } /** diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/show/L.java b/AppFrame/src/main/java/com/arialyy/frame/util/show/L.java index c7caf117..4a8145a8 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/show/L.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/show/L.java @@ -32,7 +32,7 @@ public class L { static int JSON_INDENT = 4; private L() { - /* cannot be instantiated */ + /* cannot be instantiated */ throw new UnsupportedOperationException("cannot be instantiated"); } @@ -108,73 +108,99 @@ public class L { // 下面四个是默认tag的函数 public static void i(String... msg) { - if (isDebug) printLog(I, msg); + if (isDebug) { + printLog(I, msg); + } } public static void d(String... msg) { - if (isDebug) printLog(D, msg); + if (isDebug) { + printLog(D, msg); + } } public static void w(String... msg) { - if (isDebug) printLog(W, 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)); + if (isDebug) { + printLog(E, msg); + } } public static void v(String... msg) { - if (isDebug) printLog(V, msg); + if (isDebug) { + printLog(V, msg); + } } // 下面是传入自定义tag的函数 public static void i(String tag, String msg) { - if (isDebug) Log.i(tag, msg); + if (isDebug) { + Log.i(tag, msg); + } } public static void d(String tag, String msg) { - if (isDebug) Log.d(tag, msg); + if (isDebug) { + Log.d(tag, msg); + } } public static void w(String tag, String msg) { - if (isDebug) Log.w(tag, msg); + if (isDebug) { + Log.w(tag, msg); + } } public static void e(String tag, String msg) { - if (isDebug) Log.e(tag, msg); + if (isDebug) { + Log.e(tag, msg); + } } public static void v(String tag, String msg) { - if (isDebug) Log.v(tag, msg); + if (isDebug) { + Log.v(tag, msg); + } } //带异常的 public static void i(String tag, String msg, Throwable tr) { - if (isDebug) Log.i(tag, msg, 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); + if (isDebug) { + Log.d(tag, msg, tr); + } } public static void w(String tag, String msg, Throwable tr) { - if (isDebug) Log.w(tag, msg, 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); + if (isDebug) { + Log.e(tag, msg, tr); + } } public static void v(String tag, String msg, Throwable tr) { - if (isDebug) Log.v(tag, msg, tr); + if (isDebug) { + Log.v(tag, msg, tr); + } } /** - * 统一打印 + * 同意打印 */ private static void printHunk(char type, String str) { switch (type) { diff --git a/AppFrame/src/main/java/com/arialyy/frame/util/show/T.java b/AppFrame/src/main/java/com/arialyy/frame/util/show/T.java index 60a1b86c..985ff4b2 100644 --- a/AppFrame/src/main/java/com/arialyy/frame/util/show/T.java +++ b/AppFrame/src/main/java/com/arialyy/frame/util/show/T.java @@ -22,41 +22,53 @@ public class T { * 短时间显示Toast */ public static void showShort(Context context, CharSequence message) { - if (isShow) Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); + 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(); + 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(); + 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(); + 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(); + 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(); + if (isShow) { + Toast.makeText(context, message, duration).show(); + } } } \ No newline at end of file diff --git a/AppFrame/src/main/res/drawable/selector_green_bt.xml b/AppFrame/src/main/res/drawable/selector_green_bt.xml index 72bd5b97..f9e4e2e9 100644 --- a/AppFrame/src/main/res/drawable/selector_green_bt.xml +++ b/AppFrame/src/main/res/drawable/selector_green_bt.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/AppFrame/src/main/res/layout/layout_error_temp.xml b/AppFrame/src/main/res/layout/layout_error_temp.xml index e0c2831b..23b8ba13 100644 --- a/AppFrame/src/main/res/layout/layout_error_temp.xml +++ b/AppFrame/src/main/res/layout/layout_error_temp.xml @@ -15,8 +15,8 @@ diff --git a/AppFrame/src/main/res/values/color.xml b/AppFrame/src/main/res/values/color.xml index 33322e7b..48312e04 100644 --- a/AppFrame/src/main/res/values/color.xml +++ b/AppFrame/src/main/res/values/color.xml @@ -1,6 +1,6 @@ - #E5E5E5 - #fff - #A5A5A5 + #E5E5E5 + #fff + #757575 \ No newline at end of file diff --git a/AppFrame/src/main/res/values/strings.xml b/AppFrame/src/main/res/values/strings.xml index 087ebb00..1bb5c0ef 100644 --- a/AppFrame/src/main/res/values/strings.xml +++ b/AppFrame/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - Frame + Frame diff --git a/AppFrame/src/main/res/values/style.xml b/AppFrame/src/main/res/values/style.xml index cc70cbd6..2492071d 100644 --- a/AppFrame/src/main/res/values/style.xml +++ b/AppFrame/src/main/res/values/style.xml @@ -1,15 +1,15 @@ - - - + + - + \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java index de69ee0d..2768b77b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java @@ -99,10 +99,18 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable { this.groupHash = groupHash; } + /** + * 后面会删除该方法,请使用{@link #getFilePath()} + */ + @Deprecated public String getDownloadPath() { return downloadPath; } + public String getFilePath() { + return downloadPath; + } + public DownloadEntity setDownloadPath(String downloadPath) { this.downloadPath = downloadPath; return this; diff --git a/AriaAnnotations/src/main/java/com/arialyy/annotations/Download.java b/AriaAnnotations/src/main/java/com/arialyy/annotations/Download.java index d33608c8..83084ed9 100644 --- a/AriaAnnotations/src/main/java/com/arialyy/annotations/Download.java +++ b/AriaAnnotations/src/main/java/com/arialyy/annotations/Download.java @@ -39,7 +39,7 @@ import java.lang.annotation.Target; /** * "@Download.onPre"注解,下载队列已经满了,继续创建新任务,将会回调该方法 */ - @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onWait{ + @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onWait { String[] value() default { AriaConstance.NO_URL }; } @@ -108,9 +108,11 @@ import java.lang.annotation.Target; /** * "@Download.onNoSupportBreakPoint"注解,如果该任务不支持断点,Aria会调用该方法 + * + * @deprecated 该注解将在后续版本删除 */ - @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) - @interface onNoSupportBreakPoint { + @Deprecated + @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onNoSupportBreakPoint { String[] value() default { AriaConstance.NO_URL }; } } diff --git a/README.md b/README.md index da6ed806..87f4806d 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ __注意:3.5.4以下版本升级时,需要更新[配置文件]!!(https:/ ```java Aria.download(this) .load(DOWNLOAD_URL) //读取下载地址 - .setDownloadPath(DOWNLOAD_PATH) //设置文件保存的完整路径 + .setFilePath(DOWNLOAD_PATH) //设置文件保存的完整路径 .start(); //启动下载 ``` diff --git a/app/build.gradle b/app/build.gradle index 6b0b4ec1..eaf22fc7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,8 +44,9 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') testImplementation 'junit:junit:4.12' - implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}" + implementation "com.android.support:cardview-v7:${rootProject.ext.supportLibVersion}" implementation "com.android.support:design:${rootProject.ext.supportLibVersion}" + implementation "org.jetbrains.kotlin:kotlin-stdlib:${rootProject.ext.kotlin_version}" api project(':Aria') kapt project(':AriaCompiler') @@ -58,7 +59,7 @@ dependencies { implementation project(':AppFrame') debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4' implementation 'com.github.bumptech.glide:glide:3.7.0' - + implementation 'com.pddstudio:highlightjs-android:1.5.0' } repositories { mavenCentral() diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 269769f7..6b7eedf0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -42,6 +42,11 @@ + diff --git a/app/src/main/assets/help_code/FtpDownload.java b/app/src/main/assets/help_code/FtpDownload.java new file mode 100644 index 00000000..2aefed21 --- /dev/null +++ b/app/src/main/assets/help_code/FtpDownload.java @@ -0,0 +1,90 @@ + +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import com.arialyy.annotations.Download; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.download.DownloadTask; +import com.arialyy.aria.util.CommonUtil; +import com.arialyy.simple.R; +import com.arialyy.simple.base.BaseActivity; +import com.arialyy.simple.databinding.ActivityTestBinding; +import java.io.File; + +/** + * Created by lyy on 2019/5/28. + * Ftp 下载 + * 文档 + */ +public class FtpDownload extends BaseActivity { + String TAG = "TestFTPActivity"; + private final String URL = "ftp://192.168.1.3:21/download//AriaPrj.rar"; + private final String FILE_PATH = "/mnt/sdcard/AriaPrj.rar"; + + @Override protected int setLayoutId() { + return R.layout.activity_test; + } + + @Override protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + mBar.setVisibility(View.GONE); + Aria.download(this).register(); + } + + @Download.onWait void onWait(DownloadTask task) { + Log.d(TAG, "wait ==> " + task.getEntity().getFileName()); + } + + @Download.onPre protected void onPre(DownloadTask task) { + Log.d(TAG, "onPre"); + } + + @Download.onTaskStart void taskStart(DownloadTask task) { + Log.d(TAG, "onStart"); + } + + @Download.onTaskRunning protected void running(DownloadTask task) { + Log.d(TAG, "running,speed=" + task.getConvertSpeed()); + } + + @Download.onTaskResume void taskResume(DownloadTask task) { + Log.d(TAG, "resume"); + } + + @Download.onTaskStop void taskStop(DownloadTask task) { + Log.d(TAG, "stop"); + } + + @Download.onTaskCancel void taskCancel(DownloadTask task) { + Log.d(TAG, "cancel"); + } + + @Download.onTaskFail void taskFail(DownloadTask task) { + Log.d(TAG, "fail"); + } + + @Download.onTaskComplete void taskComplete(DownloadTask task) { + Log.d(TAG, "complete, md5 => " + CommonUtil.getFileMD5(new File(task.getKey()))); + } + + public void onClick(View view) { + switch (view.getId()) { + case R.id.start: + Aria.download(this) + .loadFtp(URL) + .setFilePath(FILE_PATH) + .login("lao", "123456") + //.asFtps() // ftps 配置 + //.setStorePath("/mnt/sdcard/Download/server.crt") //设置证书路径 + // .setAlias("www.laoyuyu.me") // 设置证书别名 + .start(); + break; + case R.id.stop: + Aria.download(this).loadFtp(FILE_PATH).stop(); + break; + case R.id.cancel: + Aria.download(this).loadFtp(FILE_PATH).cancel(); + break; + } + } +} diff --git a/app/src/main/assets/help_code/FtpUpload.java b/app/src/main/assets/help_code/FtpUpload.java new file mode 100644 index 00000000..48ad3c99 --- /dev/null +++ b/app/src/main/assets/help_code/FtpUpload.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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. + */ +import android.app.Activity; +import android.os.Bundle; +import android.os.Environment; +import android.util.Log; +import android.view.View; +import com.arialyy.annotations.Upload; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.common.ftp.FtpInterceptHandler; +import com.arialyy.aria.core.common.ftp.IFtpUploadInterceptor; +import com.arialyy.aria.core.upload.UploadEntity; +import com.arialyy.aria.core.upload.UploadTask; +import com.arialyy.frame.util.FileUtil; +import com.arialyy.frame.util.show.T; +import com.arialyy.simple.R; +import java.io.File; +import java.util.List; + +/** + * Created by lyy on 2019/5/28. Ftp 文件上传demo + * 文档 + */ +public class FtpUpload extends Activity { + private static final String TAG = "FtpUpload"; + private String mFilePath = Environment.getExternalStorageDirectory().getPath() + "/AriaPrj.rar"; + private String mUrl = "ftp://172.168.1.2:2121/aa/你好"; + + @Override protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Aria.upload(this).register(); + // 读取历史记录信息 + UploadEntity entity = Aria.upload(this).getUploadEntity(mFilePath); + if (entity != null) { + // 设置界面的进度、文件大小等信息 + } + } + + public void onClick(View view) { + switch (view.getId()) { + case R.id.start: + if (Aria.upload(this).load(mFilePath).isRunning()) { + Aria.upload(this).loadFtp(mFilePath).stop(); // 停止任务 + } else { + Aria.upload(this) + .loadFtp(mFilePath) // 需要上传的文件 + .setUploadUrl(mUrl) // 服务器地址 + // 如果ftp服务器端有同名文件,可通过拦截器处理是覆盖服务器端文件,还是修改文件名 + .setUploadInterceptor( + new IFtpUploadInterceptor() { + + @Override + public FtpInterceptHandler onIntercept(UploadEntity entity, + List fileList) { + FtpInterceptHandler.Builder builder = new FtpInterceptHandler.Builder(); + //builder.coverServerFile(); + builder.resetFileName("test.zip"); + return builder.build(); + } + }) + .login("N0rI", "0qcK") + .start(); + } + break; + case R.id.cancel: + Aria.upload(this).loadFtp(mFilePath).cancel(); + break; + } + } + + @Upload.onWait void onWait(UploadTask task) { + Log.d(TAG, task.getTaskName() + "_wait"); + } + + @Upload.onPre public void onPre(UploadTask task) { + setFileSize(task.getConvertFileSize()); + } + + @Upload.onTaskStart public void taskStart(UploadTask task) { + Log.d(TAG, "开始上传,md5:" + FileUtil.getFileMD5(new File(task.getEntity().getFilePath()))); + } + + @Upload.onTaskResume public void taskResume(UploadTask task) { + Log.d(TAG, "恢复上传"); + } + + @Upload.onTaskStop public void taskStop(UploadTask task) { + setSpeed(""); + Log.d(TAG, "停止上传"); + } + + @Upload.onTaskCancel public void taskCancel(UploadTask task) { + setSpeed(""); + setFileSize(""); + setProgress(0); + Log.d(TAG, "删除任务"); + } + + @Upload.onTaskFail public void taskFail(UploadTask task) { + Log.d(TAG, "上传失败"); + } + + @Upload.onTaskRunning public void taskRunning(UploadTask task) { + Log.d(TAG, "PP = " + task.getPercent()); + setProgress(task.getPercent()); + setSpeed(task.getConvertSpeed()); + } + + @Upload.onTaskComplete public void taskComplete(UploadTask task) { + setProgress(100); + setSpeed(""); + T.showShort(this, "文件:" + task.getEntity().getFileName() + ",上传完成"); + } +} diff --git a/app/src/main/assets/help_code/HttpDownload.java b/app/src/main/assets/help_code/HttpDownload.java new file mode 100644 index 00000000..61d82669 --- /dev/null +++ b/app/src/main/assets/help_code/HttpDownload.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.core.upload; + +import android.app.Activity; +import android.os.Bundle; +import android.os.Environment; +import android.util.Log; +import android.view.View; +import com.arialyy.annotations.Download; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.common.ftp.FtpInterceptHandler; +import com.arialyy.aria.core.common.ftp.IFtpUploadInterceptor; +import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.upload.UploadEntity; +import com.arialyy.aria.core.upload.UploadTask; +import com.arialyy.frame.util.FileUtil; +import com.arialyy.frame.util.show.T; +import com.arialyy.simple.R; +import java.io.File; +import java.util.List; + +/** + * Created by lyy on 2017/7/28. HTTP 文件下载demo + * 文档 + */ +public class FtpUpload extends Activity { + private static final String TAG = "FtpUpload"; + private String mFilePath = Environment.getExternalStorageDirectory().getPath() + "/test.apk"; + private String mUrl = "http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk"; + + @Override protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Aria.download(this).register(); + // 读取历史记录信息 + DownloadEntity entity = Aria.download(this).getDownloadEntity(mFilePath); + if (entity != null) { + // 设置界面的进度、文件大小等信息 + } + } + + public void onClick(View view) { + switch (view.getId()) { + case R.id.start: + if (Aria.download(this).load(mUrl).isRunning()) { + Aria.download(this).load(mUrl).stop(); // 停止任务 + } else { + Aria.download(this) + .load(mUrl) // 下载url + .setFilePath(mFilePath) // 文件保存路径 + //.addHeader(key, value) // 添加头 + //.asPost() //或 asGet() + //.setParam() // 设置参数 + .start(); + } + break; + case R.id.cancel: + Aria.download(this).load(mUrl).cancel(); + break; + } + } + + @Download.onWait void onWait(DownloadTask task) { + Log.d(TAG, task.getTaskName() + "_wait"); + } + + @Download.onPre public void onPre(DownloadTask task) { + setFileSize(task.getConvertFileSize()); + } + + @Download.onTaskStart public void taskStart(DownloadTask task) { + Log.d(TAG, "开始下载,md5:" + FileUtil.getFileMD5(new File(task.getEntity().getFilePath()))); + } + + @Download.onTaskResume public void taskResume(DownloadTask task) { + Log.d(TAG, "恢复下载"); + } + + @Download.onTaskStop public void taskStop(DownloadTask task) { + setSpeed(""); + Log.d(TAG, "停止下载"); + } + + @Download.onTaskCancel public void taskCancel(DownloadTask task) { + setSpeed(""); + setFileSize(""); + setProgress(0); + Log.d(TAG, "删除任务"); + } + + @Download.onTaskFail public void taskFail(DownloadTask task) { + Log.d(TAG, "下载失败"); + } + + @Download.onTaskRunning public void taskRunning(DownloadTask task) { + Log.d(TAG, "PP = " + task.getPercent()); + setProgress(task.getPercent()); + setSpeed(task.getConvertSpeed()); + } + + @Download.onTaskComplete public void taskComplete(DownloadTask task) { + setProgress(100); + setSpeed(""); + T.showShort(this, "文件:" + task.getEntity().getFileName() + ",下载完成"); + } +} diff --git a/app/src/main/assets/help_code/KotlinHttpDownload.kt b/app/src/main/assets/help_code/KotlinHttpDownload.kt new file mode 100644 index 00000000..88892ffb --- /dev/null +++ b/app/src/main/assets/help_code/KotlinHttpDownload.kt @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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. + */ +import android.os.Bundle +import android.os.Environment +import android.util.Log +import android.view.View +import android.widget.Button +import android.widget.Toast +import com.arialyy.annotations.Download +import com.arialyy.aria.core.Aria +import com.arialyy.aria.core.download.DownloadTarget +import com.arialyy.aria.core.download.DownloadTask +import com.arialyy.aria.core.inf.IEntity +import com.arialyy.simple.R +import com.arialyy.simple.base.BaseActivity +import com.arialyy.simple.databinding.ActivitySingleBinding + +/** + * Created by lyy on 2017/10/23. + */ +class KotlinDownloadActivity : BaseActivity() { + + private val DOWNLOAD_URL = + "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk" + + private lateinit var mStart: Button + private lateinit var mStop: Button + private lateinit var mCancel: Button + private lateinit var target: DownloadTarget + + override fun setLayoutId(): Int { + return R.layout.activity_single + } + + override fun init(savedInstanceState: Bundle?) { + title = "kotlin测试" + Aria.get(this) + .downloadConfig.maxTaskNum = 2 + Aria.download(this) + .register() + mStart = findViewById(R.id.start) + mStop = findViewById(R.id.stop) + mCancel = findViewById(R.id.cancel) + mStop.visibility = View.GONE + + target = Aria.download(this) + .load(DOWNLOAD_URL) + binding.progress = target.percent + if (target.taskState == IEntity.STATE_STOP) { + mStart.text = "恢复" + } else if (target.isRunning) { + mStart.text = "停止" + } + binding.fileSize = target.convertFileSize + } + + /** + * 注解方法不能添加internal修饰符,否则会出现e: [kapt] An exception occurred: java.lang.IllegalArgumentException: index 1 for '$a' not in range (received 0 arguments)错误 + */ + @Download.onTaskRunning + fun running(task: DownloadTask) { + Log.d(TAG, task.percent.toString()) + val len = task.fileSize + if (len == 0L) { + binding.progress = 0 + } else { + binding.progress = task.percent + } + binding.speed = task.convertSpeed + } + + @Download.onWait + fun onWait(task: DownloadTask) { + if (task.key == DOWNLOAD_URL) { + Log.d(TAG, "wait ==> " + task.downloadEntity.fileName) + } + } + + @Download.onPre + fun onPre(task: DownloadTask) { + if (task.key == DOWNLOAD_URL) { + mStart.text = "停止" + } + } + + @Download.onTaskStart + fun taskStart(task: DownloadTask) { + if (task.key == DOWNLOAD_URL) { + binding.fileSize = task.convertFileSize + } + } + + @Download.onTaskComplete + fun complete(task: DownloadTask) { + Log.d(TAG, "完成") + } + + @Download.onTaskResume + fun taskResume(task: DownloadTask) { + if (task.key == DOWNLOAD_URL) { + mStart.text = "停止" + } + } + + @Download.onTaskStop + fun taskStop(task: DownloadTask) { + if (task.key == DOWNLOAD_URL) { + mStart.text = "恢复" + binding.speed = "" + } + } + + @Download.onTaskCancel + fun taskCancel(task: DownloadTask) { + if (task.key == DOWNLOAD_URL) { + binding.progress = 0 + Toast.makeText(this@KotlinDownloadActivity, "取消下载", Toast.LENGTH_SHORT) + .show() + mStart.text = "开始" + binding.speed = "" + Log.d(TAG, "cancel") + } + } + + @Download.onTaskFail + fun taskFail(task: DownloadTask) { + if (task.key == DOWNLOAD_URL) { + Toast.makeText(this@KotlinDownloadActivity, "下载失败", Toast.LENGTH_SHORT) + .show() + mStart.text = "开始" + } + } + + fun onClick(view: View) { + when (view.id) { + R.id.start -> { + if (target.isRunning) { + Aria.download(this) + .load(DOWNLOAD_URL) + .stop() + } else { + startD() + } + } + R.id.stop -> Aria.download(this).load(DOWNLOAD_URL).stop() + R.id.cancel -> Aria.download(this).load(DOWNLOAD_URL).cancel() + } + } + + private fun startD() { + Aria.download(this) + .load(DOWNLOAD_URL) + .addHeader("groupHash", "value") + .setFilePath(Environment.getExternalStorageDirectory().path + "/kotlin.apk") + .start() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/arialyy/simple/base/BaseActivity.java b/app/src/main/java/com/arialyy/simple/base/BaseActivity.java index 97448773..1e71236e 100644 --- a/app/src/main/java/com/arialyy/simple/base/BaseActivity.java +++ b/app/src/main/java/com/arialyy/simple/base/BaseActivity.java @@ -43,9 +43,11 @@ public abstract class BaseActivity extends AbsActivi @Override protected void init(Bundle savedInstanceState) { super.init(savedInstanceState); mBar = findViewById(R.id.toolbar); - setSupportActionBar(mBar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - mBar.setOnMenuItemClickListener(this); + if (mBar != null) { + setSupportActionBar(mBar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mBar.setOnMenuItemClickListener(this); + } } protected void setTile(String title) { diff --git a/app/src/main/java/com/arialyy/simple/base/BaseApplication.java b/app/src/main/java/com/arialyy/simple/base/BaseApplication.java index 3dcd7f94..0a58422e 100644 --- a/app/src/main/java/com/arialyy/simple/base/BaseApplication.java +++ b/app/src/main/java/com/arialyy/simple/base/BaseApplication.java @@ -23,7 +23,6 @@ import android.os.StrictMode; import com.arialyy.aria.core.Aria; import com.arialyy.frame.core.AbsFrame; import com.arialyy.simple.BuildConfig; -import com.arialyy.simple.common.ConnectionChangeReceiver; //import com.squareup.leakcanary.LeakCanary; /** @@ -46,15 +45,15 @@ public class BaseApplication extends Application { StrictMode.setThreadPolicy( new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); //if (LeakCanary.isInAnalyzerProcess(this)) {//1 - // This process is dedicated to LeakCanary for heap analysis. - // You should not init your app in this process. - //return; + // This process is dedicated to LeakCanary for heap analysis. + // You should not init your app in this process. + //return; //} //LeakCanary.install(this); - } + } - //registerReceiver(new ConnectionChangeReceiver(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); -} + //registerReceiver(new ConnectionChangeReceiver(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); + } public static BaseApplication getApp() { return INSTANCE; diff --git a/app/src/main/java/com/arialyy/simple/common/DialogModule.java b/app/src/main/java/com/arialyy/simple/common/DialogModule.java new file mode 100644 index 00000000..c594550f --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/common/DialogModule.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.common; + +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.text.TextUtils; +import com.arialyy.aria.util.ALog; +import com.arialyy.frame.base.BaseViewModule; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class DialogModule extends BaseViewModule { + + private MutableLiveData> mDirs = new MutableLiveData<>(); + + /** + * 获取指定目录下的文件夹 + * + * @param path 指定路径 + */ + LiveData> getDirs(String path) { + if (TextUtils.isEmpty(path)) { + ALog.e(TAG, "路径为空"); + return mDirs; + } + if (!path.startsWith("/")) { + ALog.e(TAG, "路径错误"); + return mDirs; + } + File file = new File(path); + File[] files = file.listFiles(); + List data = new ArrayList<>(); + for (File f : files) { + if (f.isDirectory()) { + data.add(f); + } + } + mDirs.postValue(data); + + return mDirs; + } +} diff --git a/app/src/main/java/com/arialyy/simple/common/DirChooseDialog.java b/app/src/main/java/com/arialyy/simple/common/DirChooseDialog.java new file mode 100644 index 00000000..23376c67 --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/common/DirChooseDialog.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.common; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.arch.lifecycle.Observer; +import android.arch.lifecycle.ViewModelProviders; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.os.Environment; +import android.support.annotation.Nullable; +import android.support.v7.widget.DividerItemDecoration; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.DisplayMetrics; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.TextView; +import com.arialyy.aria.util.ALog; +import com.arialyy.simple.R; +import com.arialyy.simple.base.BaseDialog; +import com.arialyy.simple.base.adapter.AbsHolder; +import com.arialyy.simple.base.adapter.AbsRVAdapter; +import com.arialyy.simple.base.adapter.RvItemClickSupport; +import com.arialyy.simple.databinding.DialogChooseDirBinding; +import com.arialyy.simple.databinding.DialogMsgBinding; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by AriaL on 2019/5/28. + */ +@SuppressLint("ValidFragment") public class DirChooseDialog + extends BaseDialog { + public static final int DIR_CHOOSE_DIALOG_RESULT = 0xB2; + private String mCurrentPath = Environment.getExternalStorageDirectory().getPath(); + private List mData = new ArrayList<>(); + private DialogModule mModule; + + public DirChooseDialog(Object obj) { + super(obj); + } + + @Override protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + getBinding().list.setLayoutManager(new LinearLayoutManager(getContext())); + getBinding().list.addItemDecoration( + new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL)); + final Adapter adapter = new Adapter(getContext(), mData); + getBinding().list.setAdapter(adapter); + getBinding().setCurrentPath(mCurrentPath); + + mModule = ViewModelProviders.of(this).get(DialogModule.class); + mModule.getDirs(mCurrentPath).observe(this, new Observer>() { + @Override public void onChanged(@Nullable List files) { + mData.clear(); + if (files != null && !files.isEmpty()) { + mData.addAll(files); + } + adapter.notifyDataSetChanged(); + if (mCurrentPath.equals(Environment.getExternalStorageDirectory().getPath())) { + getBinding().up.setVisibility(View.GONE); + } + getBinding().setCurrentPath(mCurrentPath); + getBinding().currentPath.setSelected(true); + } + }); + + getBinding().up.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + up(); + } + }); + + getBinding().enter.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + getSimplerModule().onDialog(DIR_CHOOSE_DIALOG_RESULT, mCurrentPath); + dismiss(); + } + }); + + RvItemClickSupport.addTo(getBinding().list).setOnItemClickListener( + new RvItemClickSupport.OnItemClickListener() { + @Override public void onItemClicked(RecyclerView recyclerView, int position, View v) { + getBinding().up.setVisibility(View.VISIBLE); + mCurrentPath = mCurrentPath.concat("/").concat(mData.get(position).getName()); + mModule.getDirs(mCurrentPath); + } + }); + } + + private void up() { + int endIndex = mCurrentPath.lastIndexOf("/"); + mCurrentPath = mCurrentPath.substring(0, endIndex); + mModule.getDirs(mCurrentPath); + } + + @Override public void onStart() { + super.onStart(); + Dialog dialog = getDialog(); + if (dialog != null) { + DisplayMetrics dm = new DisplayMetrics(); + getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); + dialog.getWindow() + .setLayout((dm.widthPixels), ViewGroup.LayoutParams.WRAP_CONTENT); + // 拦截返回键 + dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { + @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { + if (mCurrentPath.equals(Environment.getExternalStorageDirectory().getPath())) { + dismiss(); + } else { + up(); + } + return true; + } + return false; + } + }); + } + } + + @Override protected int setLayoutId() { + return R.layout.dialog_choose_dir; + } + + /** + * 适配器 + */ + private class Adapter extends AbsRVAdapter { + + Adapter(Context context, List data) { + super(context, data); + } + + @Override protected Holder getViewHolder(View convertView, int viewType) { + return new Holder(convertView); + } + + @Override protected int setLayoutId(int type) { + return R.layout.item_choose_dir; + } + + @Override protected void bindData(Holder holder, int position, File item) { + holder.text.setSelected(true); + holder.text.setText(item.getName()); + } + + private class Holder extends AbsHolder { + private TextView text; + + Holder(View itemView) { + super(itemView); + text = findViewById(R.id.text); + } + } + } +} diff --git a/app/src/main/java/com/arialyy/simple/common/ModifyPathDialog.java b/app/src/main/java/com/arialyy/simple/common/ModifyPathDialog.java new file mode 100644 index 00000000..df2f0cc1 --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/common/ModifyPathDialog.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.common; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.Toast; +import com.arialyy.simple.R; +import com.arialyy.simple.base.BaseDialog; +import com.arialyy.simple.databinding.DialogModifyPathBinding; +import com.arialyy.simple.databinding.DialogMsgBinding; +import java.io.File; + +/** + * Created by AriaL on 2019/5/28. + * 修改文件路径 + */ +@SuppressLint("ValidFragment") public class ModifyPathDialog + extends BaseDialog { + public static final int MODIFY_PATH_RESULT = 0xB3; + + private String mTitle, mFilePath, mDir; + + public ModifyPathDialog(Object obj, String title, String filePath) { + super(obj); + mTitle = title; + mFilePath = filePath; + } + + @Override protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + getBinding().setTitle(mTitle); + getBinding().setViewModel(this); + final File temp = new File(mFilePath); + mDir = temp.getParent(); + getBinding().setDir(mDir); + getBinding().setName(temp.getName()); + getBinding().edit.post(new Runnable() { + @Override public void run() { + getBinding().edit.setSelection(temp.getName().length()); + } + }); + getBinding().enter.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + if (TextUtils.isEmpty(getBinding().getName())) { + Toast.makeText(getContext(), getString(R.string.error_file_name_null), Toast.LENGTH_SHORT) + .show(); + return; + } + mFilePath = mDir + "/" + getBinding().getName(); + getSimplerModule().onDialog(MODIFY_PATH_RESULT, mFilePath); + dismiss(); + } + }); + getBinding().cancel.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + dismiss(); + } + }); + } + + public void chooseDir() { + DirChooseDialog dirChooseDialog = new DirChooseDialog(this); + dirChooseDialog.show(getChildFragmentManager(), "DirChooseDialog"); + } + + @Override protected int setLayoutId() { + return R.layout.dialog_modify_path; + } + + @Override protected void dataCallback(int result, Object data) { + super.dataCallback(result, data); + if (result == DirChooseDialog.DIR_CHOOSE_DIALOG_RESULT) { + mDir = String.valueOf(data); + getBinding().setDir(mDir); + } + } +} diff --git a/app/src/main/java/com/arialyy/simple/common/ModifyUrlDialog.java b/app/src/main/java/com/arialyy/simple/common/ModifyUrlDialog.java index ccb14259..c4592af4 100644 --- a/app/src/main/java/com/arialyy/simple/common/ModifyUrlDialog.java +++ b/app/src/main/java/com/arialyy/simple/common/ModifyUrlDialog.java @@ -23,7 +23,7 @@ import com.arialyy.simple.base.BaseDialog; import com.arialyy.simple.databinding.DialogModifyUrlBinding; /** - * Created by AriaL on 2017/6/3. + * Created by AriaL on 2019/5/27. */ @SuppressLint("ValidFragment") public class ModifyUrlDialog extends BaseDialog { @@ -48,7 +48,9 @@ import com.arialyy.simple.databinding.DialogModifyUrlBinding; }); getBinding().enter.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + mText = getBinding().getText(); getSimplerModule().onDialog(MODIFY_URL_DIALOG_RESULT, mText); + dismiss(); } }); getBinding().edit.post(new Runnable() { diff --git a/app/src/main/java/com/arialyy/simple/core/FullScreenCodeActivity.java b/app/src/main/java/com/arialyy/simple/core/FullScreenCodeActivity.java new file mode 100644 index 00000000..d0fcb3bd --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/core/FullScreenCodeActivity.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.core; + +import android.content.pm.ActivityInfo; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Window; +import android.view.WindowManager; +import com.arialyy.aria.util.ALog; +import com.arialyy.simple.R; +import com.arialyy.simple.base.BaseActivity; +import com.arialyy.simple.databinding.ActivityFullScreenCodeBinding; +import com.pddstudio.highlightjs.models.Language; +import com.pddstudio.highlightjs.models.Theme; +import java.io.File; + +/** + * 全是显示代码的actiivty + */ +public class FullScreenCodeActivity extends BaseActivity { + private static final String TAG = "FullScreenCodeActivity"; + public static final String KEY_FILE_PATH = "KEY_FILE_PATH"; + + @Override protected int setLayoutId() { + return R.layout.activity_full_screen_code; + } + + @Override protected void onCreate(Bundle savedInstanceState) { + //去除标题栏 + requestWindowFeature(Window.FEATURE_NO_TITLE); + //去除状态栏 + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + super.onCreate(savedInstanceState); + } + + @Override protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + String filePath = getIntent().getStringExtra(KEY_FILE_PATH); + + if (TextUtils.isEmpty(filePath)) { + ALog.e(TAG, "代码的文件路径为空"); + finish(); + return; + } + getBinding().codeView.setZoomSupportEnabled(true); + getBinding().codeView.setHighlightLanguage(Language.JAVA); + getBinding().codeView.setTheme(Theme.ANDROID_STUDIO); + getBinding().codeView.setSource(new File(filePath)); + + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } +} diff --git a/app/src/main/java/com/arialyy/simple/core/download/DownloadModule1.java b/app/src/main/java/com/arialyy/simple/core/download/DownloadModule1.java new file mode 100644 index 00000000..8219f7ff --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/core/download/DownloadModule1.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.core.download; + +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.content.Context; +import android.os.Environment; +import android.text.TextUtils; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.util.ALog; +import com.arialyy.frame.base.BaseViewModule; +import com.arialyy.simple.util.AppUtil; +import java.io.File; + +public class DownloadModule1 extends BaseViewModule { + private final String DOWNLOAD_URL_KEY = "DOWNLOAD_URL_KEY"; + private final String DOWNLOAD_PATH_KEY = "DOWNLOAD_PATH_KEY"; + + private final String defUrl = + "http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk"; + private final String defFilePath = + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath(); + + private MutableLiveData liveData = new MutableLiveData<>(); + private DownloadEntity singDownloadInfo; + + /** + * 单任务下载的信息 + */ + LiveData getSingDownloadInfo(Context context) { + String url = AppUtil.getConfigValue(context, DOWNLOAD_URL_KEY, defUrl); + String filePath = AppUtil.getConfigValue(context, DOWNLOAD_PATH_KEY, defFilePath); + + singDownloadInfo = Aria.download(context).getDownloadEntity(url); + if (singDownloadInfo == null) { + singDownloadInfo = new DownloadEntity(); + singDownloadInfo.setUrl(url); + File temp = new File(defFilePath); + singDownloadInfo.setDownloadPath(filePath); + singDownloadInfo.setFileName(temp.getName()); + } else { + AppUtil.setConfigValue(context, DOWNLOAD_PATH_KEY, singDownloadInfo.getDownloadPath()); + AppUtil.setConfigValue(context, DOWNLOAD_URL_KEY, singDownloadInfo.getUrl()); + } + liveData.postValue(singDownloadInfo); + + return liveData; + } + + /** + * 更新文件保存路径 + * + * @param filePath 文件保存路径 + */ + void updateFilePath(Context context, String filePath) { + if (TextUtils.isEmpty(filePath)) { + ALog.e(TAG, "文件保存路径为空"); + return; + } + File temp = new File(filePath); + AppUtil.setConfigValue(context, DOWNLOAD_PATH_KEY, filePath); + singDownloadInfo.setFileName(temp.getName()); + singDownloadInfo.setDownloadPath(filePath); + liveData.postValue(singDownloadInfo); + } + + /** + * 更新url + */ + void uploadUrl(Context context, String url) { + if (TextUtils.isEmpty(url)) { + ALog.e(TAG, "下载地址为空"); + return; + } + AppUtil.setConfigValue(context, DOWNLOAD_URL_KEY, url); + singDownloadInfo.setUrl(url); + liveData.postValue(singDownloadInfo); + } +} diff --git a/app/src/main/java/com/arialyy/simple/core/download/KotlinDownloadActivity.kt b/app/src/main/java/com/arialyy/simple/core/download/KotlinDownloadActivity.kt index 25a8cc59..93297e02 100644 --- a/app/src/main/java/com/arialyy/simple/core/download/KotlinDownloadActivity.kt +++ b/app/src/main/java/com/arialyy/simple/core/download/KotlinDownloadActivity.kt @@ -1,166 +1,317 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.core.download +import android.arch.lifecycle.Observer +import android.arch.lifecycle.ViewModelProviders +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent import android.os.Bundle -import android.os.Environment import android.util.Log +import android.view.Menu +import android.view.MenuItem import android.view.View -import android.widget.Button import android.widget.Toast + import com.arialyy.annotations.Download import com.arialyy.aria.core.Aria +import com.arialyy.aria.core.download.DownloadEntity import com.arialyy.aria.core.download.DownloadTarget import com.arialyy.aria.core.download.DownloadTask import com.arialyy.aria.core.inf.IEntity +import com.arialyy.aria.core.inf.IHttpFileLenAdapter +import com.arialyy.aria.core.scheduler.ISchedulers +import com.arialyy.aria.util.ALog +import com.arialyy.aria.util.CommonUtil import com.arialyy.frame.util.show.T import com.arialyy.simple.R import com.arialyy.simple.base.BaseActivity -import com.arialyy.simple.databinding.ActivitySingleBinding +import com.arialyy.simple.common.ModifyPathDialog +import com.arialyy.simple.common.ModifyUrlDialog +import com.arialyy.simple.databinding.ActivitySingleKotlinBinding +import com.arialyy.simple.util.AppUtil +import com.pddstudio.highlightjs.models.Language -/** - * Created by lyy on 2017/10/23. - */ -class KotlinDownloadActivity : BaseActivity() { +import java.io.IOException - private val DOWNLOAD_URL = - "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk" +class KotlinDownloadActivity : BaseActivity() { - private lateinit var mStart: Button - private lateinit var mStop: Button - private lateinit var mCancel: Button - private lateinit var target: DownloadTarget + private var mUrl: String? = null + private var mFilePath: String? = null + private var mModule: DownloadModule1? = null + private var mTarget: DownloadTarget? = null - override fun setLayoutId(): Int { - return R.layout.activity_single + internal var receiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive( + context: Context, + intent: Intent + ) { + if (intent.action == ISchedulers.ARIA_TASK_INFO_ACTION) { + ALog.d(TAG, "state = " + intent.getIntExtra(ISchedulers.TASK_STATE, -1)) + ALog.d(TAG, "type = " + intent.getIntExtra(ISchedulers.TASK_TYPE, -1)) + ALog.d(TAG, "speed = " + intent.getLongExtra(ISchedulers.TASK_SPEED, -1)) + ALog.d(TAG, "percent = " + intent.getIntExtra(ISchedulers.TASK_PERCENT, -1)) + ALog.d( + TAG, "entity = " + intent.getParcelableExtra( + ISchedulers.TASK_ENTITY + ).toString() + ) + } + } + } + + override fun onResume() { + super.onResume() + //registerReceiver(receiver, new IntentFilter(ISchedulers.ARIA_TASK_INFO_ACTION)); + } + + override fun onDestroy() { + super.onDestroy() + //unregisterReceiver(receiver); + Aria.download(this) + .unRegister() } override fun init(savedInstanceState: Bundle?) { - title = "kotlin测试" - Aria.get(this) - .downloadConfig.maxTaskNum = 2 + super.init(savedInstanceState) + title = "单任务下载" Aria.download(this) .register() - mStart = findViewById(R.id.start) - mStop = findViewById(R.id.stop) - mCancel = findViewById(R.id.cancel) - mStop.visibility = View.GONE - - target = Aria.download(this) - .load(DOWNLOAD_URL) - binding.progress = target.percent - if (target.taskState == IEntity.STATE_STOP) { - mStart.text = "恢复" - } else if (target.isRunning) { - mStart.text = "停止" + mModule = ViewModelProviders.of(this) + .get(DownloadModule1::class.java) + mModule!!.getSingDownloadInfo(this) + .observe(this, Observer { entity -> + if (entity == null) { + return@Observer + } + mTarget = Aria.download(this) + .load(entity.url) + if (mTarget!!.taskState == IEntity.STATE_STOP) { + binding.stateStr = getString(R.string.resume) + } else if (mTarget!!.isRunning) { + binding.stateStr = getString(R.string.stop) + } + + if (entity.fileSize != 0L) { + binding.fileSize = CommonUtil.formatFileSize(entity.fileSize.toDouble()) + binding.progress = if (entity.isComplete) + 100 + else + (entity.currentProgress * 100 / entity.fileSize).toInt() + } + binding.url = entity.url + binding.filePath = entity.filePath + mUrl = entity.url + mFilePath = entity.filePath + }) + binding.viewModel = this + try { + binding.codeView.setSource(AppUtil.getHelpCode(this, "KotlinHttpDownload.kt"), Language.JAVA) + } catch (e: IOException) { + e.printStackTrace() } - binding.fileSize = target.convertFileSize + } - /** - * 注解方法不能添加internal修饰符,否则会出现e: [kapt] An exception occurred: java.lang.IllegalArgumentException: index 1 for '$a' not in range (received 0 arguments)错误 - */ - @Download.onTaskRunning - fun running(task: DownloadTask) { - Log.d(TAG, task.percent.toString()) - val len = task.fileSize - if (len == 0L) { - binding.progress = 0 - } else { - binding.progress = task.percent + fun chooseUrl() { + val dialog = ModifyUrlDialog(this, getString(R.string.modify_url_dialog_title), mUrl) + dialog.show(supportFragmentManager, "ModifyUrlDialog") + } + + fun chooseFilePath() { + val dialog = ModifyPathDialog(this, getString(R.string.modify_file_path), mFilePath) + dialog.show(supportFragmentManager, "ModifyPathDialog") + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.menu_single_task_activity, menu) + return super.onCreateOptionsMenu(menu) + } + + override fun onMenuItemClick(item: MenuItem): Boolean { + var speed = -1 + var msg = "" + when (item.itemId) { + R.id.help -> { + msg = ("一些小知识点:\n" + + "1、你可以在注解中增加链接,用于指定被注解的方法只能被特定的下载任务回调,以防止progress乱跳\n" + + "2、当遇到网络慢的情况时,你可以先使用onPre()更新UI界面,待连接成功时,再在onTaskPre()获取完整的task数据,然后给UI界面设置正确的数据\n" + + "3、你可以在界面初始化时通过Aria.download(this).load(URL).getPercent()等方法快速获取相关任务的一些数据") + showMsgDialog("tip", msg) + } + R.id.speed_0 -> speed = 0 + R.id.speed_128 -> speed = 128 + R.id.speed_256 -> speed = 256 + R.id.speed_512 -> speed = 512 + R.id.speed_1m -> speed = 1024 + } + if (speed > -1) { + msg = item.title.toString() + Aria.download(this) + .setMaxSpeed(speed) + T.showShort(this, msg) } - binding.speed = task.convertSpeed + return true } @Download.onWait fun onWait(task: DownloadTask) { - if (task.key == DOWNLOAD_URL) { + if (task.key == mUrl) { Log.d(TAG, "wait ==> " + task.downloadEntity.fileName) } } @Download.onPre fun onPre(task: DownloadTask) { - if (task.key == DOWNLOAD_URL) { - mStart.text = "停止" + if (task.key == mUrl) { + binding.stateStr = getString(R.string.stop) } } @Download.onTaskStart fun taskStart(task: DownloadTask) { - if (task.key == DOWNLOAD_URL) { + if (task.key == mUrl) { binding.fileSize = task.convertFileSize } } - @Download.onTaskComplete - fun complete(task: DownloadTask) { - Log.d(TAG, "完成") + @Download.onTaskRunning + fun running(task: DownloadTask) { + if (task.key == mUrl) { + //Log.d(TAG, task.getKey()); + val len = task.fileSize + if (len == 0L) { + binding.progress = 0 + } else { + binding.progress = task.percent + } + binding.speed = task.convertSpeed + } } @Download.onTaskResume fun taskResume(task: DownloadTask) { - if (task.key == DOWNLOAD_URL) { - mStart.text = "停止" + if (task.key == mUrl) { + binding.stateStr = getString(R.string.stop) } } @Download.onTaskStop fun taskStop(task: DownloadTask) { - if (task.key == DOWNLOAD_URL) { - mStart.text = "恢复" + if (task.key == mUrl) { + binding.stateStr = getString(R.string.resume) binding.speed = "" } } @Download.onTaskCancel fun taskCancel(task: DownloadTask) { - if (task.key == DOWNLOAD_URL) { + if (task.key == mUrl) { binding.progress = 0 - Toast.makeText(this@KotlinDownloadActivity, "取消下载", Toast.LENGTH_SHORT) - .show() - mStart.text = "开始" + binding.stateStr = getString(R.string.start) binding.speed = "" Log.d(TAG, "cancel") } } + /** + * + */ @Download.onTaskFail - fun taskFail(task: DownloadTask) { - if (task.key == DOWNLOAD_URL) { - Toast.makeText(this@KotlinDownloadActivity, "下载失败", Toast.LENGTH_SHORT) + fun taskFail( + task: DownloadTask, + e: Exception + ) { + if (task.key == mUrl) { + Toast.makeText(this, getString(R.string.download_fail), Toast.LENGTH_SHORT) .show() - mStart.text = "开始" + binding.stateStr = getString(R.string.start) } } - @Download.onNoSupportBreakPoint - fun onNoSupportBreakPoint(task: DownloadTask) { - Log.d(TAG, "该下载链接不支持断点") - if (task.key == DOWNLOAD_URL) { - T.showShort(this@KotlinDownloadActivity, "该下载链接不支持断点") + @Download.onTaskComplete + fun taskComplete(task: DownloadTask) { + + if (task.key == mUrl) { + binding.progress = 100 + Toast.makeText( + this, getString(R.string.download_success), + Toast.LENGTH_SHORT + ) + .show() + binding.stateStr = getString(R.string.re_start) + binding.speed = "" } } + override fun setLayoutId(): Int { + return R.layout.activity_single_kotlin + } + fun onClick(view: View) { when (view.id) { - R.id.start -> { - if (target.isRunning) { - Aria.download(this) - .load(DOWNLOAD_URL) - .stop() - } else { - startD() - } + R.id.start -> if (mTarget!!.isRunning) { + Aria.download(this) + .load(mUrl!!) + .stop() + } else { + startD() } - R.id.stop -> Aria.download(this).load(DOWNLOAD_URL).stop() - R.id.cancel -> Aria.download(this).load(DOWNLOAD_URL).cancel() + R.id.stop -> Aria.download(this).load(mUrl!!).stop() + R.id.cancel -> Aria.download(this).load(mUrl!!).cancel(true) } } private fun startD() { Aria.download(this) - .load(DOWNLOAD_URL) - .addHeader("groupHash", "value") - .setFilePath(Environment.getExternalStorageDirectory().path + "/kotlin.apk") + .load(mUrl!!) + //.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3") + //.addHeader("Accept-Encoding", "gzip, deflate") + //.addHeader("DNT", "1") + //.addHeader("Cookie", "BAIDUID=648E5FF020CC69E8DD6F492D1068AAA9:FG=1; BIDUPSID=648E5FF020CC69E8DD6F492D1068AAA9; PSTM=1519099573; BD_UPN=12314753; locale=zh; BDSVRTM=0") + .useServerFileName(true) + .setFilePath(mFilePath!!, true) + .setFileLenAdapter(IHttpFileLenAdapter { headers -> + val sLength = headers["Content-Length"] + if (sLength == null || sLength.isEmpty()) { + return@IHttpFileLenAdapter -1 + } + val temp = sLength[0] + + java.lang.Long.parseLong(temp) + }) .start() } + + override fun onStop() { + super.onStop() + //Aria.download(this).unRegister(); + } + + override fun dataCallback( + result: Int, + data: Any + ) { + super.dataCallback(result, data) + if (result == ModifyUrlDialog.MODIFY_URL_DIALOG_RESULT) { + mModule!!.uploadUrl(this, data.toString()) + } else if (result == ModifyPathDialog.MODIFY_PATH_RESULT) { + mModule!!.updateFilePath(this, data.toString()) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java index d0d72cee..22aa11e6 100644 --- a/app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java @@ -16,25 +16,21 @@ package com.arialyy.simple.core.download; +import android.arch.lifecycle.Observer; +import android.arch.lifecycle.ViewModelProviders; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; import android.os.Bundle; -import android.os.Environment; -import android.os.Handler; -import android.text.TextUtils; +import android.support.annotation.Nullable; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.widget.Button; -import android.widget.RadioGroup; import android.widget.Toast; import com.arialyy.annotations.Download; import com.arialyy.aria.core.Aria; -import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadTarget; import com.arialyy.aria.core.download.DownloadTask; @@ -43,43 +39,24 @@ import com.arialyy.aria.core.inf.IHttpFileLenAdapter; import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; -import com.arialyy.frame.util.show.L; import com.arialyy.frame.util.show.T; import com.arialyy.simple.R; import com.arialyy.simple.base.BaseActivity; +import com.arialyy.simple.common.ModifyPathDialog; +import com.arialyy.simple.common.ModifyUrlDialog; import com.arialyy.simple.databinding.ActivitySingleBinding; -import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; -import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; -import com.bumptech.glide.load.resource.transcode.BitmapBytesTranscoder; -import java.io.File; -import java.util.HashMap; +import com.arialyy.simple.util.AppUtil; +import java.io.IOException; import java.util.List; import java.util.Map; public class SingleTaskActivity extends BaseActivity { - private String DOWNLOAD_URL = - //"http://kotlinlang.org/docs/kotlin-docs.pdf"; - //"https://atom-installer.github.com/v1.13.0/AtomSetup.exe?s=1484074138&ext=.exe"; - //"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apks"; - "http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk"; - //"http://120.55.95.61:8811/ghcg/zg/武义总规纲要成果.zip"; - //"https://yizi-kejian.oss-cn-beijing.aliyuncs.com/qimeng/package1/qmtable11.zip"; - //"http://rs.0.gaoshouyou.com/d/04/1e/400423a7551e1f3f0eb1812afa1f9b44.apk"; - //"http://chargepile2.techsum.net/car-manage/file/download?path=2019-04-26/c0242efd18be4ecbb23911b1c509dcad--掌通各系统汇总.xls"; // 无长度的chunked - //"http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载 - //"http://apk500.bce.baidu-mgame.com/game/67000/67734/20170622040827_oem_5502845.apk?r=1"; - //"https://dl.genymotion.com/releases/genymotion-2.12.1/genymotion-2.12.1-vbox.exe"; - //"http://9.9.9.50:5000/download/CentOS-7-x86_64-Minimal-1804.iso"; - //"http://v2.qingdian1.com/m_20180730_991/2/2B9FB34A4BCD8CE61481D1C8418EFE36_1080P.m3u8"; - //"https://firmwareapi.azurewebsites.net/firmware-overview?name=A19_Filament_W_IMG0038_00102411-encrypted.ota"; - Button mStart; - Button mStop; - Button mCancel; - RadioGroup mRg; - DownloadTarget target; + private String mUrl; + private String mFilePath; + private DownloadModule1 mModule; + private DownloadTarget mTarget; BroadcastReceiver receiver = new BroadcastReceiver() { @Override @@ -110,22 +87,51 @@ public class SingleTaskActivity extends BaseActivity { @Override protected void init(Bundle savedInstanceState) { super.init(savedInstanceState); - mStart = findViewById(R.id.start); - mStop = findViewById(R.id.stop); - mCancel = findViewById(R.id.cancel); - mRg = findViewById(R.id.speeds); - mStop.setVisibility(View.GONE); setTitle("单任务下载"); Aria.download(this).register(); - target = Aria.download(this).load(DOWNLOAD_URL); - getBinding().setProgress(target.getPercent()); - if (target.getTaskState() == IEntity.STATE_STOP) { - mStart.setText("恢复"); - //mStart.setTextColor(getResources().getColor(android.R.color.holo_blue_light)); - } else if (target.isRunning()) { - mStart.setText("停止"); + mModule = ViewModelProviders.of(this).get(DownloadModule1.class); + mModule.getSingDownloadInfo(this).observe(this, new Observer() { + + @Override public void onChanged(@Nullable DownloadEntity entity) { + if (entity == null) { + return; + } + mTarget = Aria.download(SingleTaskActivity.this).load(entity.getUrl()); + if (mTarget.getTaskState() == IEntity.STATE_STOP) { + getBinding().setStateStr(getString(R.string.resume)); + } else if (mTarget.isRunning()) { + getBinding().setStateStr(getString(R.string.stop)); + } + + if (entity.getFileSize() != 0) { + getBinding().setFileSize(CommonUtil.formatFileSize(entity.getFileSize())); + getBinding().setProgress(entity.isComplete() ? 100 + : (int) (entity.getCurrentProgress() * 100 / entity.getFileSize())); + } + getBinding().setUrl(entity.getUrl()); + getBinding().setFilePath(entity.getFilePath()); + mUrl = entity.getUrl(); + mFilePath = entity.getFilePath(); + } + }); + getBinding().setViewModel(this); + try { + getBinding().codeView.setSource(AppUtil.getHelpCode(this, "HttpDownload.java")); + } catch (IOException e) { + e.printStackTrace(); } - getBinding().setFileSize(target.getConvertFileSize()); + } + + public void chooseUrl() { + ModifyUrlDialog dialog = + new ModifyUrlDialog(this, getString(R.string.modify_url_dialog_title), mUrl); + dialog.show(getSupportFragmentManager(), "ModifyUrlDialog"); + } + + public void chooseFilePath() { + ModifyPathDialog dialog = + new ModifyPathDialog(this, getString(R.string.modify_file_path), mFilePath); + dialog.show(getSupportFragmentManager(), "ModifyPathDialog"); } @Override @@ -172,61 +178,59 @@ public class SingleTaskActivity extends BaseActivity { @Download.onWait void onWait(DownloadTask task) { - if (task.getKey().equals(DOWNLOAD_URL)) { + if (task.getKey().equals(mUrl)) { Log.d(TAG, "wait ==> " + task.getDownloadEntity().getFileName()); } } @Download.onPre protected void onPre(DownloadTask task) { - if (task.getKey().equals(DOWNLOAD_URL)) { - mStart.setText("停止"); + if (task.getKey().equals(mUrl)) { + getBinding().setStateStr(getString(R.string.stop)); } } @Download.onTaskStart void taskStart(DownloadTask task) { - if (task.getKey().equals(DOWNLOAD_URL)) { + if (task.getKey().equals(mUrl)) { getBinding().setFileSize(task.getConvertFileSize()); } } @Download.onTaskRunning protected void running(DownloadTask task) { - //ALog.d(TAG, String.format("%s_running_%s", getClass().getName(), hashCode())); - //if (task.getKey().equals(DOWNLOAD_URL)) { - //Log.d(TAG, task.getKey()); - long len = task.getFileSize(); - if (len == 0) { - getBinding().setProgress(0); - } else { - getBinding().setProgress(task.getPercent()); + if (task.getKey().equals(mUrl)) { + //Log.d(TAG, task.getKey()); + long len = task.getFileSize(); + if (len == 0) { + getBinding().setProgress(0); + } else { + getBinding().setProgress(task.getPercent()); + } + getBinding().setSpeed(task.getConvertSpeed()); } - getBinding().setSpeed(task.getConvertSpeed()); - //} } @Download.onTaskResume void taskResume(DownloadTask task) { - if (task.getKey().equals(DOWNLOAD_URL)) { - mStart.setText("停止"); + if (task.getKey().equals(mUrl)) { + getBinding().setStateStr(getString(R.string.stop)); } } @Download.onTaskStop void taskStop(DownloadTask task) { - if (task.getKey().equals(DOWNLOAD_URL)) { - mStart.setText("恢复"); + if (task.getKey().equals(mUrl)) { + getBinding().setStateStr(getString(R.string.resume)); getBinding().setSpeed(""); } } @Download.onTaskCancel void taskCancel(DownloadTask task) { - if (task.getKey().equals(DOWNLOAD_URL)) { + if (task.getKey().equals(mUrl)) { getBinding().setProgress(0); - Toast.makeText(SingleTaskActivity.this, "取消下载", Toast.LENGTH_SHORT).show(); - mStart.setText("开始"); + getBinding().setStateStr(getString(R.string.start)); getBinding().setSpeed(""); Log.d(TAG, "cancel"); } @@ -237,48 +241,22 @@ public class SingleTaskActivity extends BaseActivity { */ @Download.onTaskFail void taskFail(DownloadTask task, Exception e) { - if (task.getKey().equals(DOWNLOAD_URL)) { - Toast.makeText(SingleTaskActivity.this, "下载失败", Toast.LENGTH_SHORT).show(); - mStart.setText("开始"); + if (task.getKey().equals(mUrl)) { + Toast.makeText(SingleTaskActivity.this, getString(R.string.download_fail), Toast.LENGTH_SHORT) + .show(); + getBinding().setStateStr(getString(R.string.start)); } } @Download.onTaskComplete void taskComplete(DownloadTask task) { - //Glide.with(this).load("").asBitmap().transform(new BitmapTransformation() { - // @Override - // protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { - // return null; - // } - // - // @Override public String getId() { - // return null; - // } - //}) - //if (task.getKey().equals(DOWNLOAD_URL)) { - getBinding().setProgress(100); - Toast.makeText(SingleTaskActivity.this, "下载完成", Toast.LENGTH_SHORT).show(); - mStart.setText("重新开始?"); - //mCancel.setEnabled(false); - getBinding().setSpeed(""); - L.d(TAG, "path = " + task.getDownloadEntity().getDownloadPath()); - L.d(TAG, "md5Code = " + CommonUtil.getFileMD5(new File(task.getDownloadPath()))); - L.d(TAG, "data = " + Aria.download(this).getDownloadEntity(DOWNLOAD_URL)); - //DownloadEntity temp = Aria.download(this).getDownloadEntity(DOWNLOAD_URL); - //L.d(TAG, "status = " + temp.getState() + ", isComplete = " + temp.isComplete()); - //Intent install = new Intent(Intent.ACTION_VIEW); - //install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - //File apkFile = new File(task.getDownloadPath()); - //install.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); - //startActivity(install); - //} - } - @Download.onNoSupportBreakPoint - public void onNoSupportBreakPoint(DownloadTask task) { - Log.d(TAG, "该下载链接不支持断点"); - if (task.getKey().equals(DOWNLOAD_URL)) { - T.showShort(SingleTaskActivity.this, "该下载链接不支持断点"); + if (task.getKey().equals(mUrl)) { + getBinding().setProgress(100); + Toast.makeText(SingleTaskActivity.this, getString(R.string.download_success), + Toast.LENGTH_SHORT).show(); + getBinding().setStateStr(getString(R.string.re_start)); + getBinding().setSpeed(""); } } @@ -290,35 +268,30 @@ public class SingleTaskActivity extends BaseActivity { public void onClick(View view) { switch (view.getId()) { case R.id.start: - if (target.isRunning()) { - Aria.download(this).load(DOWNLOAD_URL).stop(); + if (mTarget.isRunning()) { + Aria.download(this).load(mUrl).stop(); } else { startD(); } break; case R.id.stop: - Aria.download(this).load(DOWNLOAD_URL).stop(); + Aria.download(this).load(mUrl).stop(); break; case R.id.cancel: - Aria.download(this).load(DOWNLOAD_URL).reStart(); - //Aria.download(this).load(DOWNLOAD_URL).cancel(true); - //Aria.download(this).load(DOWNLOAD_URL).removeRecord(); + Aria.download(this).load(mUrl).cancel(true); break; } } - int i = 1; - private void startD() { - String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/ggsg14.apk"; Aria.download(SingleTaskActivity.this) - .load(DOWNLOAD_URL) + .load(mUrl) //.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3") //.addHeader("Accept-Encoding", "gzip, deflate") //.addHeader("DNT", "1") //.addHeader("Cookie", "BAIDUID=648E5FF020CC69E8DD6F492D1068AAA9:FG=1; BIDUPSID=648E5FF020CC69E8DD6F492D1068AAA9; PSTM=1519099573; BD_UPN=12314753; locale=zh; BDSVRTM=0") .useServerFileName(true) - .setFilePath(path, true) + .setFilePath(mFilePath, true) .setFileLenAdapter(new IHttpFileLenAdapter() { @Override public long handleFileLen(Map> headers) { @@ -331,15 +304,7 @@ public class SingleTaskActivity extends BaseActivity { return Long.parseLong(temp); } }) - //.asGet() - //.asPost() - //.setParams(params) - //.setExtendField("{\n" - // + "\"id\":\"你的样子\"\n< > " - // + "}") - //.resetState() .start(); - //.add(); } @Override @@ -347,4 +312,13 @@ public class SingleTaskActivity extends BaseActivity { super.onStop(); //Aria.download(this).unRegister(); } + + @Override protected void dataCallback(int result, Object data) { + super.dataCallback(result, data); + if (result == ModifyUrlDialog.MODIFY_URL_DIALOG_RESULT) { + mModule.uploadUrl(this, String.valueOf(data)); + } else if (result == ModifyPathDialog.MODIFY_PATH_RESULT) { + mModule.updateFilePath(this, String.valueOf(data)); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/arialyy/simple/core/test/TestFTPActivity.java b/app/src/main/java/com/arialyy/simple/core/test/TestFTPActivity.java index bc82ce26..a738ca08 100644 --- a/app/src/main/java/com/arialyy/simple/core/test/TestFTPActivity.java +++ b/app/src/main/java/com/arialyy/simple/core/test/TestFTPActivity.java @@ -3,9 +3,9 @@ package com.arialyy.simple.core.test; import android.os.Bundle; import android.util.Log; import android.view.View; -import com.arialyy.annotations.Upload; +import com.arialyy.annotations.Download; import com.arialyy.aria.core.Aria; -import com.arialyy.aria.core.upload.UploadTask; +import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.util.CommonUtil; import com.arialyy.simple.R; import com.arialyy.simple.base.BaseActivity; @@ -13,16 +13,14 @@ import com.arialyy.simple.databinding.ActivityTestBinding; import java.io.File; /** - * Created by Administrator on 2018/4/12. + * Created by lyy on 2019/5/28. + * Ftp 下载 + * 文档 */ - public class TestFTPActivity extends BaseActivity { String TAG = "TestFTPActivity"; - //String URL = "http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载 - //private final String URL = "ftp://192.168.1.3:21/download//AriaPrj.rar"; - private final String FILE_PATH = "/mnt/sdcard/mmm.mp4"; - private final String URL = "ftps://9.9.9.59:990/aa/你好"; - + private final String URL = "ftp://192.168.1.3:21/download//AriaPrj.rar"; + private final String FILE_PATH = "/mnt/sdcard/AriaPrj.rar"; @Override protected int setLayoutId() { return R.layout.activity_test; @@ -31,65 +29,62 @@ public class TestFTPActivity extends BaseActivity { @Override protected void init(Bundle savedInstanceState) { super.init(savedInstanceState); mBar.setVisibility(View.GONE); - Aria.upload(this).register(); - Aria.upload(this).setMaxSpeed(128); + Aria.download(this).register(); } - @Upload.onWait void onWait(UploadTask task) { + @Download.onWait void onWait(DownloadTask task) { Log.d(TAG, "wait ==> " + task.getEntity().getFileName()); } - @Upload.onPre protected void onPre(UploadTask task) { + @Download.onPre protected void onPre(DownloadTask task) { Log.d(TAG, "onPre"); } - @Upload.onTaskStart void taskStart(UploadTask task) { + @Download.onTaskStart void taskStart(DownloadTask task) { Log.d(TAG, "onStart"); } - @Upload.onTaskRunning protected void running(UploadTask task) { + @Download.onTaskRunning protected void running(DownloadTask task) { Log.d(TAG, "running,speed=" + task.getConvertSpeed()); } - @Upload.onTaskResume void taskResume(UploadTask task) { + @Download.onTaskResume void taskResume(DownloadTask task) { Log.d(TAG, "resume"); } - @Upload.onTaskStop void taskStop(UploadTask task) { + @Download.onTaskStop void taskStop(DownloadTask task) { Log.d(TAG, "stop"); } - @Upload.onTaskCancel void taskCancel(UploadTask task) { + @Download.onTaskCancel void taskCancel(DownloadTask task) { Log.d(TAG, "cancel"); } - @Upload.onTaskFail void taskFail(UploadTask task) { + @Download.onTaskFail void taskFail(DownloadTask task) { Log.d(TAG, "fail"); } - @Upload.onTaskComplete void taskComplete(UploadTask task) { + @Download.onTaskComplete void taskComplete(DownloadTask task) { Log.d(TAG, "complete, md5 => " + CommonUtil.getFileMD5(new File(task.getKey()))); } public void onClick(View view) { switch (view.getId()) { case R.id.start: - Aria.upload(this) - .loadFtp(FILE_PATH) + Aria.download(this) + .loadFtp(URL) + .setFilePath(FILE_PATH) .login("lao", "123456") - .setUploadUrl(URL) - .asFtps() - .setStorePath("/mnt/sdcard/Download/server.crt") - .setAlias("www.laoyuyu.me") + //.asFtps() // ftps 配置 + //.setStorePath("/mnt/sdcard/Download/server.crt") //设置证书路径 + // .setAlias("www.laoyuyu.me") // 设置证书别名 .start(); - //Uri uri = Uri.parse("ftp://z:z@dygod18.com:21211/[电影天堂www.dy2018.com]猩球崛起3:终极之战BD国英双语中英双字.mkv"); - //ALog.d(TAG, "sh = " + uri.getScheme() + ", user = " + uri.getUserInfo() + ", host = " + uri.getHost() + ", port = " + uri.getPort() + " remotePath = " + uri.getPath()); break; case R.id.stop: - Aria.upload(this).loadFtp(FILE_PATH).stop(); + Aria.download(this).loadFtp(FILE_PATH).stop(); break; case R.id.cancel: - Aria.upload(this).loadFtp(FILE_PATH).cancel(); + Aria.download(this).loadFtp(FILE_PATH).cancel(); break; } } diff --git a/app/src/main/java/com/arialyy/simple/core/upload/FtpUploadActivity.java b/app/src/main/java/com/arialyy/simple/core/upload/FtpUploadActivity.java index c46c6868..8f70f0bf 100644 --- a/app/src/main/java/com/arialyy/simple/core/upload/FtpUploadActivity.java +++ b/app/src/main/java/com/arialyy/simple/core/upload/FtpUploadActivity.java @@ -15,11 +15,11 @@ */ package com.arialyy.simple.core.upload; +import android.arch.lifecycle.Observer; import android.content.Intent; import android.net.Uri; -import android.os.Build; import android.os.Bundle; -import android.support.v4.content.FileProvider; +import android.support.annotation.Nullable; import android.util.Log; import android.view.View; import com.arialyy.annotations.Upload; @@ -28,38 +28,64 @@ import com.arialyy.aria.core.common.ftp.FtpInterceptHandler; import com.arialyy.aria.core.common.ftp.IFtpUploadInterceptor; import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadTask; +import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; import com.arialyy.frame.util.FileUtil; import com.arialyy.frame.util.show.T; -import com.arialyy.simple.BuildConfig; import com.arialyy.simple.R; import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.common.ModifyUrlDialog; import com.arialyy.simple.databinding.ActivityFtpUploadBinding; +import com.arialyy.simple.util.AppUtil; import java.io.File; +import java.io.IOException; import java.util.List; +import android.arch.lifecycle.ViewModelProviders; /** * Created by lyy on 2017/7/28. Ftp 文件上传demo */ public class FtpUploadActivity extends BaseActivity { private final int OPEN_FILE_MANAGER_CODE = 0xB1; - private String mFilePath = "/mnt/sdcard/AriaPrj.rar"; - private String mUrl = "ftp://9.9.9.205:2121/aa/你好"; + private String mFilePath; + private String mUrl; + private UploadModule mModule; @Override protected void init(Bundle savedInstanceState) { setTile("D_FTP 文件上传"); super.init(savedInstanceState); Aria.upload(this).register(); - UploadEntity entity = Aria.upload(this).getUploadEntity(mFilePath); - if (entity != null) { - getBinding().setFileSize(CommonUtil.formatFileSize(entity.getFileSize())); - getBinding().setProgress(entity.isComplete() ? 100 - : (int) (entity.getCurrentProgress() * 100 / entity.getFileSize())); - } - getBinding().setUrl(mUrl); - getBinding().setFilePath(mFilePath); + getBinding().setViewModel(this); + setUI(); + } + + private void setUI() { + mModule = ViewModelProviders.of(this).get(UploadModule.class); + mModule.getFtpInfo(this).observe(this, new Observer() { + @Override public void onChanged(@Nullable UploadEntity entity) { + if (entity != null) { + if (entity.getFileSize() != 0) { + getBinding().setFileSize(CommonUtil.formatFileSize(entity.getFileSize())); + getBinding().setProgress(entity.isComplete() ? 100 + : (int) (entity.getCurrentProgress() * 100 / entity.getFileSize())); + } + getBinding().setUrl(entity.getUrl()); + getBinding().setFilePath(entity.getFilePath()); + mUrl = entity.getUrl(); + mFilePath = entity.getFilePath(); + } + } + }); + setHelpCode(); + } + + private void setHelpCode() { + try { + getBinding().codeView.setSource(AppUtil.getHelpCode(this, "FtpUpload.java")); + } catch (IOException e) { + e.printStackTrace(); + } } @Override protected int setLayoutId() { @@ -73,23 +99,7 @@ public class FtpUploadActivity extends BaseActivity { } public void chooseFilePath() { - - File parentFile = new File(mFilePath); - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - Uri uri; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - uri = FileProvider.getUriForFile(this, - BuildConfig.APPLICATION_ID + ".provider", - parentFile.getParentFile()); - } else { - uri = Uri.fromFile(parentFile.getParentFile()); - } - - intent.setDataAndType(uri, "*/*"); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - startActivityForResult(intent, OPEN_FILE_MANAGER_CODE); + AppUtil.chooseFile(this, new File(mFilePath), null, OPEN_FILE_MANAGER_CODE); } public void onClick(View view) { @@ -169,8 +179,7 @@ public class FtpUploadActivity extends BaseActivity { @Override protected void dataCallback(int result, Object data) { super.dataCallback(result, data); if (result == ModifyUrlDialog.MODIFY_URL_DIALOG_RESULT) { - mUrl = String.valueOf(data); - getBinding().setUrl(mUrl); + mModule.updateFtpUrl(this, String.valueOf(data)); } } @@ -178,7 +187,12 @@ public class FtpUploadActivity extends BaseActivity { super.onActivityResult(requestCode, resultCode, data); if (requestCode == OPEN_FILE_MANAGER_CODE && resultCode == RESULT_OK) { Uri uri = data.getData(); - //Toast.makeText(this, "文件路径:" + uri.getPath(), Toast.LENGTH_SHORT).show(); + if (uri != null) { + mModule.updateFtpFilePath(this, uri.getPath()); + ALog.d(TAG, String.format("选择的文件路径:%s", uri.getPath())); + } else { + ALog.d(TAG, "没有选择文件"); + } } } } diff --git a/app/src/main/java/com/arialyy/simple/core/upload/UploadModule.java b/app/src/main/java/com/arialyy/simple/core/upload/UploadModule.java new file mode 100644 index 00000000..c4460160 --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/core/upload/UploadModule.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.core.upload; + +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.content.Context; +import android.os.Environment; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.upload.UploadEntity; +import com.arialyy.frame.base.BaseViewModule; +import com.arialyy.simple.util.AppUtil; + +public class UploadModule extends BaseViewModule { + private final String FTP_URL_KEY = "FTP_URL_KEY"; + private final String FTP_PATH_KEY = "FTP_PATH_KEY"; + private MutableLiveData liveData = new MutableLiveData<>(); + UploadEntity uploadInfo; + + /** + * 获取Ftp上传信息 + */ + LiveData getFtpInfo(Context context) { + String url = AppUtil.getConfigValue(context, FTP_URL_KEY, "ftp://9.9.9.205:2121/aa/你好"); + String filePath = AppUtil.getConfigValue(context, FTP_PATH_KEY, + Environment.getExternalStorageDirectory().getPath() + "/AriaPrj.rar"); + + UploadEntity entity = Aria.upload(context).getUploadEntity(filePath); + if (entity != null) { + uploadInfo = entity; + AppUtil.setConfigValue(context, FTP_URL_KEY, uploadInfo.getUrl()); + AppUtil.setConfigValue(context, FTP_PATH_KEY, uploadInfo.getFilePath()); + } else { + uploadInfo = new UploadEntity(); + uploadInfo.setUrl(url); + uploadInfo.setFilePath(filePath); + } + + liveData.postValue(uploadInfo); + return liveData; + } + + /** + * 更新Url + */ + void updateFtpUrl(Context context, String url) { + uploadInfo.setUrl(url); + AppUtil.setConfigValue(context, FTP_URL_KEY, url); + liveData.postValue(uploadInfo); + } + + /** + * 更新文件路径 + */ + void updateFtpFilePath(Context context, String filePath) { + uploadInfo.setFilePath(filePath); + AppUtil.setConfigValue(context, FTP_PATH_KEY, filePath); + liveData.postValue(uploadInfo); + } +} diff --git a/app/src/main/java/com/arialyy/simple/util/AppUtil.java b/app/src/main/java/com/arialyy/simple/util/AppUtil.java new file mode 100644 index 00000000..ce3f97c7 --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/util/AppUtil.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.util; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Build; +import android.support.v4.content.FileProvider; +import android.text.TextUtils; +import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; +import com.arialyy.simple.BuildConfig; +import java.io.File; +import java.io.IOException; + +public class AppUtil { + private static final String TAG = "AppUtil"; + private static final String ARIA_SHARE_PRE_KEY = "ARIA_SHARE_PRE_KEY"; + + /** + * http下载示例代码 + */ + public static File getHelpCode(Context context, String fileName) throws IOException { + String path = String.format("%s/code/%s", context.getFilesDir().getPath(), fileName); + File ftpCode = new File(path); + if (!ftpCode.exists()) { + CommonUtil.createFile(path); + CommonUtil.createFileFormInputStream(context.getAssets() + .open(String.format("help_code/%s", fileName)), + path); + } + return ftpCode; + } + + /** + * 读取配置文件字段 + * + * @param key key + * @param defStr 默认字符串 + */ + public static String getConfigValue(Context context, String key, String defStr) { + SharedPreferences preferences = + context.getSharedPreferences(ARIA_SHARE_PRE_KEY, Context.MODE_PRIVATE); + return preferences.getString(key, defStr); + } + + /** + * set配置文件字段 + * + * @param key key + * @param value 需要保存的字符串 + */ + public static void setConfigValue(Context context, String key, String value) { + SharedPreferences preferences = + context.getSharedPreferences(ARIA_SHARE_PRE_KEY, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(key, value); + editor.apply(); + } + + /** + * 调用系统文件管理器选择文件 + * + * @param file 不能是文件夹 + * @param mineType android 可用的minetype + * @param requestCode 请求码 + */ + public static void chooseFile(Activity activity, File file, String mineType, int requestCode) { + if (file.isDirectory()) { + ALog.e(TAG, "不能选择文件夹"); + return; + } + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + Uri uri; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + uri = FileProvider.getUriForFile(activity.getApplicationContext(), + BuildConfig.APPLICATION_ID + ".provider", + file); + } else { + uri = Uri.fromFile(file); + } + + intent.setDataAndType(uri, TextUtils.isEmpty(mineType) ? "*/*" : mineType); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + activity.startActivityForResult(intent, requestCode); + } +} diff --git a/app/src/main/java/com/arialyy/simple/widget/CodeView.java b/app/src/main/java/com/arialyy/simple/widget/CodeView.java new file mode 100644 index 00000000..83767e9e --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/widget/CodeView.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.simple.widget; + +import android.content.Context; +import android.content.Intent; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.RelativeLayout; +import com.arialyy.simple.R; +import com.arialyy.simple.core.FullScreenCodeActivity; +import com.pddstudio.highlightjs.HighlightJsView; +import com.pddstudio.highlightjs.models.Language; +import com.pddstudio.highlightjs.models.Theme; +import java.io.File; + +/** + * 代码高亮控件 + */ +public class CodeView extends RelativeLayout { + + private HighlightJsView mCodeView; + private File mSourceFile; + + public CodeView(Context context) { + super(context, null); + } + + public CodeView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + private void init(Context context) { + LayoutInflater.from(context).inflate(R.layout.layout_code_demo, this, true); + mCodeView = findViewById(R.id.js_view); + mCodeView.setHighlightLanguage(Language.JAVA); + mCodeView.setTheme(Theme.ANDROID_STUDIO); + mCodeView.setZoomSupportEnabled(true); + findViewById(R.id.full_screen).setOnClickListener(new OnClickListener() { + @Override public void onClick(View v) { + // 横屏显示代码 + Intent intent = new Intent(getContext(), FullScreenCodeActivity.class); + intent.putExtra(FullScreenCodeActivity.KEY_FILE_PATH, mSourceFile.getPath()); + getContext().startActivity(intent); + } + }); + } + + public void setSource(File sourceFile) { + mSourceFile = sourceFile; + mCodeView.setSource(sourceFile); + } + + + public void setSource(File sourceFile, Language language) { + mSourceFile = sourceFile; + mCodeView.setHighlightLanguage(language); + mCodeView.setSource(sourceFile); + } +} diff --git a/app/src/main/java/com/arialyy/simple/widget/SvgTextView.java b/app/src/main/java/com/arialyy/simple/widget/SvgTextView.java index cdd72166..e2cb2d09 100644 --- a/app/src/main/java/com/arialyy/simple/widget/SvgTextView.java +++ b/app/src/main/java/com/arialyy/simple/widget/SvgTextView.java @@ -21,6 +21,7 @@ import android.databinding.BindingAdapter; import android.graphics.drawable.Drawable; import android.support.annotation.DrawableRes; import android.support.v7.widget.AppCompatImageView; +import android.text.Html; import android.text.TextUtils; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -78,7 +79,7 @@ public class SvgTextView extends RelativeLayout { icon.setImageResource(drawable); } - public void setText(CharSequence text) { - textView.setText(text); + public void setText(String text) { + textView.setText(Html.fromHtml(text)); } } diff --git a/app/src/main/res/drawable/ic_choose_file.xml b/app/src/main/res/drawable/ic_choose_file.xml index 2a4617a0..224fbad5 100644 --- a/app/src/main/res/drawable/ic_choose_file.xml +++ b/app/src/main/res/drawable/ic_choose_file.xml @@ -1,6 +1,15 @@ - - - - + + + + diff --git a/app/src/main/res/drawable/ic_dir.xml b/app/src/main/res/drawable/ic_dir.xml new file mode 100644 index 00000000..b92c5ddc --- /dev/null +++ b/app/src/main/res/drawable/ic_dir.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_full_screen.xml b/app/src/main/res/drawable/ic_full_screen.xml new file mode 100644 index 00000000..7c1d6bd1 --- /dev/null +++ b/app/src/main/res/drawable/ic_full_screen.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_modify.xml b/app/src/main/res/drawable/ic_modify.xml index ee86c638..cc88dcdf 100644 --- a/app/src/main/res/drawable/ic_modify.xml +++ b/app/src/main/res/drawable/ic_modify.xml @@ -4,6 +4,6 @@ android:viewportWidth="1024" android:width="24dp"> diff --git a/app/src/main/res/layout/activity_ftp_upload.xml b/app/src/main/res/layout/activity_ftp_upload.xml index adab8e88..174e9ab4 100644 --- a/app/src/main/res/layout/activity_ftp_upload.xml +++ b/app/src/main/res/layout/activity_ftp_upload.xml @@ -71,5 +71,13 @@ bind:stateStr="@{stateStr}" /> + + + + diff --git a/app/src/main/res/layout/activity_full_screen_code.xml b/app/src/main/res/layout/activity_full_screen_code.xml new file mode 100644 index 00000000..552c5cbd --- /dev/null +++ b/app/src/main/res/layout/activity_full_screen_code.xml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/activity_single.xml b/app/src/main/res/layout/activity_single.xml index 0fac024c..7716da64 100644 --- a/app/src/main/res/layout/activity_single.xml +++ b/app/src/main/res/layout/activity_single.xml @@ -16,40 +16,71 @@ name="progress" type="int" /> + + + + + - - + + - - + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:layout_marginTop="16dp" + bind:iconClickListener="@{() -> viewModel.chooseUrl()}" + bind:svg_text_view_icon="@drawable/ic_modify" + bind:text="@{@string/url(url)}" + /> - + - - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_single_kotlin.xml b/app/src/main/res/layout/activity_single_kotlin.xml new file mode 100644 index 00000000..1dfc66fd --- /dev/null +++ b/app/src/main/res/layout/activity_single_kotlin.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_choose_dir.xml b/app/src/main/res/layout/dialog_choose_dir.xml new file mode 100644 index 00000000..633f980a --- /dev/null +++ b/app/src/main/res/layout/dialog_choose_dir.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + +