Merge branch 'v_2.0'
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -37,7 +37,7 @@
|
|||||||
<ConfirmationsSetting value="0" id="Add" />
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
<ConfirmationsSetting value="0" id="Remove" />
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
2
.idea/modules.xml
generated
2
.idea/modules.xml
generated
@ -3,7 +3,9 @@
|
|||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/Aria.iml" filepath="$PROJECT_DIR$/Aria.iml" />
|
<module fileurl="file://$PROJECT_DIR$/Aria.iml" filepath="$PROJECT_DIR$/Aria.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/Aria/Aria.iml" filepath="$PROJECT_DIR$/Aria/Aria.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/Aria/Aria-Aria.iml" filepath="$PROJECT_DIR$/Aria/Aria-Aria.iml" />
|
<module fileurl="file://$PROJECT_DIR$/Aria/Aria-Aria.iml" filepath="$PROJECT_DIR$/Aria/Aria-Aria.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/AriaPrj.iml" filepath="$PROJECT_DIR$/AriaPrj.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -7,8 +7,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 9
|
minSdkVersion 9
|
||||||
targetSdkVersion 23
|
targetSdkVersion 23
|
||||||
versionCode 85
|
versionCode 86
|
||||||
versionName "2.3.7"
|
versionName "2.4.2"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
|
@ -15,9 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.arialyy.aria.core;
|
package com.arialyy.aria.core;
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
|
||||||
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
|
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
|
||||||
import com.arialyy.aria.core.scheduler.OnSchedulerListener;
|
import com.arialyy.aria.core.scheduler.OnSchedulerListener;
|
||||||
import com.arialyy.aria.util.CheckUtil;
|
import com.arialyy.aria.util.CheckUtil;
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.arialyy.aria.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/1/18.
|
||||||
|
* AM 上传文件接收器
|
||||||
|
*/
|
||||||
|
public class AMUplodReceiver {
|
||||||
|
}
|
@ -28,6 +28,7 @@ import android.os.Build;
|
|||||||
import android.widget.PopupWindow;
|
import android.widget.PopupWindow;
|
||||||
import com.arialyy.aria.core.scheduler.OnSchedulerListener;
|
import com.arialyy.aria.core.scheduler.OnSchedulerListener;
|
||||||
import com.arialyy.aria.core.task.Task;
|
import com.arialyy.aria.core.task.Task;
|
||||||
|
import com.arialyy.aria.util.CheckUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lyy on 2016/12/1.
|
* Created by lyy on 2016/12/1.
|
||||||
@ -98,12 +99,12 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
private Aria() {
|
private Aria() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接受Activity、Service、Application
|
* 接受Activity、Service、Application
|
||||||
*/
|
*/
|
||||||
public static AMReceiver whit(Context context) {
|
public static AMReceiver whit(Context context) {
|
||||||
//if (context == null) throw new IllegalArgumentException("context 不能为 null");
|
CheckUtil.checkNull(context);
|
||||||
checkNull(context);
|
|
||||||
if (context instanceof Activity
|
if (context instanceof Activity
|
||||||
|| context instanceof Service
|
|| context instanceof Service
|
||||||
|| context instanceof Application) {
|
|| context instanceof Application) {
|
||||||
@ -117,7 +118,7 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
* 处理Fragment
|
* 处理Fragment
|
||||||
*/
|
*/
|
||||||
public static AMReceiver whit(Fragment fragment) {
|
public static AMReceiver whit(Fragment fragment) {
|
||||||
checkNull(fragment);
|
CheckUtil.checkNull(fragment);
|
||||||
return AriaManager.getInstance(
|
return AriaManager.getInstance(
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
|
||||||
: fragment.getActivity()).get(fragment);
|
: fragment.getActivity()).get(fragment);
|
||||||
@ -127,7 +128,7 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
* 处理Fragment
|
* 处理Fragment
|
||||||
*/
|
*/
|
||||||
public static AMReceiver whit(android.support.v4.app.Fragment fragment) {
|
public static AMReceiver whit(android.support.v4.app.Fragment fragment) {
|
||||||
checkNull(fragment);
|
CheckUtil.checkNull(fragment);
|
||||||
return AriaManager.getInstance(
|
return AriaManager.getInstance(
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
|
||||||
: fragment.getActivity()).get(fragment);
|
: fragment.getActivity()).get(fragment);
|
||||||
@ -137,7 +138,7 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
* 处理Fragment、或者DialogFragment
|
* 处理Fragment、或者DialogFragment
|
||||||
*/
|
*/
|
||||||
public static AMReceiver whit(DialogFragment dialog) {
|
public static AMReceiver whit(DialogFragment dialog) {
|
||||||
checkNull(dialog);
|
CheckUtil.checkNull(dialog);
|
||||||
return AriaManager.getInstance(
|
return AriaManager.getInstance(
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? dialog.getContext() : dialog.getActivity())
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? dialog.getContext() : dialog.getActivity())
|
||||||
.get(dialog);
|
.get(dialog);
|
||||||
@ -147,7 +148,7 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
* 处理popupwindow
|
* 处理popupwindow
|
||||||
*/
|
*/
|
||||||
public static AMReceiver whit(PopupWindow popupWindow) {
|
public static AMReceiver whit(PopupWindow popupWindow) {
|
||||||
checkNull(popupWindow);
|
CheckUtil.checkNull(popupWindow);
|
||||||
return AriaManager.getInstance(popupWindow.getContentView().getContext()).get(popupWindow);
|
return AriaManager.getInstance(popupWindow.getContentView().getContext()).get(popupWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +156,7 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
* 处理Dialog
|
* 处理Dialog
|
||||||
*/
|
*/
|
||||||
public static AMReceiver whit(Dialog dialog) {
|
public static AMReceiver whit(Dialog dialog) {
|
||||||
checkNull(dialog);
|
CheckUtil.checkNull(dialog);
|
||||||
return AriaManager.getInstance(dialog.getContext()).get(dialog);
|
return AriaManager.getInstance(dialog.getContext()).get(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +178,7 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
* 处理Dialog的通用任务
|
* 处理Dialog的通用任务
|
||||||
*/
|
*/
|
||||||
public static AriaManager get(Dialog dialog) {
|
public static AriaManager get(Dialog dialog) {
|
||||||
checkNull(dialog);
|
CheckUtil.checkNull(dialog);
|
||||||
return AriaManager.getInstance(dialog.getContext());
|
return AriaManager.getInstance(dialog.getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +186,7 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
* 处理Dialog的通用任务
|
* 处理Dialog的通用任务
|
||||||
*/
|
*/
|
||||||
public static AriaManager get(PopupWindow popupWindow) {
|
public static AriaManager get(PopupWindow popupWindow) {
|
||||||
checkNull(popupWindow);
|
CheckUtil.checkNull(popupWindow);
|
||||||
return AriaManager.getInstance(popupWindow.getContentView().getContext());
|
return AriaManager.getInstance(popupWindow.getContentView().getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +194,7 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
* 处理Fragment的通用任务
|
* 处理Fragment的通用任务
|
||||||
*/
|
*/
|
||||||
public static AriaManager get(Fragment fragment) {
|
public static AriaManager get(Fragment fragment) {
|
||||||
checkNull(fragment);
|
CheckUtil.checkNull(fragment);
|
||||||
return AriaManager.getInstance(
|
return AriaManager.getInstance(
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
|
||||||
: fragment.getActivity());
|
: fragment.getActivity());
|
||||||
@ -203,16 +204,12 @@ import com.arialyy.aria.core.task.Task;
|
|||||||
* 处理Fragment的通用任务
|
* 处理Fragment的通用任务
|
||||||
*/
|
*/
|
||||||
public static AriaManager get(android.support.v4.app.Fragment fragment) {
|
public static AriaManager get(android.support.v4.app.Fragment fragment) {
|
||||||
checkNull(fragment);
|
CheckUtil.checkNull(fragment);
|
||||||
return AriaManager.getInstance(
|
return AriaManager.getInstance(
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
|
||||||
: fragment.getActivity());
|
: fragment.getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkNull(Object obj) {
|
|
||||||
if (obj == null) throw new IllegalArgumentException("不能传入空对象");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SimpleSchedulerListener implements OnSchedulerListener {
|
public static class SimpleSchedulerListener implements OnSchedulerListener {
|
||||||
|
|
||||||
@Override public void onTaskPre(Task task) {
|
@Override public void onTaskPre(Task task) {
|
||||||
|
@ -30,6 +30,7 @@ import android.text.TextUtils;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.PopupWindow;
|
import android.widget.PopupWindow;
|
||||||
import com.arialyy.aria.core.command.CmdFactory;
|
import com.arialyy.aria.core.command.CmdFactory;
|
||||||
|
import com.arialyy.aria.util.CAConfiguration;
|
||||||
import com.arialyy.aria.util.CheckUtil;
|
import com.arialyy.aria.util.CheckUtil;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
import com.arialyy.aria.core.command.IDownloadCmd;
|
import com.arialyy.aria.core.command.IDownloadCmd;
|
||||||
@ -73,6 +74,24 @@ import java.util.Set;
|
|||||||
return getTarget(obj);
|
return getTarget(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置CA证书信息
|
||||||
|
*
|
||||||
|
* @param caAlias ca证书别名
|
||||||
|
* @param caPath assets 文件夹下的ca证书完整路径
|
||||||
|
*/
|
||||||
|
public void setCAInfo(String caAlias, String caPath) {
|
||||||
|
if (TextUtils.isEmpty(caAlias)) {
|
||||||
|
Log.e(TAG, "ca证书别名不能为null");
|
||||||
|
return;
|
||||||
|
} else if (TextUtils.isEmpty(caPath)) {
|
||||||
|
Log.e(TAG, "ca证书路径不能为null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CAConfiguration.CA_ALIAS = caAlias;
|
||||||
|
CAConfiguration.CA_PATH = caPath;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取下载列表
|
* 获取下载列表
|
||||||
*/
|
*/
|
||||||
@ -198,8 +217,15 @@ import java.util.Set;
|
|||||||
key = clsName;
|
key = clsName;
|
||||||
}
|
}
|
||||||
handlePopupWindowLift((PopupWindow) obj);
|
handlePopupWindowLift((PopupWindow) obj);
|
||||||
|
} else if (obj instanceof Service) {
|
||||||
|
key = clsName;
|
||||||
|
} else if (obj instanceof Application) {
|
||||||
|
key = clsName;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
if (obj instanceof Activity || obj instanceof Service) {
|
||||||
|
key = clsName;
|
||||||
|
} else if (obj instanceof Application) {
|
||||||
key = clsName;
|
key = clsName;
|
||||||
}
|
}
|
||||||
if (TextUtils.isEmpty(key)) {
|
if (TextUtils.isEmpty(key)) {
|
||||||
|
16
Aria/src/main/java/com/arialyy/aria/core/RequestEnum.java
Normal file
16
Aria/src/main/java/com/arialyy/aria/core/RequestEnum.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package com.arialyy.aria.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/1/23.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum RequestEnum {
|
||||||
|
GET("GET"), POST("POST");
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
RequestEnum(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
Aria/src/main/java/com/arialyy/aria/core/TaskEntity.java
Normal file
10
Aria/src/main/java/com/arialyy/aria/core/TaskEntity.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package com.arialyy.aria.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/1/23.
|
||||||
|
* 任务实体
|
||||||
|
*/
|
||||||
|
public class TaskEntity {
|
||||||
|
public DownloadEntity downloadEntity;
|
||||||
|
public RequestEnum requestEnum = RequestEnum.GET;
|
||||||
|
}
|
@ -89,21 +89,15 @@ public class DownloadTaskQueue implements ITaskQueue {
|
|||||||
|
|
||||||
@Override public void stopTask(Task task) {
|
@Override public void stopTask(Task task) {
|
||||||
if (!task.isDownloading()) Log.w(TAG, "停止任务失败,【任务已经停止】");
|
if (!task.isDownloading()) Log.w(TAG, "停止任务失败,【任务已经停止】");
|
||||||
|
if (mExecutePool.removeTask(task)) {
|
||||||
task.stop();
|
task.stop();
|
||||||
//if (task.isDownloading()) {
|
} else {
|
||||||
// if (mExecutePool.removeTask(task)) {
|
task.stop();
|
||||||
// task.stop();
|
Log.w(TAG, "停止任务失败,【任务已经停止】");
|
||||||
// }
|
}
|
||||||
//} else {
|
|
||||||
// task.stop();
|
|
||||||
// Log.w(TAG, "停止任务失败,【任务已经停止】");
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void cancelTask(Task task) {
|
@Override public void cancelTask(Task task) {
|
||||||
//if (mExecutePool.removeTask(task) || mCachePool.removeTask(task)) {
|
|
||||||
// task.cancel();
|
|
||||||
//}
|
|
||||||
task.cancel();
|
task.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,10 +113,6 @@ public class DownloadTaskQueue implements ITaskQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Override public IDownloadSchedulers getDownloadSchedulers() {
|
|
||||||
// return mSchedulers;
|
|
||||||
//}
|
|
||||||
|
|
||||||
@Override public int size() {
|
@Override public int size() {
|
||||||
return mExecutePool.size();
|
return mExecutePool.size();
|
||||||
}
|
}
|
||||||
@ -159,12 +149,10 @@ public class DownloadTaskQueue implements ITaskQueue {
|
|||||||
@Override public Task createTask(String target, DownloadEntity entity) {
|
@Override public Task createTask(String target, DownloadEntity entity) {
|
||||||
Task task;
|
Task task;
|
||||||
if (TextUtils.isEmpty(target)) {
|
if (TextUtils.isEmpty(target)) {
|
||||||
//task = TaskFactory.getInstance().createTask(mContext, entity, mSchedulers);
|
|
||||||
task =
|
task =
|
||||||
TaskFactory.getInstance().createTask(mContext, entity, DownloadSchedulers.getInstance());
|
TaskFactory.getInstance().createTask(mContext, entity, DownloadSchedulers.getInstance());
|
||||||
} else {
|
} else {
|
||||||
task = TaskFactory.getInstance()
|
task = TaskFactory.getInstance()
|
||||||
//.createTask(target.getClass().getName(), mContext, entity, mSchedulers);
|
|
||||||
.createTask(target, mContext, entity, DownloadSchedulers.getInstance());
|
.createTask(target, mContext, entity, DownloadSchedulers.getInstance());
|
||||||
}
|
}
|
||||||
mCachePool.putTask(task);
|
mCachePool.putTask(task);
|
||||||
@ -183,13 +171,10 @@ public class DownloadTaskQueue implements ITaskQueue {
|
|||||||
Task task = mExecutePool.getTask(entity.getDownloadUrl());
|
Task task = mExecutePool.getTask(entity.getDownloadUrl());
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
|
Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
|
||||||
} else {
|
|
||||||
task = mCachePool.getTask(entity.getDownloadUrl());
|
|
||||||
}
|
}
|
||||||
|
task = mCachePool.getTask(entity.getDownloadUrl());
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
Log.d(TAG, "从缓存池删除任务,删除" + (mCachePool.removeTask(task) ? "成功" : "失败"));
|
Log.d(TAG, "从缓存池删除任务,删除" + (mCachePool.removeTask(task) ? "成功" : "失败"));
|
||||||
} else {
|
|
||||||
Log.w(TAG, "没有找到下载链接为【" + entity.getDownloadUrl() + "】的任务");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,29 +182,15 @@ public class DownloadTaskQueue implements ITaskQueue {
|
|||||||
return mCachePool.pollTask();
|
return mCachePool.pollTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Override public void setScheduler(IDownloadSchedulers schedulers) {
|
|
||||||
// mSchedulers = schedulers;
|
|
||||||
//}
|
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
Context context;
|
Context context;
|
||||||
IDownloadSchedulers schedulers;
|
|
||||||
|
|
||||||
public Builder(Context context) {
|
public Builder(Context context) {
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
//public Builder setDownloadSchedulers(IDownloadSchedulers schedulers) {
|
|
||||||
// this.schedulers = schedulers;
|
|
||||||
// return this;
|
|
||||||
//}
|
|
||||||
|
|
||||||
public DownloadTaskQueue build() {
|
public DownloadTaskQueue build() {
|
||||||
DownloadTaskQueue queue = new DownloadTaskQueue(context);
|
DownloadTaskQueue queue = new DownloadTaskQueue(context);
|
||||||
//if (schedulers == null) {
|
|
||||||
// schedulers = DownloadSchedulers.getInstance();
|
|
||||||
//}
|
|
||||||
//queue.setScheduler(schedulers);
|
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,11 +73,4 @@ public interface ITaskQueue extends IDownloader {
|
|||||||
* @return 下载任务 or null
|
* @return 下载任务 or null
|
||||||
*/
|
*/
|
||||||
public Task getNextTask();
|
public Task getNextTask();
|
||||||
|
|
||||||
///**
|
|
||||||
// * 设置下载调度器
|
|
||||||
// *
|
|
||||||
// * @param schedulers 下载调度器{@link IDownloadSchedulers}
|
|
||||||
// */
|
|
||||||
//public void setScheduler(IDownloadSchedulers schedulers);
|
|
||||||
}
|
}
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.arialyy.aria.core.scheduler;
|
package com.arialyy.aria.core.scheduler;
|
||||||
|
|
||||||
|
import android.os.CountDownTimer;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -120,16 +121,16 @@ public class DownloadSchedulers implements IDownloadSchedulers {
|
|||||||
case STOP:
|
case STOP:
|
||||||
case CANCEL:
|
case CANCEL:
|
||||||
mQueue.removeTask(entity);
|
mQueue.removeTask(entity);
|
||||||
mQueue.removeTask(entity);
|
if (mQueue.size() < Configuration.getInstance().getDownloadNum()) {
|
||||||
if (mQueue.size() != Configuration.getInstance().getDownloadNum()) {
|
|
||||||
startNextTask(entity);
|
startNextTask(entity);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMPLETE:
|
case COMPLETE:
|
||||||
|
mQueue.removeTask(entity);
|
||||||
startNextTask(entity);
|
startNextTask(entity);
|
||||||
break;
|
break;
|
||||||
case FAIL:
|
case FAIL:
|
||||||
handleFailTask(entity);
|
handleFailTask(task);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -154,10 +155,8 @@ public class DownloadSchedulers implements IDownloadSchedulers {
|
|||||||
|
|
||||||
private void callback(int state, Task task, OnSchedulerListener listener) {
|
private void callback(int state, Task task, OnSchedulerListener listener) {
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
//Task task = mQueue.getTask(entity);
|
|
||||||
if (task == null) {
|
if (task == null) {
|
||||||
//Log.e(TAG, "队列中没有下载链接【" + entity.getDownloadUrl() + "】的任务");
|
Log.e(TAG, "TASK 为null,回调失败");
|
||||||
Log.e(TAG, "传递的下载任务");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@ -192,12 +191,17 @@ public class DownloadSchedulers implements IDownloadSchedulers {
|
|||||||
/**
|
/**
|
||||||
* 处理下载任务下载失败的情形
|
* 处理下载任务下载失败的情形
|
||||||
*
|
*
|
||||||
* @param entity 失败实体
|
* @param task 下载任务
|
||||||
*/
|
*/
|
||||||
@Override public void handleFailTask(final DownloadEntity entity) {
|
@Override public void handleFailTask(final Task task) {
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override public void run() {
|
|
||||||
final Configuration config = Configuration.getInstance();
|
final Configuration config = Configuration.getInstance();
|
||||||
|
CountDownTimer timer = new CountDownTimer(config.getReTryInterval(), 1000) {
|
||||||
|
@Override public void onTick(long millisUntilFinished) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFinish() {
|
||||||
|
DownloadEntity entity = task.getDownloadEntity();
|
||||||
if (entity.getFailNum() <= config.getReTryNum()) {
|
if (entity.getFailNum() <= config.getReTryNum()) {
|
||||||
Task task = mQueue.getTask(entity);
|
Task task = mQueue.getTask(entity);
|
||||||
mQueue.reTryStart(task);
|
mQueue.reTryStart(task);
|
||||||
@ -207,10 +211,12 @@ public class DownloadSchedulers implements IDownloadSchedulers {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
mQueue.removeTask(entity);
|
||||||
startNextTask(entity);
|
startNextTask(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
};
|
||||||
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,7 +225,6 @@ public class DownloadSchedulers implements IDownloadSchedulers {
|
|||||||
* @param entity 通过Handler传递的下载实体
|
* @param entity 通过Handler传递的下载实体
|
||||||
*/
|
*/
|
||||||
@Override public void startNextTask(DownloadEntity entity) {
|
@Override public void startNextTask(DownloadEntity entity) {
|
||||||
mQueue.removeTask(entity);
|
|
||||||
Task newTask = mQueue.getNextTask();
|
Task newTask = mQueue.getNextTask();
|
||||||
if (newTask == null) {
|
if (newTask == null) {
|
||||||
Log.w(TAG, "没有下一任务");
|
Log.w(TAG, "没有下一任务");
|
||||||
|
@ -18,6 +18,7 @@ package com.arialyy.aria.core.scheduler;
|
|||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import com.arialyy.aria.core.DownloadEntity;
|
import com.arialyy.aria.core.DownloadEntity;
|
||||||
|
import com.arialyy.aria.core.task.Task;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by “AriaLyy@outlook.com” on 2016/11/2.
|
* Created by “AriaLyy@outlook.com” on 2016/11/2.
|
||||||
@ -42,9 +43,9 @@ public interface IDownloadSchedulers extends Handler.Callback {
|
|||||||
/**
|
/**
|
||||||
* 处理下载任务下载失败的情形
|
* 处理下载任务下载失败的情形
|
||||||
*
|
*
|
||||||
* @param entity 下载实体
|
* @param task 下载任务
|
||||||
*/
|
*/
|
||||||
public void handleFailTask(DownloadEntity entity);
|
public void handleFailTask(Task task);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动下一个任务,条件:任务停止,取消下载,任务完成
|
* 启动下一个任务,条件:任务停止,取消下载,任务完成
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.aria.core.task;
|
||||||
|
|
||||||
|
import com.arialyy.aria.util.CAConfiguration;
|
||||||
|
import com.arialyy.aria.util.SSLContextUtil;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.ProtocolException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2017/1/18.
|
||||||
|
* 链接帮助类
|
||||||
|
*/
|
||||||
|
class ConnectionHelp {
|
||||||
|
/**
|
||||||
|
* 处理链接
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
static HttpURLConnection handleConnection(URL url) throws IOException {
|
||||||
|
HttpURLConnection conn;
|
||||||
|
URLConnection urlConn = url.openConnection();
|
||||||
|
if (urlConn instanceof HttpsURLConnection) {
|
||||||
|
conn = (HttpsURLConnection) urlConn;
|
||||||
|
SSLContext sslContext =
|
||||||
|
SSLContextUtil.getSSLContext(CAConfiguration.CA_ALIAS, CAConfiguration.CA_ALIAS);
|
||||||
|
if (sslContext == null) {
|
||||||
|
sslContext = SSLContextUtil.getDefaultSLLContext();
|
||||||
|
}
|
||||||
|
SSLSocketFactory ssf = sslContext.getSocketFactory();
|
||||||
|
((HttpsURLConnection) conn).setSSLSocketFactory(ssf);
|
||||||
|
((HttpsURLConnection) conn).setHostnameVerifier(SSLContextUtil.HOSTNAME_VERIFIER);
|
||||||
|
} else {
|
||||||
|
conn = (HttpURLConnection) urlConn;
|
||||||
|
}
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置头部参数
|
||||||
|
*
|
||||||
|
* @throws ProtocolException
|
||||||
|
*/
|
||||||
|
static HttpURLConnection setConnectParam(HttpURLConnection conn) throws ProtocolException {
|
||||||
|
conn.setRequestMethod("GET");
|
||||||
|
conn.setRequestProperty("Charset", "UTF-8");
|
||||||
|
conn.setRequestProperty("User-Agent",
|
||||||
|
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
|
||||||
|
conn.setRequestProperty("Accept",
|
||||||
|
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
|
||||||
|
////用于处理Disconnect 不起作用问题
|
||||||
|
//conn.setRequestProperty("Connection", "close");
|
||||||
|
conn.setRequestProperty("Connection", "Keep-Alive");
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
}
|
@ -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.aria.core.task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2017/1/18.
|
||||||
|
* 下载状态常量
|
||||||
|
*/
|
||||||
|
final class DownloadStateConstance {
|
||||||
|
int CANCEL_NUM = 0;
|
||||||
|
int STOP_NUM = 0;
|
||||||
|
int FAIL_NUM = 0;
|
||||||
|
int CONNECT_TIME_OUT = 5000 * 4; //连接超时时间
|
||||||
|
int READ_TIME_OUT = 1000 * 20; //流读取的超时时间
|
||||||
|
int COMPLETE_THREAD_NUM = 0;
|
||||||
|
int THREAD_NUM = 3;
|
||||||
|
long CURRENT_LOCATION = 0;
|
||||||
|
boolean isDownloading = false;
|
||||||
|
boolean isCancel = false;
|
||||||
|
boolean isStop = false;
|
||||||
|
|
||||||
|
DownloadStateConstance(int num) {
|
||||||
|
THREAD_NUM = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanState() {
|
||||||
|
isCancel = false;
|
||||||
|
isStop = false;
|
||||||
|
isDownloading = true;
|
||||||
|
CURRENT_LOCATION = 0;
|
||||||
|
CANCEL_NUM = 0;
|
||||||
|
STOP_NUM = 0;
|
||||||
|
FAIL_NUM = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有子线程是否都已经停止下载
|
||||||
|
*/
|
||||||
|
boolean isStop() {
|
||||||
|
return STOP_NUM == THREAD_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有子线程是否都已经下载失败
|
||||||
|
*/
|
||||||
|
boolean isFail() {
|
||||||
|
return FAIL_NUM == THREAD_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有子线程是否都已经完成下载
|
||||||
|
*/
|
||||||
|
boolean isComplete() {
|
||||||
|
return COMPLETE_THREAD_NUM == THREAD_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有子线程是否都已经取消下载
|
||||||
|
*/
|
||||||
|
boolean isCancel() {
|
||||||
|
return CANCEL_NUM == THREAD_NUM;
|
||||||
|
}
|
||||||
|
}
|
@ -20,14 +20,12 @@ import android.content.Context;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import com.arialyy.aria.core.DownloadEntity;
|
import com.arialyy.aria.core.DownloadEntity;
|
||||||
|
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.ProtocolException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@ -37,9 +35,8 @@ import java.util.concurrent.Executors;
|
|||||||
* Created by lyy on 2015/8/25.
|
* Created by lyy on 2015/8/25.
|
||||||
* 下载工具类
|
* 下载工具类
|
||||||
*/
|
*/
|
||||||
final class DownloadUtil implements IDownloadUtil, Runnable {
|
public class DownloadUtil implements IDownloadUtil, Runnable {
|
||||||
private static final String TAG = "DownloadUtil";
|
private static final String TAG = "DownloadUtil";
|
||||||
private static final Object LOCK = new Object();
|
|
||||||
/**
|
/**
|
||||||
* 线程数
|
* 线程数
|
||||||
*/
|
*/
|
||||||
@ -48,27 +45,17 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
private IDownloadListener mListener;
|
private IDownloadListener mListener;
|
||||||
private int mConnectTimeOut = 5000 * 4; //连接超时时间
|
private int mConnectTimeOut = 5000 * 4; //连接超时时间
|
||||||
private int mReadTimeOut = 5000 * 20; //流读取的超时时间
|
private int mReadTimeOut = 5000 * 20; //流读取的超时时间
|
||||||
/**
|
|
||||||
* 已经完成下载任务的线程数量
|
|
||||||
*/
|
|
||||||
private boolean isDownloading = false;
|
|
||||||
private boolean isStop = false;
|
|
||||||
private boolean isCancel = false;
|
|
||||||
private boolean isNewTask = true;
|
private boolean isNewTask = true;
|
||||||
private boolean isSupportBreakpoint = true;
|
private boolean isSupportBreakpoint = true;
|
||||||
private int mCompleteThreadNum = 0;
|
|
||||||
private int mCancelNum = 0;
|
|
||||||
private long mCurrentLocation = 0;
|
|
||||||
private int mStopNum = 0;
|
|
||||||
private int mFailNum = 0;
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private DownloadEntity mDownloadEntity;
|
private DownloadEntity mDownloadEntity;
|
||||||
private ExecutorService mFixedThreadPool;
|
private ExecutorService mFixedThreadPool;
|
||||||
private File mDownloadFile; //下载的文件
|
private File mDownloadFile; //下载的文件
|
||||||
private File mConfigFile;//下载信息配置文件
|
private File mConfigFile;//下载信息配置文件
|
||||||
private SparseArray<Runnable> mTask = new SparseArray<>();
|
private SparseArray<Runnable> mTask = new SparseArray<>();
|
||||||
|
private DownloadStateConstance mConstance;
|
||||||
|
|
||||||
DownloadUtil(Context context, DownloadEntity entity, IDownloadListener downloadListener) {
|
public DownloadUtil(Context context, DownloadEntity entity, IDownloadListener downloadListener) {
|
||||||
this(context, entity, downloadListener, 3);
|
this(context, entity, downloadListener, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +66,7 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
mListener = downloadListener;
|
mListener = downloadListener;
|
||||||
THREAD_NUM = threadNum;
|
THREAD_NUM = threadNum;
|
||||||
mFixedThreadPool = Executors.newFixedThreadPool(Integer.MAX_VALUE);
|
mFixedThreadPool = Executors.newFixedThreadPool(Integer.MAX_VALUE);
|
||||||
|
mConstance = new DownloadStateConstance(THREAD_NUM);
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,19 +110,19 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
* 获取当前下载位置
|
* 获取当前下载位置
|
||||||
*/
|
*/
|
||||||
@Override public long getCurrentLocation() {
|
@Override public long getCurrentLocation() {
|
||||||
return mCurrentLocation;
|
return mConstance.CURRENT_LOCATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean isDownloading() {
|
@Override public boolean isDownloading() {
|
||||||
return isDownloading;
|
return mConstance.isDownloading;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消下载
|
* 取消下载
|
||||||
*/
|
*/
|
||||||
@Override public void cancelDownload() {
|
@Override public void cancelDownload() {
|
||||||
isCancel = true;
|
mConstance.isCancel = true;
|
||||||
isDownloading = false;
|
mConstance.isDownloading = false;
|
||||||
mFixedThreadPool.shutdown();
|
mFixedThreadPool.shutdown();
|
||||||
for (int i = 0; i < THREAD_NUM; i++) {
|
for (int i = 0; i < THREAD_NUM; i++) {
|
||||||
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
|
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
|
||||||
@ -148,8 +136,8 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
* 停止下载
|
* 停止下载
|
||||||
*/
|
*/
|
||||||
@Override public void stopDownload() {
|
@Override public void stopDownload() {
|
||||||
isStop = true;
|
mConstance.isStop = true;
|
||||||
isDownloading = false;
|
mConstance.isDownloading = false;
|
||||||
mFixedThreadPool.shutdown();
|
mFixedThreadPool.shutdown();
|
||||||
for (int i = 0; i < THREAD_NUM; i++) {
|
for (int i = 0; i < THREAD_NUM; i++) {
|
||||||
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
|
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
|
||||||
@ -189,13 +177,7 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
* 多线程断点续传下载文件,开始下载
|
* 多线程断点续传下载文件,开始下载
|
||||||
*/
|
*/
|
||||||
@Override public void startDownload() {
|
@Override public void startDownload() {
|
||||||
isDownloading = true;
|
mConstance.cleanState();
|
||||||
mCurrentLocation = 0;
|
|
||||||
isStop = false;
|
|
||||||
isCancel = false;
|
|
||||||
mCancelNum = 0;
|
|
||||||
mStopNum = 0;
|
|
||||||
mFailNum = 0;
|
|
||||||
mListener.onPre();
|
mListener.onPre();
|
||||||
new Thread(this).start();
|
new Thread(this).start();
|
||||||
}
|
}
|
||||||
@ -206,25 +188,16 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
|
|
||||||
private void failDownload(String msg) {
|
private void failDownload(String msg) {
|
||||||
Log.e(TAG, msg);
|
Log.e(TAG, msg);
|
||||||
isDownloading = false;
|
mConstance.isDownloading = false;
|
||||||
stopDownload();
|
stopDownload();
|
||||||
mListener.onFail();
|
mListener.onFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setConnectParam(HttpURLConnection conn) throws ProtocolException {
|
|
||||||
conn.setRequestMethod("GET");
|
|
||||||
conn.setRequestProperty("Charset", "UTF-8");
|
|
||||||
conn.setRequestProperty("User-Agent",
|
|
||||||
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
|
|
||||||
conn.setRequestProperty("Accept",
|
|
||||||
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
try {
|
try {
|
||||||
URL url = new URL(mDownloadEntity.getDownloadUrl());
|
URL url = new URL(mDownloadEntity.getDownloadUrl());
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = ConnectionHelp.handleConnection(url);
|
||||||
setConnectParam(conn);
|
conn = ConnectionHelp.setConnectParam(conn);
|
||||||
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
|
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
|
||||||
conn.setConnectTimeout(mConnectTimeOut * 4);
|
conn.setConnectTimeout(mConnectTimeOut * 4);
|
||||||
conn.connect();
|
conn.connect();
|
||||||
@ -242,12 +215,16 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
handleBreakpoint(conn);
|
handleBreakpoint(conn);
|
||||||
} else if (code == HttpURLConnection.HTTP_OK || len < 0) {
|
} else if (code == HttpURLConnection.HTTP_OK || len < 0) {
|
||||||
//在conn.setRequestProperty("Range", "bytes=" + 0 + "-");下,200为不支持断点状态
|
//在conn.setRequestProperty("Range", "bytes=" + 0 + "-");下,200为不支持断点状态
|
||||||
|
if (len < 0) {
|
||||||
|
failDownload("任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,文件长度小于0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
isSupportBreakpoint = false;
|
isSupportBreakpoint = false;
|
||||||
mListener.supportBreakpoint(false);
|
mListener.supportBreakpoint(false);
|
||||||
Log.w(TAG, "该下载链接不支持断点下载");
|
Log.w(TAG, "该下载链接不支持断点下载");
|
||||||
handleBreakpoint(conn);
|
handleBreakpoint(conn);
|
||||||
} else {
|
} else {
|
||||||
failDownload("下载失败,返回码:" + code);
|
failDownload("任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,返回码:" + code);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
failDownload("下载失败【downloadUrl:"
|
failDownload("下载失败【downloadUrl:"
|
||||||
@ -263,16 +240,19 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
* 处理断点
|
* 处理断点
|
||||||
*/
|
*/
|
||||||
private void handleBreakpoint(HttpURLConnection conn) throws IOException {
|
private void handleBreakpoint(HttpURLConnection conn) throws IOException {
|
||||||
|
|
||||||
//不支持断点只能单线程下载
|
//不支持断点只能单线程下载
|
||||||
if (!isSupportBreakpoint) {
|
if (!isSupportBreakpoint) {
|
||||||
ConfigEntity entity = new ConfigEntity();
|
ConfigEntity entity = new ConfigEntity();
|
||||||
entity.fileSize = conn.getContentLength();
|
entity.FILE_SIZE = conn.getContentLength();
|
||||||
entity.downloadUrl = mDownloadEntity.getDownloadUrl();
|
entity.DOWNLOAD_URL = mDownloadEntity.getDownloadUrl();
|
||||||
entity.tempFile = mDownloadFile;
|
entity.TEMP_FILE = mDownloadFile;
|
||||||
entity.threadId = 0;
|
entity.THREAD_ID = 0;
|
||||||
entity.startLocation = 0;
|
entity.START_LOCATION = 0;
|
||||||
entity.endLocation = entity.fileSize;
|
entity.END_LOCATION = entity.FILE_SIZE;
|
||||||
SingleThreadTask task = new SingleThreadTask(entity);
|
entity.CONFIG_FILE_PATH = mConfigFile.getPath();
|
||||||
|
entity.isSupportBreakpoint = isSupportBreakpoint;
|
||||||
|
SingleThreadTask task = new SingleThreadTask(mConstance, mListener, entity);
|
||||||
mFixedThreadPool.execute(task);
|
mFixedThreadPool.execute(task);
|
||||||
mListener.onStart(0);
|
mListener.onStart(0);
|
||||||
return;
|
return;
|
||||||
@ -280,7 +260,10 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
int fileLength = conn.getContentLength();
|
int fileLength = conn.getContentLength();
|
||||||
//必须建一个文件
|
//必须建一个文件
|
||||||
CommonUtil.createFile(mDownloadFile.getPath());
|
CommonUtil.createFile(mDownloadFile.getPath());
|
||||||
RandomAccessFile file = new RandomAccessFile(mDownloadFile.getPath(), "rwd");
|
//RandomAccessFile file = new RandomAccessFile(mDownloadFile.getPath(), "rwd");
|
||||||
|
////设置文件长度
|
||||||
|
//file.setLength(fileLength);
|
||||||
|
BufferedRandomAccessFile file = new BufferedRandomAccessFile(mDownloadFile.getPath(), "rwd", 8192);
|
||||||
//设置文件长度
|
//设置文件长度
|
||||||
file.setLength(fileLength);
|
file.setLength(fileLength);
|
||||||
mListener.onPostPre(fileLength);
|
mListener.onPostPre(fileLength);
|
||||||
@ -311,17 +294,17 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
long startL = i * blockSize, endL = (i + 1) * blockSize;
|
long startL = i * blockSize, endL = (i + 1) * blockSize;
|
||||||
Object state = pro.getProperty(mDownloadFile.getName() + "_state_" + i);
|
Object state = pro.getProperty(mDownloadFile.getName() + "_state_" + i);
|
||||||
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
|
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
|
||||||
mCurrentLocation += endL - startL;
|
mConstance.CURRENT_LOCATION += endL - startL;
|
||||||
Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
|
Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
|
||||||
mCompleteThreadNum++;
|
mConstance.COMPLETE_THREAD_NUM++;
|
||||||
mStopNum++;
|
mConstance.STOP_NUM++;
|
||||||
mCancelNum++;
|
mConstance.CANCEL_NUM++;
|
||||||
if (mCompleteThreadNum == THREAD_NUM) {
|
if (mConstance.isComplete()) {
|
||||||
if (mConfigFile.exists()) {
|
if (mConfigFile.exists()) {
|
||||||
mConfigFile.delete();
|
mConfigFile.delete();
|
||||||
}
|
}
|
||||||
mListener.onComplete();
|
mListener.onComplete();
|
||||||
isDownloading = false;
|
mConstance.isDownloading = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -331,7 +314,7 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
//如果有记录,则恢复下载
|
//如果有记录,则恢复下载
|
||||||
if (!isNewTask && record != null && Long.parseLong(record + "") > 0) {
|
if (!isNewTask && record != null && Long.parseLong(record + "") > 0) {
|
||||||
Long r = Long.parseLong(record + "");
|
Long r = Long.parseLong(record + "");
|
||||||
mCurrentLocation += r - startL;
|
mConstance.CURRENT_LOCATION += r - startL;
|
||||||
Log.d(TAG, "++++++++++ 线程_" + i + "_恢复下载 ++++++++++");
|
Log.d(TAG, "++++++++++ 线程_" + i + "_恢复下载 ++++++++++");
|
||||||
mListener.onChildResume(r);
|
mListener.onChildResume(r);
|
||||||
startL = r;
|
startL = r;
|
||||||
@ -349,19 +332,21 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
endL = fileLength;
|
endL = fileLength;
|
||||||
}
|
}
|
||||||
ConfigEntity entity = new ConfigEntity();
|
ConfigEntity entity = new ConfigEntity();
|
||||||
entity.fileSize = fileLength;
|
entity.FILE_SIZE = fileLength;
|
||||||
entity.downloadUrl = mDownloadEntity.getDownloadUrl();
|
entity.DOWNLOAD_URL = mDownloadEntity.getDownloadUrl();
|
||||||
entity.tempFile = mDownloadFile;
|
entity.TEMP_FILE = mDownloadFile;
|
||||||
entity.threadId = i;
|
entity.THREAD_ID = i;
|
||||||
entity.startLocation = startL;
|
entity.START_LOCATION = startL;
|
||||||
entity.endLocation = endL;
|
entity.END_LOCATION = endL;
|
||||||
SingleThreadTask task = new SingleThreadTask(entity);
|
entity.CONFIG_FILE_PATH = mConfigFile.getPath();
|
||||||
|
entity.isSupportBreakpoint = isSupportBreakpoint;
|
||||||
|
SingleThreadTask task = new SingleThreadTask(mConstance, mListener, entity);
|
||||||
mTask.put(i, task);
|
mTask.put(i, task);
|
||||||
}
|
}
|
||||||
if (mCurrentLocation > 0) {
|
if (mConstance.CURRENT_LOCATION > 0) {
|
||||||
mListener.onResume(mCurrentLocation);
|
mListener.onResume(mConstance.CURRENT_LOCATION);
|
||||||
} else {
|
} else {
|
||||||
mListener.onStart(mCurrentLocation);
|
mListener.onStart(mConstance.CURRENT_LOCATION);
|
||||||
}
|
}
|
||||||
for (int l : recordL) {
|
for (int l : recordL) {
|
||||||
if (l == -1) continue;
|
if (l == -1) continue;
|
||||||
@ -375,228 +360,15 @@ final class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
/**
|
/**
|
||||||
* 子线程下载信息类
|
* 子线程下载信息类
|
||||||
*/
|
*/
|
||||||
private static class ConfigEntity {
|
final static class ConfigEntity {
|
||||||
//文件大小
|
//文件大小
|
||||||
long fileSize;
|
long FILE_SIZE;
|
||||||
String downloadUrl;
|
String DOWNLOAD_URL;
|
||||||
int threadId;
|
int THREAD_ID;
|
||||||
long startLocation;
|
long START_LOCATION;
|
||||||
long endLocation;
|
long END_LOCATION;
|
||||||
File tempFile;
|
File TEMP_FILE;
|
||||||
}
|
boolean isSupportBreakpoint = true;
|
||||||
|
String CONFIG_FILE_PATH;
|
||||||
/**
|
|
||||||
* 单个线程的下载任务
|
|
||||||
*/
|
|
||||||
private class SingleThreadTask implements Runnable {
|
|
||||||
private static final String TAG = "SingleThreadTask";
|
|
||||||
private ConfigEntity configEntity;
|
|
||||||
private String configFPath;
|
|
||||||
private long currentLocation = 0;
|
|
||||||
|
|
||||||
private SingleThreadTask(ConfigEntity downloadInfo) {
|
|
||||||
this.configEntity = downloadInfo;
|
|
||||||
if (isSupportBreakpoint) {
|
|
||||||
configFPath = mContext.getFilesDir().getPath()
|
|
||||||
+ "/temp/"
|
|
||||||
+ configEntity.tempFile.getName()
|
|
||||||
+ ".properties";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void run() {
|
|
||||||
HttpURLConnection conn = null;
|
|
||||||
InputStream is = null;
|
|
||||||
try {
|
|
||||||
URL url = new URL(configEntity.downloadUrl);
|
|
||||||
conn = (HttpURLConnection) url.openConnection();
|
|
||||||
if (isSupportBreakpoint) {
|
|
||||||
Log.d(TAG, "线程_"
|
|
||||||
+ configEntity.threadId
|
|
||||||
+ "_正在下载【开始位置 : "
|
|
||||||
+ configEntity.startLocation
|
|
||||||
+ ",结束位置:"
|
|
||||||
+ configEntity.endLocation
|
|
||||||
+ "】");
|
|
||||||
//在头里面请求下载开始位置和结束位置
|
|
||||||
conn.setRequestProperty("Range",
|
|
||||||
"bytes=" + configEntity.startLocation + "-" + configEntity.endLocation);
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "该下载不支持断点,即将重新下载");
|
|
||||||
}
|
|
||||||
setConnectParam(conn);
|
|
||||||
conn.setConnectTimeout(mConnectTimeOut);
|
|
||||||
conn.setReadTimeout(mReadTimeOut); //设置读取流的等待时间,必须设置该参数
|
|
||||||
is = conn.getInputStream();
|
|
||||||
//创建可设置位置的文件
|
|
||||||
RandomAccessFile file = new RandomAccessFile(configEntity.tempFile, "rwd");
|
|
||||||
//设置每条线程写入文件的位置
|
|
||||||
file.seek(configEntity.startLocation);
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int len;
|
|
||||||
//当前子线程的下载位置
|
|
||||||
currentLocation = configEntity.startLocation;
|
|
||||||
while ((len = is.read(buffer)) != -1) {
|
|
||||||
if (isCancel) {
|
|
||||||
Log.d(TAG, "++++++++++ thread_" + configEntity.threadId + "_cancel ++++++++++");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isStop) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//把下载数据数据写入文件
|
|
||||||
file.write(buffer, 0, len);
|
|
||||||
progress(len);
|
|
||||||
}
|
|
||||||
file.close();
|
|
||||||
//close 为阻塞的,需要使用线程池来处理
|
|
||||||
is.close();
|
|
||||||
conn.disconnect();
|
|
||||||
|
|
||||||
if (isCancel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//停止状态不需要删除记录文件
|
|
||||||
if (isStop) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//支持断点的处理
|
|
||||||
if (isSupportBreakpoint) {
|
|
||||||
Log.i(TAG, "线程【" + configEntity.threadId + "】下载完毕");
|
|
||||||
writeConfig(configEntity.tempFile.getName() + "_state_" + configEntity.threadId, 1 + "");
|
|
||||||
mListener.onChildComplete(configEntity.endLocation);
|
|
||||||
mCompleteThreadNum++;
|
|
||||||
if (mCompleteThreadNum == THREAD_NUM) {
|
|
||||||
File configFile = new File(configFPath);
|
|
||||||
if (configFile.exists()) {
|
|
||||||
configFile.delete();
|
|
||||||
}
|
|
||||||
isDownloading = false;
|
|
||||||
mListener.onComplete();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "下载任务完成");
|
|
||||||
isDownloading = false;
|
|
||||||
mListener.onComplete();
|
|
||||||
}
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
mFailNum++;
|
|
||||||
failDownload(configEntity, currentLocation, "下载链接异常", e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
mFailNum++;
|
|
||||||
failDownload(configEntity, currentLocation, "下载失败【" + configEntity.downloadUrl + "】", e);
|
|
||||||
} catch (Exception e) {
|
|
||||||
mFailNum++;
|
|
||||||
failDownload(configEntity, currentLocation, "获取流失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止下载
|
|
||||||
*/
|
|
||||||
protected void stop() {
|
|
||||||
synchronized (LOCK) {
|
|
||||||
try {
|
|
||||||
if (isSupportBreakpoint) {
|
|
||||||
mStopNum++;
|
|
||||||
String location = String.valueOf(currentLocation);
|
|
||||||
Log.i(TAG,
|
|
||||||
"thread_" + configEntity.threadId + "_stop, stop location ==> " + currentLocation);
|
|
||||||
writeConfig(configEntity.tempFile.getName() + "_record_" + configEntity.threadId,
|
|
||||||
location);
|
|
||||||
if (mStopNum == THREAD_NUM) {
|
|
||||||
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
|
|
||||||
isDownloading = false;
|
|
||||||
mListener.onStop(mCurrentLocation);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
|
|
||||||
isDownloading = false;
|
|
||||||
mListener.onStop(mCurrentLocation);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载中
|
|
||||||
*/
|
|
||||||
private void progress(long len) {
|
|
||||||
synchronized (LOCK) {
|
|
||||||
currentLocation += len;
|
|
||||||
mCurrentLocation += len;
|
|
||||||
mListener.onProgress(mCurrentLocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消下载
|
|
||||||
*/
|
|
||||||
private void cancel() {
|
|
||||||
synchronized (LOCK) {
|
|
||||||
if (isSupportBreakpoint) {
|
|
||||||
mCancelNum++;
|
|
||||||
if (mCancelNum == THREAD_NUM) {
|
|
||||||
File configFile = new File(configFPath);
|
|
||||||
if (configFile.exists()) {
|
|
||||||
configFile.delete();
|
|
||||||
}
|
|
||||||
if (configEntity.tempFile.exists()) {
|
|
||||||
configEntity.tempFile.delete();
|
|
||||||
}
|
|
||||||
Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
|
|
||||||
isDownloading = false;
|
|
||||||
mListener.onCancel();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
|
|
||||||
isDownloading = false;
|
|
||||||
mListener.onCancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载失败
|
|
||||||
*/
|
|
||||||
private void failDownload(ConfigEntity dEntity, long currentLocation, String msg,
|
|
||||||
Exception ex) {
|
|
||||||
synchronized (LOCK) {
|
|
||||||
try {
|
|
||||||
isDownloading = false;
|
|
||||||
isStop = true;
|
|
||||||
if (ex != null) {
|
|
||||||
Log.e(TAG, CommonUtil.getPrintException(ex));
|
|
||||||
}
|
|
||||||
if (isSupportBreakpoint) {
|
|
||||||
if (currentLocation != -1) {
|
|
||||||
String location = String.valueOf(currentLocation);
|
|
||||||
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location);
|
|
||||||
}
|
|
||||||
if (mFailNum == THREAD_NUM) {
|
|
||||||
Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++");
|
|
||||||
mListener.onFail();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++");
|
|
||||||
mListener.onFail();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将记录写入到配置文件
|
|
||||||
*/
|
|
||||||
private void writeConfig(String key, String record) throws IOException {
|
|
||||||
File configFile = new File(configFPath);
|
|
||||||
Properties pro = CommonUtil.loadConfig(configFile);
|
|
||||||
pro.setProperty(key, record);
|
|
||||||
CommonUtil.saveConfig(configFile, pro);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* 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.aria.core.task;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||||
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2017/1/18.
|
||||||
|
* 下载线程
|
||||||
|
*/
|
||||||
|
final class SingleThreadTask implements Runnable {
|
||||||
|
private static final String TAG = "SingleThreadTask";
|
||||||
|
// TODO: 2017/2/22 不能使用1024 否则最大速度不能超过3m
|
||||||
|
private static final int BUF_SIZE = 8192;
|
||||||
|
private DownloadUtil.ConfigEntity mConfigEntity;
|
||||||
|
private String mConfigFPath;
|
||||||
|
private long mChildCurrentLocation = 0;
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
private IDownloadListener mListener;
|
||||||
|
private DownloadStateConstance mConstance;
|
||||||
|
|
||||||
|
SingleThreadTask(DownloadStateConstance constance, IDownloadListener listener,
|
||||||
|
DownloadUtil.ConfigEntity downloadInfo) {
|
||||||
|
mConstance = constance;
|
||||||
|
mListener = listener;
|
||||||
|
this.mConfigEntity = downloadInfo;
|
||||||
|
if (mConfigEntity.isSupportBreakpoint) {
|
||||||
|
mConfigFPath = downloadInfo.CONFIG_FILE_PATH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void run() {
|
||||||
|
HttpURLConnection conn = null;
|
||||||
|
InputStream is = null;
|
||||||
|
try {
|
||||||
|
URL url = new URL(mConfigEntity.DOWNLOAD_URL);
|
||||||
|
//conn = (HttpURLConnection) url.openConnection();
|
||||||
|
conn = ConnectionHelp.handleConnection(url);
|
||||||
|
if (mConfigEntity.isSupportBreakpoint) {
|
||||||
|
Log.d(TAG, "线程_"
|
||||||
|
+ mConfigEntity.THREAD_ID
|
||||||
|
+ "_正在下载【开始位置 : "
|
||||||
|
+ mConfigEntity.START_LOCATION
|
||||||
|
+ ",结束位置:"
|
||||||
|
+ mConfigEntity.END_LOCATION
|
||||||
|
+ "】");
|
||||||
|
//在头里面请求下载开始位置和结束位置
|
||||||
|
conn.setRequestProperty("Range",
|
||||||
|
"bytes=" + mConfigEntity.START_LOCATION + "-" + mConfigEntity.END_LOCATION);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "该下载不支持断点,即将重新下载");
|
||||||
|
}
|
||||||
|
conn = ConnectionHelp.setConnectParam(conn);
|
||||||
|
conn.setConnectTimeout(mConstance.CONNECT_TIME_OUT);
|
||||||
|
conn.setReadTimeout(mConstance.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数
|
||||||
|
is = conn.getInputStream();
|
||||||
|
//创建可设置位置的文件
|
||||||
|
BufferedRandomAccessFile file =
|
||||||
|
new BufferedRandomAccessFile(mConfigEntity.TEMP_FILE, "rwd", BUF_SIZE);
|
||||||
|
//设置文件长度
|
||||||
|
file.seek(mConfigEntity.START_LOCATION);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[BUF_SIZE];
|
||||||
|
int len;
|
||||||
|
//当前子线程的下载位置
|
||||||
|
mChildCurrentLocation = mConfigEntity.START_LOCATION;
|
||||||
|
while ((len = is.read(buffer)) != -1) {
|
||||||
|
if (mConstance.isCancel) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (mConstance.isStop) {
|
||||||
|
Log.i(TAG, "stop");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//把下载数据数据写入文件
|
||||||
|
file.write(buffer, 0, len);
|
||||||
|
progress(len);
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
//close 为阻塞的,需要使用线程池来处理
|
||||||
|
is.close();
|
||||||
|
conn.disconnect();
|
||||||
|
if (mConstance.isCancel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//停止状态不需要删除记录文件
|
||||||
|
if (mConstance.isStop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//支持断点的处理
|
||||||
|
if (mConfigEntity.isSupportBreakpoint) {
|
||||||
|
Log.i(TAG, "线程【" + mConfigEntity.THREAD_ID + "】下载完毕");
|
||||||
|
writeConfig(mConfigEntity.TEMP_FILE.getName() + "_state_" + mConfigEntity.THREAD_ID,
|
||||||
|
1 + "");
|
||||||
|
mListener.onChildComplete(mConfigEntity.END_LOCATION);
|
||||||
|
mConstance.COMPLETE_THREAD_NUM++;
|
||||||
|
if (mConstance.isComplete()) {
|
||||||
|
File configFile = new File(mConfigFPath);
|
||||||
|
if (configFile.exists()) {
|
||||||
|
configFile.delete();
|
||||||
|
}
|
||||||
|
mConstance.isDownloading = false;
|
||||||
|
mListener.onComplete();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "下载任务完成");
|
||||||
|
mConstance.isDownloading = false;
|
||||||
|
mListener.onComplete();
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
mConstance.FAIL_NUM++;
|
||||||
|
failDownload(mConfigEntity, mChildCurrentLocation, "下载链接异常", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
mConstance.FAIL_NUM++;
|
||||||
|
failDownload(mConfigEntity, mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】",
|
||||||
|
e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
mConstance.FAIL_NUM++;
|
||||||
|
failDownload(mConfigEntity, mChildCurrentLocation, "获取流失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止下载
|
||||||
|
*/
|
||||||
|
protected void stop() {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
try {
|
||||||
|
if (mConfigEntity.isSupportBreakpoint) {
|
||||||
|
mConstance.STOP_NUM++;
|
||||||
|
String location = String.valueOf(mChildCurrentLocation);
|
||||||
|
Log.d(TAG, "thread_"
|
||||||
|
+ mConfigEntity.THREAD_ID
|
||||||
|
+ "_stop, stop location ==> "
|
||||||
|
+ mChildCurrentLocation);
|
||||||
|
writeConfig(mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID,
|
||||||
|
location);
|
||||||
|
if (mConstance.isStop()) {
|
||||||
|
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
|
||||||
|
mConstance.isDownloading = false;
|
||||||
|
mListener.onStop(mConstance.CURRENT_LOCATION);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
|
||||||
|
mConstance.isDownloading = false;
|
||||||
|
mListener.onStop(mConstance.CURRENT_LOCATION);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载中
|
||||||
|
*/
|
||||||
|
private void progress(long len) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
mChildCurrentLocation += len;
|
||||||
|
mConstance.CURRENT_LOCATION += len;
|
||||||
|
mListener.onProgress(mConstance.CURRENT_LOCATION);
|
||||||
|
//mHandler.sendEmptyMessage(1);
|
||||||
|
//mHandler.post(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Handler mHandler = new Handler(Looper.getMainLooper()) {
|
||||||
|
@Override public void handleMessage(Message msg) {
|
||||||
|
super.handleMessage(msg);
|
||||||
|
mListener.onProgress(mConstance.CURRENT_LOCATION);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Thread t = new Thread(new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
mListener.onProgress(mConstance.CURRENT_LOCATION);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Handler handler = new Handler(){
|
||||||
|
// @Override public void handleMessage(Message msg) {
|
||||||
|
// super.handleMessage(msg);
|
||||||
|
// mListener.onProgress(mConstance.CURRENT_LOCATION);
|
||||||
|
// }
|
||||||
|
//};
|
||||||
|
|
||||||
|
Thread thread = new Thread();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消下载
|
||||||
|
*/
|
||||||
|
protected void cancel() {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (mConfigEntity.isSupportBreakpoint) {
|
||||||
|
mConstance.CANCEL_NUM++;
|
||||||
|
Log.d(TAG, "++++++++++ thread_" + mConfigEntity.THREAD_ID + "_cancel ++++++++++");
|
||||||
|
if (mConstance.isCancel()) {
|
||||||
|
File configFile = new File(mConfigFPath);
|
||||||
|
if (configFile.exists()) {
|
||||||
|
configFile.delete();
|
||||||
|
}
|
||||||
|
if (mConfigEntity.TEMP_FILE.exists()) {
|
||||||
|
mConfigEntity.TEMP_FILE.delete();
|
||||||
|
}
|
||||||
|
Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
|
||||||
|
mConstance.isDownloading = false;
|
||||||
|
mListener.onCancel();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
|
||||||
|
mConstance.isDownloading = false;
|
||||||
|
mListener.onCancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载失败
|
||||||
|
*/
|
||||||
|
private void failDownload(DownloadUtil.ConfigEntity dEntity, long currentLocation, String msg,
|
||||||
|
Exception ex) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
try {
|
||||||
|
mConstance.isDownloading = false;
|
||||||
|
mConstance.isStop = true;
|
||||||
|
if (ex != null) {
|
||||||
|
Log.e(TAG, CommonUtil.getPrintException(ex));
|
||||||
|
}
|
||||||
|
if (mConfigEntity.isSupportBreakpoint) {
|
||||||
|
if (currentLocation != -1) {
|
||||||
|
String location = String.valueOf(currentLocation);
|
||||||
|
writeConfig(dEntity.TEMP_FILE.getName() + "_record_" + dEntity.THREAD_ID, location);
|
||||||
|
}
|
||||||
|
if (mConstance.isFail()) {
|
||||||
|
Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++");
|
||||||
|
mListener.onFail();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++");
|
||||||
|
mListener.onFail();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将记录写入到配置文件
|
||||||
|
*/
|
||||||
|
private void writeConfig(String key, String record) throws IOException {
|
||||||
|
File configFile = new File(mConfigFPath);
|
||||||
|
Properties pro = CommonUtil.loadConfig(configFile);
|
||||||
|
pro.setProperty(key, record);
|
||||||
|
CommonUtil.saveConfig(configFile, pro);
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ import android.os.Handler;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.arialyy.aria.core.Aria;
|
import com.arialyy.aria.core.Aria;
|
||||||
import com.arialyy.aria.core.DownloadManager;
|
import com.arialyy.aria.core.DownloadManager;
|
||||||
|
import com.arialyy.aria.core.TaskEntity;
|
||||||
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
|
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
|
||||||
import com.arialyy.aria.core.scheduler.IDownloadSchedulers;
|
import com.arialyy.aria.core.scheduler.IDownloadSchedulers;
|
||||||
import com.arialyy.aria.core.DownloadEntity;
|
import com.arialyy.aria.core.DownloadEntity;
|
||||||
@ -196,20 +197,9 @@ public class Task {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
///**
|
|
||||||
// * 设置自定义下载工具
|
|
||||||
// *
|
|
||||||
// * @param downloadUtil {@link IDownloadUtil}
|
|
||||||
// */
|
|
||||||
//public Builder setDownloadUtil(IDownloadUtil downloadUtil) {
|
|
||||||
// this.downloadUtil = downloadUtil;
|
|
||||||
// return this;
|
|
||||||
//}
|
|
||||||
|
|
||||||
public Task build() {
|
public Task build() {
|
||||||
Task task = new Task(context, downloadEntity, outHandler);
|
Task task = new Task(context, downloadEntity, outHandler);
|
||||||
task.setTargetName(targetName);
|
task.setTargetName(targetName);
|
||||||
//Log.w(TAG, "downloadEntity hashcode ==> " + downloadEntity.hashCode());
|
|
||||||
downloadEntity.save();
|
downloadEntity.save();
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.arialyy.aria.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/1/18.
|
||||||
|
* Aria 文件异常
|
||||||
|
*/
|
||||||
|
public class FileException extends NullPointerException {
|
||||||
|
private static final String ARIA_FILE_EXCEPTION = "Aria Exception:";
|
||||||
|
|
||||||
|
public FileException(String detailMessage) {
|
||||||
|
super(ARIA_FILE_EXCEPTION + detailMessage);
|
||||||
|
}
|
||||||
|
}
|
@ -113,7 +113,6 @@ public class DbUtil {
|
|||||||
params[i] = "'" + expression[i + 1] + "'";
|
params[i] = "'" + expression[i + 1] + "'";
|
||||||
}
|
}
|
||||||
sql = String.format(sql, params);
|
sql = String.format(sql, params);
|
||||||
Log.d(TAG, sql);
|
|
||||||
print(DEL_DATA, sql);
|
print(DEL_DATA, sql);
|
||||||
mDb.execSQL(sql);
|
mDb.execSQL(sql);
|
||||||
close();
|
close();
|
||||||
@ -185,7 +184,6 @@ public class DbUtil {
|
|||||||
params[i] = "'" + expression[i + 1] + "'";
|
params[i] = "'" + expression[i + 1] + "'";
|
||||||
}
|
}
|
||||||
sql = String.format(sql, params);
|
sql = String.format(sql, params);
|
||||||
Log.d(TAG, sql);
|
|
||||||
print(FIND_DATA, sql);
|
print(FIND_DATA, sql);
|
||||||
Cursor cursor = mDb.rawQuery(sql, null);
|
Cursor cursor = mDb.rawQuery(sql, null);
|
||||||
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
|
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
|
||||||
|
@ -0,0 +1,328 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.aria.util;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
//import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A <code>BufferedRandomAccessFile</code> is like a
|
||||||
|
* <code>RandomAccessFile</code>, but it uses a private buffer so that most
|
||||||
|
* operations do not require a disk access.
|
||||||
|
* <P>
|
||||||
|
*
|
||||||
|
* Note: The operations on this class are unmonitored. Also, the correct
|
||||||
|
* functioning of the <code>RandomAccessFile</code> methods that are not
|
||||||
|
* overridden here relies on the implementation of those methods in the
|
||||||
|
* superclass.
|
||||||
|
* Author : Avinash Lakshman ( alakshman@facebook.com) Prashant Malik ( pmalik@facebook.com )
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class BufferedRandomAccessFile extends RandomAccessFile {
|
||||||
|
//private static final Logger logger_ = Logger.getLogger(BufferedRandomAccessFile.class);
|
||||||
|
static final int LogBuffSz_ = 16; // 64K buffer
|
||||||
|
public static final int BuffSz_ = (1 << LogBuffSz_);
|
||||||
|
static final long BuffMask_ = ~(((long) BuffSz_) - 1L);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This implementation is based on the buffer implementation in Modula-3's
|
||||||
|
* "Rd", "Wr", "RdClass", and "WrClass" interfaces.
|
||||||
|
*/
|
||||||
|
private boolean dirty_; // true iff unflushed bytes exist
|
||||||
|
private boolean closed_; // true iff the file is closed
|
||||||
|
private long curr_; // current position in file
|
||||||
|
private long lo_, hi_; // bounds on characters in "buff"
|
||||||
|
private byte[] buff_; // local buffer
|
||||||
|
private long maxHi_; // this.lo + this.buff.length
|
||||||
|
private boolean hitEOF_; // buffer contains last file block?
|
||||||
|
private long diskPos_; // disk position
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To describe the above fields, we introduce the following abstractions for
|
||||||
|
* the file "f":
|
||||||
|
*
|
||||||
|
* len(f) the length of the file curr(f) the current position in the file
|
||||||
|
* c(f) the abstract contents of the file disk(f) the contents of f's
|
||||||
|
* backing disk file closed(f) true iff the file is closed
|
||||||
|
*
|
||||||
|
* "curr(f)" is an index in the closed interval [0, len(f)]. "c(f)" is a
|
||||||
|
* character sequence of length "len(f)". "c(f)" and "disk(f)" may differ if
|
||||||
|
* "c(f)" contains unflushed writes not reflected in "disk(f)". The flush
|
||||||
|
* operation has the effect of making "disk(f)" identical to "c(f)".
|
||||||
|
*
|
||||||
|
* A file is said to be *valid* if the following conditions hold:
|
||||||
|
*
|
||||||
|
* V1. The "closed" and "curr" fields are correct:
|
||||||
|
*
|
||||||
|
* f.closed == closed(f) f.curr == curr(f)
|
||||||
|
*
|
||||||
|
* V2. The current position is either contained in the buffer, or just past
|
||||||
|
* the buffer:
|
||||||
|
*
|
||||||
|
* f.lo <= f.curr <= f.hi
|
||||||
|
*
|
||||||
|
* V3. Any (possibly) unflushed characters are stored in "f.buff":
|
||||||
|
*
|
||||||
|
* (forall i in [f.lo, f.curr): c(f)[i] == f.buff[i - f.lo])
|
||||||
|
*
|
||||||
|
* V4. For all characters not covered by V3, c(f) and disk(f) agree:
|
||||||
|
*
|
||||||
|
* (forall i in [f.lo, len(f)): i not in [f.lo, f.curr) => c(f)[i] ==
|
||||||
|
* disk(f)[i])
|
||||||
|
*
|
||||||
|
* V5. "f.dirty" is true iff the buffer contains bytes that should be
|
||||||
|
* flushed to the file; by V3 and V4, only part of the buffer can be dirty.
|
||||||
|
*
|
||||||
|
* f.dirty == (exists i in [f.lo, f.curr): c(f)[i] != f.buff[i - f.lo])
|
||||||
|
*
|
||||||
|
* V6. this.maxHi == this.lo + this.buff.length
|
||||||
|
*
|
||||||
|
* Note that "f.buff" can be "null" in a valid file, since the range of
|
||||||
|
* characters in V3 is empty when "f.lo == f.curr".
|
||||||
|
*
|
||||||
|
* A file is said to be *ready* if the buffer contains the current position,
|
||||||
|
* i.e., when:
|
||||||
|
*
|
||||||
|
* R1. !f.closed && f.buff != null && f.lo <= f.curr && f.curr < f.hi
|
||||||
|
*
|
||||||
|
* When a file is ready, reading or writing a single byte can be performed
|
||||||
|
* by reading or writing the in-memory buffer without performing a disk
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new <code>BufferedRandomAccessFile</code> on <code>file</code>
|
||||||
|
* in mode <code>mode</code>, which should be "r" for reading only, or
|
||||||
|
* "rw" for reading and writing.
|
||||||
|
*/
|
||||||
|
public BufferedRandomAccessFile(File file, String mode) throws IOException {
|
||||||
|
super(file, mode);
|
||||||
|
this.init(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedRandomAccessFile(File file, String mode, int size) throws IOException {
|
||||||
|
super(file, mode);
|
||||||
|
this.init(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new <code>BufferedRandomAccessFile</code> on the file named
|
||||||
|
* <code>name</code> in mode <code>mode</code>, which should be "r" for
|
||||||
|
* reading only, or "rw" for reading and writing.
|
||||||
|
*/
|
||||||
|
public BufferedRandomAccessFile(String name, String mode) throws IOException {
|
||||||
|
super(name, mode);
|
||||||
|
this.init(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedRandomAccessFile(String name, String mode, int size) throws FileNotFoundException {
|
||||||
|
super(name, mode);
|
||||||
|
this.init(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(int size) {
|
||||||
|
this.dirty_ = this.closed_ = false;
|
||||||
|
this.lo_ = this.curr_ = this.hi_ = 0;
|
||||||
|
this.buff_ = (size > BuffSz_) ? new byte[size] : new byte[BuffSz_];
|
||||||
|
this.maxHi_ = (long) BuffSz_;
|
||||||
|
this.hitEOF_ = false;
|
||||||
|
this.diskPos_ = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
this.flush();
|
||||||
|
this.closed_ = true;
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush any bytes in the file's buffer that have not yet been written to
|
||||||
|
* disk. If the file was created read-only, this method is a no-op.
|
||||||
|
*/
|
||||||
|
public void flush() throws IOException {
|
||||||
|
this.flushBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush any dirty bytes in the buffer to disk. */
|
||||||
|
private void flushBuffer() throws IOException {
|
||||||
|
if (this.dirty_) {
|
||||||
|
if (this.diskPos_ != this.lo_) super.seek(this.lo_);
|
||||||
|
int len = (int) (this.curr_ - this.lo_);
|
||||||
|
super.write(this.buff_, 0, len);
|
||||||
|
this.diskPos_ = this.curr_;
|
||||||
|
this.dirty_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read at most "this.buff.length" bytes into "this.buff", returning the
|
||||||
|
* number of bytes read. If the return result is less than
|
||||||
|
* "this.buff.length", then EOF was read.
|
||||||
|
*/
|
||||||
|
private int fillBuffer() throws IOException {
|
||||||
|
int cnt = 0;
|
||||||
|
int rem = this.buff_.length;
|
||||||
|
while (rem > 0) {
|
||||||
|
int n = super.read(this.buff_, cnt, rem);
|
||||||
|
if (n < 0) break;
|
||||||
|
cnt += n;
|
||||||
|
rem -= n;
|
||||||
|
}
|
||||||
|
if ((cnt < 0) && (this.hitEOF_ = (cnt < this.buff_.length))) {
|
||||||
|
// make sure buffer that wasn't read is initialized with -1
|
||||||
|
Arrays.fill(this.buff_, cnt, this.buff_.length, (byte) 0xff);
|
||||||
|
}
|
||||||
|
this.diskPos_ += cnt;
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This method positions <code>this.curr</code> at position <code>pos</code>.
|
||||||
|
* If <code>pos</code> does not fall in the current buffer, it flushes the
|
||||||
|
* current buffer and loads the correct one.<p>
|
||||||
|
*
|
||||||
|
* On exit from this routine <code>this.curr == this.hi</code> iff <code>pos</code>
|
||||||
|
* is at or past the end-of-file, which can only happen if the file was
|
||||||
|
* opened in read-only mode.
|
||||||
|
*/
|
||||||
|
public void seek(long pos) throws IOException {
|
||||||
|
if (pos >= this.hi_ || pos < this.lo_) {
|
||||||
|
// seeking outside of current buffer -- flush and read
|
||||||
|
this.flushBuffer();
|
||||||
|
this.lo_ = pos & BuffMask_; // start at BuffSz boundary
|
||||||
|
this.maxHi_ = this.lo_ + (long) this.buff_.length;
|
||||||
|
if (this.diskPos_ != this.lo_) {
|
||||||
|
super.seek(this.lo_);
|
||||||
|
this.diskPos_ = this.lo_;
|
||||||
|
}
|
||||||
|
int n = this.fillBuffer();
|
||||||
|
this.hi_ = this.lo_ + (long) n;
|
||||||
|
} else {
|
||||||
|
// seeking inside current buffer -- no read required
|
||||||
|
if (pos < this.curr_) {
|
||||||
|
// if seeking backwards, we must flush to maintain V4
|
||||||
|
this.flushBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.curr_ = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getFilePointer() {
|
||||||
|
return this.curr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long length() throws IOException {
|
||||||
|
return Math.max(this.curr_, super.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read() throws IOException {
|
||||||
|
if (this.curr_ >= this.hi_) {
|
||||||
|
// test for EOF
|
||||||
|
// if (this.hi < this.maxHi) return -1;
|
||||||
|
if (this.hitEOF_) return -1;
|
||||||
|
|
||||||
|
// slow path -- read another buffer
|
||||||
|
this.seek(this.curr_);
|
||||||
|
if (this.curr_ == this.hi_) return -1;
|
||||||
|
}
|
||||||
|
byte res = this.buff_[(int) (this.curr_ - this.lo_)];
|
||||||
|
this.curr_++;
|
||||||
|
return ((int) res) & 0xFF; // convert byte -> int
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(byte[] b) throws IOException {
|
||||||
|
return this.read(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
if (this.curr_ >= this.hi_) {
|
||||||
|
// test for EOF
|
||||||
|
// if (this.hi < this.maxHi) return -1;
|
||||||
|
if (this.hitEOF_) return -1;
|
||||||
|
|
||||||
|
// slow path -- read another buffer
|
||||||
|
this.seek(this.curr_);
|
||||||
|
if (this.curr_ == this.hi_) return -1;
|
||||||
|
}
|
||||||
|
len = Math.min(len, (int) (this.hi_ - this.curr_));
|
||||||
|
int buffOff = (int) (this.curr_ - this.lo_);
|
||||||
|
System.arraycopy(this.buff_, buffOff, b, off, len);
|
||||||
|
this.curr_ += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
if (this.curr_ >= this.hi_) {
|
||||||
|
if (this.hitEOF_ && this.hi_ < this.maxHi_) {
|
||||||
|
// at EOF -- bump "hi"
|
||||||
|
this.hi_++;
|
||||||
|
} else {
|
||||||
|
// slow path -- write current buffer; read next one
|
||||||
|
this.seek(this.curr_);
|
||||||
|
if (this.curr_ == this.hi_) {
|
||||||
|
// appending to EOF -- bump "hi"
|
||||||
|
this.hi_++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.buff_[(int) (this.curr_ - this.lo_)] = (byte) b;
|
||||||
|
this.curr_++;
|
||||||
|
this.dirty_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(byte[] b) throws IOException {
|
||||||
|
this.write(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
|
while (len > 0) {
|
||||||
|
int n = this.writeAtMost(b, off, len);
|
||||||
|
off += n;
|
||||||
|
len -= n;
|
||||||
|
this.dirty_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write at most "len" bytes to "b" starting at position "off", and return
|
||||||
|
* the number of bytes written.
|
||||||
|
*/
|
||||||
|
private int writeAtMost(byte[] b, int off, int len) throws IOException {
|
||||||
|
if (this.curr_ >= this.hi_) {
|
||||||
|
if (this.hitEOF_ && this.hi_ < this.maxHi_) {
|
||||||
|
// at EOF -- bump "hi"
|
||||||
|
this.hi_ = this.maxHi_;
|
||||||
|
} else {
|
||||||
|
// slow path -- write current buffer; read next one
|
||||||
|
this.seek(this.curr_);
|
||||||
|
if (this.curr_ == this.hi_) {
|
||||||
|
// appending to EOF -- bump "hi"
|
||||||
|
this.hi_ = this.maxHi_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len = Math.min(len, (int) (this.hi_ - this.curr_));
|
||||||
|
int buffOff = (int) (this.curr_ - this.lo_);
|
||||||
|
System.arraycopy(b, off, this.buff_, buffOff, len);
|
||||||
|
this.curr_ += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.aria.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/1/11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CAConfiguration {
|
||||||
|
public static String CA_PATH, CA_ALIAS;
|
||||||
|
}
|
@ -19,6 +19,7 @@ package com.arialyy.aria.util;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.arialyy.aria.core.DownloadEntity;
|
import com.arialyy.aria.core.DownloadEntity;
|
||||||
|
import com.arialyy.aria.exception.FileException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -30,6 +31,10 @@ import java.util.regex.Pattern;
|
|||||||
public class CheckUtil {
|
public class CheckUtil {
|
||||||
private static final String TAG = "CheckUtil";
|
private static final String TAG = "CheckUtil";
|
||||||
|
|
||||||
|
public static void checkNull(Object obj) {
|
||||||
|
if (obj == null) throw new IllegalArgumentException("不能传入空对象");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查sql的expression是否合法
|
* 检查sql的expression是否合法
|
||||||
*/
|
*/
|
||||||
@ -80,9 +85,9 @@ public class CheckUtil {
|
|||||||
return false;
|
return false;
|
||||||
} else if (TextUtils.isEmpty(entity.getFileName())) {
|
} else if (TextUtils.isEmpty(entity.getFileName())) {
|
||||||
//Log.w(TAG, "文件名不能为空");
|
//Log.w(TAG, "文件名不能为空");
|
||||||
throw new IllegalArgumentException("文件名不能为null");
|
throw new FileException("文件名不能为null");
|
||||||
} else if (TextUtils.isEmpty(entity.getDownloadPath())) {
|
} else if (TextUtils.isEmpty(entity.getDownloadPath())) {
|
||||||
throw new IllegalArgumentException("文件保存路径不能为null");
|
throw new FileException("文件保存路径不能为null");
|
||||||
}
|
}
|
||||||
String fileName = entity.getFileName();
|
String fileName = entity.getFileName();
|
||||||
if (fileName.contains(" ")) {
|
if (fileName.contains(" ")) {
|
||||||
|
131
Aria/src/main/java/com/arialyy/aria/util/SSLContextUtil.java
Normal file
131
Aria/src/main/java/com/arialyy/aria/util/SSLContextUtil.java
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* 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.aria.util;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import com.arialyy.aria.core.DownloadManager;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSession;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/1/11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class SSLContextUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 颁发服务器证书的 CA 未知
|
||||||
|
*
|
||||||
|
* @param caAlias CA证书别名
|
||||||
|
* @param caPath 保存在assets目录下的CA证书完整路径
|
||||||
|
*/
|
||||||
|
public static SSLContext getSSLContext(String caAlias, String caPath) {
|
||||||
|
if (TextUtils.isEmpty(caAlias) || TextUtils.isEmpty(caPath)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Load CAs from an InputStream
|
||||||
|
// (could be from a resource or ByteArrayInputStream or ...)
|
||||||
|
CertificateFactory cf = null;
|
||||||
|
try {
|
||||||
|
cf = CertificateFactory.getInstance("X.509");
|
||||||
|
InputStream caInput = DownloadManager.APP.getAssets().open(caPath);
|
||||||
|
Certificate ca;
|
||||||
|
ca = cf.generateCertificate(caInput);
|
||||||
|
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
|
||||||
|
|
||||||
|
// Create a KeyStore containing our trusted CAs
|
||||||
|
String keyStoreType = KeyStore.getDefaultType();
|
||||||
|
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
|
||||||
|
keyStore.load(null, null);
|
||||||
|
keyStore.setCertificateEntry(caAlias, ca);
|
||||||
|
|
||||||
|
// Create a TrustManager that trusts the CAs in our KeyStore
|
||||||
|
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||||
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
|
||||||
|
tmf.init(keyStore);
|
||||||
|
KeyManagerFactory kmf =
|
||||||
|
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||||
|
kmf.init(keyStore, null);
|
||||||
|
|
||||||
|
// Create an SSLContext that uses our TrustManager
|
||||||
|
SSLContext context = SSLContext.getInstance("TLS");
|
||||||
|
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
|
||||||
|
return context;
|
||||||
|
} catch (CertificateException | NoSuchAlgorithmException | IOException | KeyStoreException | KeyManagementException | UnrecoverableKeyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器证书不是由 CA 签署的,而是自签署时,获取默认的SSL
|
||||||
|
*/
|
||||||
|
public static SSLContext getDefaultSLLContext() {
|
||||||
|
SSLContext sslContext = null;
|
||||||
|
try {
|
||||||
|
sslContext = SSLContext.getInstance("TLS");
|
||||||
|
sslContext.init(null, new TrustManager[] { trustManagers }, new SecureRandom());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return sslContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建自己的 TrustManager,这次直接信任服务器证书。这种方法具有前面所述的将应用与证书直接关联的所有弊端,但可以安全地操作。
|
||||||
|
*/
|
||||||
|
private static TrustManager trustManagers = new X509TrustManager() {
|
||||||
|
|
||||||
|
@Override public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||||
|
throws CertificateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void checkServerTrusted(X509Certificate[] chain, String authType)
|
||||||
|
throws CertificateException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return new X509Certificate[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() {
|
||||||
|
public boolean verify(String hostname, SSLSession session) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
24
README.md
24
README.md
@ -8,6 +8,7 @@
|
|||||||
- 支持多线程、多任务下载
|
- 支持多线程、多任务下载
|
||||||
- 支持任务自动切换
|
- 支持任务自动切换
|
||||||
- 支持下载速度直接获取
|
- 支持下载速度直接获取
|
||||||
|
- 支持https地址下载
|
||||||
|
|
||||||
[Aria怎样使用?](#使用)
|
[Aria怎样使用?](#使用)
|
||||||
|
|
||||||
@ -16,11 +17,9 @@
|
|||||||
## 下载
|
## 下载
|
||||||
[](https://bintray.com/arialyy/maven/Aria/_latestVersion)</br>
|
[](https://bintray.com/arialyy/maven/Aria/_latestVersion)</br>
|
||||||
```java
|
```java
|
||||||
compile 'com.arialyy.aria:Aria:2.3.8'
|
compile 'com.arialyy.aria:Aria:2.4.2'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 示例
|
## 示例
|
||||||

|

|
||||||

|

|
||||||
@ -52,6 +51,7 @@ compile 'com.arialyy.aria:Aria:2.3.8'
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
### 四、通过下载链接,你还能使用Aria执行很多操作,如:
|
### 四、通过下载链接,你还能使用Aria执行很多操作,如:
|
||||||
|
Aria支持https下载,如果你希望使用自己的ca证书,那么你需要进行[Aria https证书配置](#https证书配置)
|
||||||
- 添加任务(不进行下载)
|
- 添加任务(不进行下载)
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@ -118,8 +118,25 @@ compile 'com.arialyy.aria:Aria:2.3.8'
|
|||||||
Aria.get(this).openBroadcast(true);
|
Aria.get(this).openBroadcast(true);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### https证书配置
|
||||||
|
+ 将你的证书导入`assets`目录
|
||||||
|
+ 调用以下代码配置ca证书相关信息
|
||||||
|
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 设置CA证书信息
|
||||||
|
*
|
||||||
|
* @param caAlias ca证书别名
|
||||||
|
* @param caPath assets 文件夹下的ca证书完整路径
|
||||||
|
*/
|
||||||
|
Aria.get(this).setCAInfo("caAlias","caPath");
|
||||||
|
```
|
||||||
|
|
||||||
***
|
***
|
||||||
## 开发日志
|
## 开发日志
|
||||||
|
+ v_2.4.2 修复失败重试无效的bug
|
||||||
|
+ v_2.4.1 修复下载慢的问题,修复application、service 不能使用的问题
|
||||||
|
+ v_2.4.0 支持https链接下载
|
||||||
+ v_2.3.8 修复数据错乱的bug、添加fragment支持
|
+ v_2.3.8 修复数据错乱的bug、添加fragment支持
|
||||||
+ v_2.3.6 添加dialog、popupWindow支持
|
+ v_2.3.6 添加dialog、popupWindow支持
|
||||||
+ v_2.3.3
|
+ v_2.3.3
|
||||||
@ -128,7 +145,6 @@ compile 'com.arialyy.aria:Aria:2.3.8'
|
|||||||
- 修复一个内存泄露的bug
|
- 修复一个内存泄露的bug
|
||||||
+ v_2.3.1 重命名为Aria,下载流程简化
|
+ v_2.3.1 重命名为Aria,下载流程简化
|
||||||
+ v_2.1.1 增加,选择最大下载任务数接口
|
+ v_2.1.1 增加,选择最大下载任务数接口
|
||||||
+ v_2.1.0 修复大量bug
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
@ -33,6 +33,7 @@ import com.arialyy.simple.databinding.ActivityMainBinding;
|
|||||||
import com.arialyy.simple.dialog_task.DownloadDialog;
|
import com.arialyy.simple.dialog_task.DownloadDialog;
|
||||||
import com.arialyy.simple.fragment_task.FragmentActivity;
|
import com.arialyy.simple.fragment_task.FragmentActivity;
|
||||||
import com.arialyy.simple.multi_task.MultiTaskActivity;
|
import com.arialyy.simple.multi_task.MultiTaskActivity;
|
||||||
|
import com.arialyy.simple.notification.SimpleNotification;
|
||||||
import com.arialyy.simple.pop_task.DownloadPopupWindow;
|
import com.arialyy.simple.pop_task.DownloadPopupWindow;
|
||||||
import com.arialyy.simple.single_task.SingleTaskActivity;
|
import com.arialyy.simple.single_task.SingleTaskActivity;
|
||||||
|
|
||||||
@ -104,6 +105,10 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
|
|||||||
case R.id.fragment_task:
|
case R.id.fragment_task:
|
||||||
startActivity(new Intent(this, FragmentActivity.class));
|
startActivity(new Intent(this, FragmentActivity.class));
|
||||||
break;
|
break;
|
||||||
|
case R.id.notification:
|
||||||
|
SimpleNotification notification = new SimpleNotification(this);
|
||||||
|
notification.start();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -67,7 +67,6 @@ final class FileListAdapter extends AbsRVAdapter<FileListEntity, FileListAdapter
|
|||||||
Set<String> keys = mBtStates.keySet();
|
Set<String> keys = mBtStates.keySet();
|
||||||
for (String key : keys) {
|
for (String key : keys) {
|
||||||
if (key.equals(downloadUrl)) {
|
if (key.equals(downloadUrl)) {
|
||||||
Log.d(TAG, "able ==> " + able);
|
|
||||||
mBtStates.put(downloadUrl, able);
|
mBtStates.put(downloadUrl, able);
|
||||||
notifyItemChanged(indexItem(downloadUrl));
|
notifyItemChanged(indexItem(downloadUrl));
|
||||||
return;
|
return;
|
||||||
@ -80,7 +79,7 @@ final class FileListAdapter extends AbsRVAdapter<FileListEntity, FileListAdapter
|
|||||||
for (String key : keys) {
|
for (String key : keys) {
|
||||||
if (key.equals(url)) {
|
if (key.equals(url)) {
|
||||||
int index = mPositions.get(key);
|
int index = mPositions.get(key);
|
||||||
Log.d(TAG, "index ==> " + index);
|
//Log.d(TAG, "index ==> " + index);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
package com.arialyy.simple.notification;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import com.arialyy.aria.core.Aria;
|
||||||
|
import com.arialyy.aria.core.task.Task;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import com.arialyy.frame.util.show.T;
|
||||||
|
import com.arialyy.simple.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/1/18.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class SimpleNotification {
|
||||||
|
private static final String DOWNLOAD_URL =
|
||||||
|
"http://static.gaoshouyou.com/d/6e/e5/ff6ecaaf45e532e6d07747af82357472.apk";
|
||||||
|
|
||||||
|
private NotificationManager mManager;
|
||||||
|
private Context mContext;
|
||||||
|
private NotificationCompat.Builder mBuilder;
|
||||||
|
private static final int mNotifiyId = 0;
|
||||||
|
|
||||||
|
public SimpleNotification(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
mManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
mBuilder = new NotificationCompat.Builder(mContext);
|
||||||
|
mBuilder.setContentTitle("Aria Download Test")
|
||||||
|
.setContentText("进度条")
|
||||||
|
.setProgress(100, 0, false)
|
||||||
|
.setSmallIcon(R.mipmap.ic_launcher);
|
||||||
|
mManager.notify(mNotifiyId, mBuilder.build());
|
||||||
|
Aria.whit(mContext).addSchedulerListener(new DownloadCallback(mBuilder, mManager));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
Aria.whit(mContext)
|
||||||
|
.load(DOWNLOAD_URL)
|
||||||
|
.setDownloadName("notification_test.apk")
|
||||||
|
.setDownloadPath(
|
||||||
|
Environment.getExternalStorageDirectory() + "/Download/notification_test.apk")
|
||||||
|
.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
Aria.whit(mContext).load(DOWNLOAD_URL).stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DownloadCallback extends Aria.SimpleSchedulerListener {
|
||||||
|
NotificationCompat.Builder mBuilder;
|
||||||
|
NotificationManager mManager;
|
||||||
|
|
||||||
|
private DownloadCallback(NotificationCompat.Builder builder, NotificationManager manager) {
|
||||||
|
mBuilder = builder;
|
||||||
|
mManager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onTaskStart(Task task) {
|
||||||
|
super.onTaskStart(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onTaskPre(Task task) {
|
||||||
|
super.onTaskPre(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onTaskStop(Task task) {
|
||||||
|
super.onTaskStop(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onTaskRunning(Task task) {
|
||||||
|
super.onTaskRunning(task);
|
||||||
|
long len = task.getFileSize();
|
||||||
|
int p = (int) (task.getCurrentProgress() * 100 / len);
|
||||||
|
if (mBuilder != null) {
|
||||||
|
mBuilder.setProgress(100, p, false);
|
||||||
|
mManager.notify(mNotifiyId, mBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onTaskComplete(Task task) {
|
||||||
|
super.onTaskComplete(task);
|
||||||
|
if (mBuilder != null) {
|
||||||
|
mBuilder.setProgress(100, 100, false);
|
||||||
|
mManager.notify(mNotifiyId, mBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onTaskCancel(Task task) {
|
||||||
|
super.onTaskCancel(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,8 @@ import butterknife.Bind;
|
|||||||
import com.arialyy.aria.core.AMTarget;
|
import com.arialyy.aria.core.AMTarget;
|
||||||
import com.arialyy.aria.core.Aria;
|
import com.arialyy.aria.core.Aria;
|
||||||
import com.arialyy.aria.core.DownloadEntity;
|
import com.arialyy.aria.core.DownloadEntity;
|
||||||
|
import com.arialyy.aria.core.task.DownloadUtil;
|
||||||
|
import com.arialyy.aria.core.task.IDownloadListener;
|
||||||
import com.arialyy.aria.core.task.Task;
|
import com.arialyy.aria.core.task.Task;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
import com.arialyy.frame.util.show.L;
|
import com.arialyy.frame.util.show.L;
|
||||||
@ -49,10 +51,11 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
|||||||
public static final int DOWNLOAD_RESUME = 0x05;
|
public static final int DOWNLOAD_RESUME = 0x05;
|
||||||
public static final int DOWNLOAD_COMPLETE = 0x06;
|
public static final int DOWNLOAD_COMPLETE = 0x06;
|
||||||
public static final int DOWNLOAD_RUNNING = 0x07;
|
public static final int DOWNLOAD_RUNNING = 0x07;
|
||||||
|
|
||||||
private static final String DOWNLOAD_URL =
|
private static final String DOWNLOAD_URL =
|
||||||
"http://static.gaoshouyou.com/d/3a/93/573ae1db9493a801c24bf66128b11e39.apk";
|
//"http://kotlinlang.org/docs/kotlin-docs.pdf";
|
||||||
//private static final String DOWNLOAD_URL =
|
//"https://atom-installer.github.com/v1.13.0/AtomSetup.exe?s=1484074138&ext=.exe";
|
||||||
// "http://www.yangqiang.im/wp-content/uploads/2016/10/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F.png";
|
"http://static.gaoshouyou.com/d/21/e8/61218d78d0e8b79df68dbc18dd484c97.apk";
|
||||||
@Bind(R.id.progressBar) HorizontalProgressBarWithNumber mPb;
|
@Bind(R.id.progressBar) HorizontalProgressBarWithNumber mPb;
|
||||||
@Bind(R.id.start) Button mStart;
|
@Bind(R.id.start) Button mStart;
|
||||||
@Bind(R.id.stop) Button mStop;
|
@Bind(R.id.stop) Button mStop;
|
||||||
@ -89,7 +92,7 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
|||||||
case DOWNLOAD_PRE:
|
case DOWNLOAD_PRE:
|
||||||
mSize.setText(CommonUtil.formatFileSize((Long) msg.obj));
|
mSize.setText(CommonUtil.formatFileSize((Long) msg.obj));
|
||||||
setBtState(false);
|
setBtState(false);
|
||||||
mStart.setText("暂停");
|
//mStart.setText("暂停");
|
||||||
break;
|
break;
|
||||||
case DOWNLOAD_FAILE:
|
case DOWNLOAD_FAILE:
|
||||||
Toast.makeText(SingleTaskActivity.this, "下载失败", Toast.LENGTH_SHORT).show();
|
Toast.makeText(SingleTaskActivity.this, "下载失败", Toast.LENGTH_SHORT).show();
|
||||||
@ -114,15 +117,11 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
|||||||
setBtState(false);
|
setBtState(false);
|
||||||
break;
|
break;
|
||||||
case DOWNLOAD_COMPLETE:
|
case DOWNLOAD_COMPLETE:
|
||||||
|
mPb.setProgress(100);
|
||||||
Toast.makeText(SingleTaskActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
|
Toast.makeText(SingleTaskActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
|
||||||
mStart.setText("重新开始?");
|
mStart.setText("重新开始?");
|
||||||
mCancel.setEnabled(false);
|
mCancel.setEnabled(false);
|
||||||
setBtState(true);
|
setBtState(true);
|
||||||
|
|
||||||
//String path = Environment.getExternalStorageDirectory().getPath() + "/test.jpg";
|
|
||||||
//Bitmap bm = BitmapFactory.decodeFile(path);
|
|
||||||
//mImg.setImageBitmap(bm);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,9 +199,68 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
|||||||
.load(DOWNLOAD_URL)
|
.load(DOWNLOAD_URL)
|
||||||
.setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk")
|
.setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk")
|
||||||
.setDownloadName("test.apk")
|
.setDownloadName("test.apk")
|
||||||
//.setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.jpg")
|
|
||||||
//.setDownloadName("test.jpg")
|
|
||||||
.start();
|
.start();
|
||||||
|
//DownloadEntity entity = new DownloadEntity();
|
||||||
|
//entity.setDownloadUrl(DOWNLOAD_URL);
|
||||||
|
//entity.setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk");
|
||||||
|
//entity.setFileName("test.apk");
|
||||||
|
//DownloadUtil util = new DownloadUtil(this, entity, new IDownloadListener() {
|
||||||
|
// long fileSize = 1;
|
||||||
|
// @Override public void supportBreakpoint(boolean support) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onCancel() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onFail() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onPre() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onPostPre(long fileSize) {
|
||||||
|
// this.fileSize = fileSize;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onProgress(long currentLocation) {
|
||||||
|
// long current = currentLocation;
|
||||||
|
// long len = fileSize;
|
||||||
|
// if (len == 0) {
|
||||||
|
// mPb.setProgress(0);
|
||||||
|
// } else {
|
||||||
|
// mPb.setProgress((int) ((current * 100) / len));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onChildComplete(long finishLocation) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onStart(long startLocation) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onChildResume(long resumeLocation) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onResume(long resumeLocation) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onStop(long stopLocation) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override public void onComplete() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
//util.startDownload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stop() {
|
private void stop() {
|
||||||
|
@ -56,5 +56,14 @@
|
|||||||
style="?buttonBarButtonStyle"
|
style="?buttonBarButtonStyle"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/notification"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:onClick="onClick"
|
||||||
|
android:text="在Notification中使用"
|
||||||
|
style="?buttonBarButtonStyle"
|
||||||
|
/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</layout>
|
</layout>
|
||||||
|
Reference in New Issue
Block a user