优化target结构

Change-Id: I7ec154c9d5d5319b5dc8fdbf908f4358dbf4baaf
pull/330/head
laoyuyu 7 years ago
parent bc03b82e76
commit a7174340ae
  1. 23
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  2. 64
      Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java
  3. 202
      Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java
  4. 110
      Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java
  5. 159
      Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java
  6. 200
      Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
  7. 2
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
  8. 209
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  9. 27
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  10. 131
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  11. 82
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
  12. 93
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  13. 151
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java
  14. 145
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  15. 65
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java
  16. 45
      Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java
  17. 79
      Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java
  18. 45
      Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
  19. 6
      Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
  20. 28
      Aria/src/main/java/com/arialyy/aria/core/upload/AbsUploadTarget.java
  21. 139
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java
  22. 78
      Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
  23. 2
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
  24. 64
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
  25. 28
      Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
  26. 26
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  27. 2
      app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java
  28. 2
      app/src/main/java/com/arialyy/simple/download/group/FTPDirDownloadActivity.java

@ -97,7 +97,7 @@ import org.xml.sax.SAXException;
}
/**
* 设置Aria 日志级别
* 设置Aria日志级别
*
* @param level {@link ALog#LOG_LEVEL_VERBOSE}
*/
@ -106,20 +106,34 @@ import org.xml.sax.SAXException;
}
/**
* 设置上传任务的执行队列类型
* 设置上传任务的执行队列类型后续版本会删除该api请使用
* <pre>
* <code>
* Aria.get(this).getUploadConfig().setQueueMod(mod.tag)
* </code>
* <pre/>
*
* @param mod {@link QueueMod}
* @deprecated 后续版本会删除该api
*/
@Deprecated
public AriaManager setUploadQueueMod(QueueMod mod) {
mUConfig.setQueueMod(mod.tag);
return this;
}
/**
* 设置下载任务的执行队列类型
* 设置下载任务的执行队列类型后续版本会删除该api请使用
* <pre>
* <code>
* Aria.get(this).getDownloadConfig().setQueueMod(mod.tag)
* </code>
* <pre/>
*
* @param mod {@link QueueMod}
* @deprecated 后续版本会删除该api
*/
@Deprecated
public AriaManager setDownloadQueueMod(QueueMod mod) {
mDConfig.setQueueMod(mod.tag);
return this;
@ -270,7 +284,8 @@ import org.xml.sax.SAXException;
/**
* 不允许在"onDestroy""finish""onStop"这三个方法中添加注册器
*/
private AbsReceiver checkTarget(String key, AbsReceiver receiver, Object obj, boolean needRmReceiver) {
private AbsReceiver checkTarget(String key, AbsReceiver receiver, Object obj,
boolean needRmReceiver) {
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
int i = 0;
for (StackTraceElement e : stack) {

@ -0,0 +1,64 @@
/*
* 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.delegate;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.inf.ITarget;
import com.arialyy.aria.util.ALog;
/**
* Created by laoyuyu on 2018/3/9.
* ftp 委托
*/
public class FtpDelegate<TARGET extends ITarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements IFtpTarget<TARGET> {
private static final String TAG = "FtpDelegate";
private ENTITY mEntity;
private TASK_ENTITY mTaskEntity;
public FtpDelegate(TASK_ENTITY mTaskEntity) {
this.mTaskEntity = mTaskEntity;
mEntity = mTaskEntity.getEntity();
}
@Override public TARGET charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return (TARGET) this;
mTaskEntity.charSet = charSet;
return (TARGET) this;
}
@Override public TARGET login(String userName, String password) {
return login(userName, password, null);
}
@Override public TARGET login(String userName, String password, String account) {
if (TextUtils.isEmpty(userName)) {
ALog.e(TAG, "用户名不能为null");
return (TARGET) this;
} else if (TextUtils.isEmpty(password)) {
ALog.e(TAG, "密码不能为null");
return (TARGET) this;
}
mTaskEntity.urlEntity.needLogin = true;
mTaskEntity.urlEntity.user = userName;
mTaskEntity.urlEntity.password = password;
mTaskEntity.urlEntity.account = account;
return (TARGET) this;
}
}

@ -0,0 +1,202 @@
/*
* 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.delegate;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import com.arialyy.aria.core.inf.ITarget;
import com.arialyy.aria.util.ALog;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Created by laoyuyu on 2018/3/9.
* HTTP header参数设置委托类
*/
public class HttpHeaderDelegate<TARGET extends ITarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements IHttpHeaderTarget<TARGET> {
private static final String TAG = "HttpHeaderDelegate";
private ENTITY mEntity;
private TASK_ENTITY mTaskEntity;
public HttpHeaderDelegate(TASK_ENTITY mTaskEntity) {
this.mTaskEntity = mTaskEntity;
mEntity = mTaskEntity.getEntity();
}
/**
* 给url请求添加Header数据
* 如果新的header数据和数据保存的不一致则更新数据库中对应的header数据
*
* @param key header对应的key
* @param value header对应的value
*/
@Override
public TARGET addHeader(@NonNull String key, @NonNull String value) {
if (TextUtils.isEmpty(key)) {
ALog.w(TAG, "设置header失败,header对应的key不能为null");
return (TARGET) this;
} else if (TextUtils.isEmpty(value)) {
ALog.w(TAG, "设置header失败,header对应的value不能为null");
return (TARGET) this;
}
if (mTaskEntity.headers.get(key) == null) {
mTaskEntity.headers.put(key, value);
mTaskEntity.update();
} else if (!mTaskEntity.headers.get(key).equals(value)) {
mTaskEntity.headers.put(key, value);
mTaskEntity.update();
}
return (TARGET) this;
}
/**
* 给url请求添加一组header数据
* 如果新的header数据和数据保存的不一致则更新数据库中对应的header数据
*
* @param headers 一组http header数据
*/
@Override
public TARGET addHeaders(@NonNull Map<String, String> headers) {
if (headers.size() == 0) {
ALog.w(TAG, "设置header失败,map没有header数据");
return (TARGET) this;
}
/*
两个map比较逻辑
1比对key是否相同
2如果key相同比对value是否相同
3只有当上面两个步骤中key value都相同时才能任务两个map数据一致
*/
boolean mapEquals = false;
if (mTaskEntity.headers.size() == headers.size()) {
int i = 0;
Set<String> keys = mTaskEntity.headers.keySet();
for (String key : keys) {
if (headers.containsKey(key)) {
i++;
} else {
break;
}
}
if (i == mTaskEntity.headers.size()) {
int j = 0;
Collection<String> values = mTaskEntity.headers.values();
for (String value : values) {
if (headers.containsValue(value)) {
j++;
} else {
break;
}
}
if (j == mTaskEntity.headers.size()) {
mapEquals = true;
}
}
}
if (!mapEquals) {
mTaskEntity.headers.clear();
Set<String> keys = headers.keySet();
for (String key : keys) {
mTaskEntity.headers.put(key, headers.get(key));
}
mTaskEntity.update();
}
return (TARGET) this;
}
/**
* 设置请求类型POST或GET默认为在GET
* 只试用于HTTP请求
*
* @param requestEnum {@link RequestEnum}
*/
@Override
public TARGET setRequestMode(RequestEnum requestEnum) {
mTaskEntity.requestEnum = requestEnum;
return (TARGET) this;
}
/**
* 如果你的下载链接的header中含有md5码信息那么你可以通过设置key来获取从header获取该md5码信息
* key默认值为Content-MD5
* 获取md5信息{@link DownloadEntity#getMd5Code()}
*/
@Override
public TARGET setHeaderMd5Key(String md5Key) {
if (TextUtils.isEmpty(md5Key)) return (TARGET) this;
mTaskEntity.md5Key = md5Key;
if (TextUtils.isEmpty(mTaskEntity.md5Key) || !mTaskEntity.md5Key.equals(md5Key)) {
mTaskEntity.update();
}
return (TARGET) this;
}
/**
* 如果你的文件长度是放在header中那么你需要配置key来让Aria知道正确的文件长度
* key默认值为Content-Length
*/
@Override
public TARGET setHeaderContentLengthKey(String contentLength) {
if (TextUtils.isEmpty(contentLength)) return (TARGET) this;
mTaskEntity.contentLength = contentLength;
if (TextUtils.isEmpty(mTaskEntity.contentLength) || !mTaskEntity.contentLength.equals(
contentLength)) {
mTaskEntity.update();
}
return (TARGET) this;
}
/**
* 如果你的下载链接的header中含有文件描述信息那么你可以通过设置key来获取从header获取该文件描述信息
* key默认值为Content-Disposition
* 获取文件描述信息{@link DownloadEntity#getDisposition()}
*/
@Override
public TARGET setHeaderDispositionKey(String dispositionKey) {
if (TextUtils.isEmpty(dispositionKey)) return (TARGET) this;
mTaskEntity.dispositionKey = dispositionKey;
if (TextUtils.isEmpty(mTaskEntity.dispositionKey) || !mTaskEntity.dispositionKey.equals(
dispositionKey)) {
mTaskEntity.update();
}
return (TARGET) this;
}
/**
* 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息你可以通过设置key来获取header中的文件名
* key默认值为attachment;filename
* 获取文件名信息{@link DownloadEntity#getServerFileName()}
*/
@Override
public TARGET setHeaderDispositionFileKey(String dispositionFileKey) {
if (TextUtils.isEmpty(dispositionFileKey)) return (TARGET) this;
mTaskEntity.dispositionFileKey = dispositionFileKey;
if (TextUtils.isEmpty(mTaskEntity.dispositionFileKey) || !mTaskEntity.dispositionFileKey.equals(
dispositionFileKey)) {
mTaskEntity.update();
}
return (TARGET) this;
}
}

@ -0,0 +1,110 @@
/*
* 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.download;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by lyy on 2017/2/28.
*/
abstract class AbsDownloadTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
static final int HTTP = 1;
static final int FTP = 2;
//HTTP任务组
static final int GROUP_HTTP = 3;
//FTP文件夹
static final int GROUP_FTP_DIR = 4;
/**
* 设置的文件保存路径的临时变量
*/
String mTempFilePath;
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
protected void setHighestPriority() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
NormalCmdFactory.TASK_HIGHEST_PRIORITY, checkTaskType()))
.exe();
}
}
/**
* 添加任务
*/
public void add() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE,
checkTaskType()))
.exe();
}
}
/**
* 重定向后新url的key默认为location
*/
public void setRedirectUrlKey(String redirectUrlKey) {
if (TextUtils.isEmpty(redirectUrlKey)) {
ALog.e("AbsDownloadTarget", "重定向后,新url的key不能为null");
return;
}
mTaskEntity.redirectUrlKey = redirectUrlKey;
}
/**
* 获取任务文件大小
*
* @return 文件大小
*/
public long getFileSize() {
return getSize();
}
/**
* 获取单位转换后的文件大小
*
* @return 文件大小{@code xxx mb}
*/
public String getConvertFileSize() {
return getConvertSize();
}
/**
* 设置target类型
*
* @return {@link #HTTP}{@link #FTP}{@link #GROUP_HTTP}{@link #GROUP_FTP_DIR}
*/
protected abstract int getTargetType();
}

@ -16,32 +16,29 @@
package com.arialyy.aria.core.download;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsDownloadTarget;
import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.manager.SubTaskManager;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ALog;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Aria.Lao on 2017/7/26.
*/
abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends AbsGroupTaskEntity>
extends AbsDownloadTarget<TARGET, DownloadGroupEntity, TASK_ENTITY> {
abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
extends AbsDownloadTarget<TARGET, DownloadGroupEntity, DownloadGroupTaskEntity> {
private static final String TAG = "BaseGroupTarget";
List<String> mUrls = new ArrayList<>();
String mGroupName;
/**
* 子任务文件
* 组任务名
*/
private List<String> mSubTaskFileName = new ArrayList<>();
String mGroupName;
/**
* 是否已经设置了文件路径
* 文件夹临时路径
*/
private boolean isSetDirPathed = false;
private String mDirPathTemp;
private SubTaskManager mSubTaskManager;
@ -67,6 +64,21 @@ abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends Abs
return (TARGET) this;
}
@Override public boolean taskExists() {
return DownloadGroupTaskQueue.getInstance().getTask(mEntity.getGroupName()) != null;
}
/**
* 设置任务组的文件夹路径该api后续会删除
*
* @param groupDirPath 任务组保存文件夹路径
* @deprecated {@link #setDirPath(String)} 请使用这个api
*/
@Deprecated
public TARGET setDownloadDirPath(String groupDirPath) {
return setDirPath(groupDirPath);
}
/**
* 设置任务组的文件夹路径在Aria中任务组的所有子任务都会下载到以任务组组名的文件夹中
* groupDirPath = "/mnt/sdcard/download/group_test"
@ -84,32 +96,16 @@ abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends Abs
* }
* </pre>
*
* @param groupDirPath 任务组保存文件夹路径
* @param dirPath 任务组保存文件夹路径
*/
public TARGET setDownloadDirPath(String groupDirPath) {
if (TextUtils.isEmpty(groupDirPath)) {
throw new NullPointerException("任务组文件夹保存路径不能为null");
}
isSetDirPathed = true;
if (mEntity.getDirPath().equals(groupDirPath)) return (TARGET) this;
File file = new File(groupDirPath);
if (file.exists() && file.isFile()) {
throw new IllegalArgumentException("路径不能为文件");
}
if (!file.exists()) {
file.mkdirs();
public TARGET setDirPath(String dirPath) {
mDirPathTemp = dirPath;
return (TARGET) this;
}
mEntity.setDirPath(groupDirPath);
if (!TextUtils.isEmpty(mEntity.getDirPath())) {
reChangeDirPath(groupDirPath);
} else {
mEntity.setSubTasks(createSubTask());
}
mEntity.update();
return (TARGET) this;
@Override public boolean isRunning() {
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
}
/**
@ -133,81 +129,38 @@ abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends Abs
DbEntity.exeSql(
"UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
}
} else {
mEntity.setSubTasks(createSubTask());
}
}
/**
* 设置子任务文件名该方法必须在{@link #setDownloadDirPath(String)}之后调用否则不生效
* 检查并设置文件夹路径
*
* @see #setSubFileName(List)
* @return {@code true} 合法
*/
@Deprecated public TARGET setSubTaskFileName(List<String> subTaskFileName) {
return setSubFileName(subTaskFileName);
}
/**
* 设置子任务文件名该方法必须在{@link #setDownloadDirPath(String)}之后调用否则不生效
*/
public TARGET setSubFileName(List<String> subTaskFileName) {
if (subTaskFileName == null || subTaskFileName.isEmpty()) return (TARGET) this;
mSubTaskFileName.addAll(subTaskFileName);
if (mUrls.size() != subTaskFileName.size()) {
throw new IllegalArgumentException("下载链接数必须要和保存路径的数量一致");
}
if (isSetDirPathed) {
List<DownloadEntity> entities = mEntity.getSubTask();
int i = 0;
for (DownloadEntity entity : entities) {
if (i < mSubTaskFileName.size()) {
String newName = mSubTaskFileName.get(i);
updateSubFileName(entity, newName);
}
i++;
}
}
return (TARGET) this;
}
/**
* 更新子任务文件名
*/
private void updateSubFileName(DownloadEntity entity, String newName) {
if (!newName.equals(entity.getFileName())) {
String oldPath = mEntity.getDirPath() + "/" + entity.getFileName();
String newPath = mEntity.getDirPath() + "/" + newName;
File oldFile = new File(oldPath);
if (oldFile.exists()) {
oldFile.renameTo(new File(newPath));
}
CommonUtil.renameDownloadConfig(oldFile.getName(), newName);
DbEntity.exeSql(
"UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
entity.setDownloadPath(newPath);
entity.setFileName(newName);
entity.update();
boolean checkDirPath() {
final String dirPath = mDirPathTemp;
if (TextUtils.isEmpty(dirPath)) {
ALog.e(TAG, "文件夹路径不能为null");
return false;
} else if (!dirPath.startsWith("/")) {
ALog.e(TAG, "文件夹路径【" + dirPath + "】错误");
return false;
}
File file = new File(dirPath);
if (file.isFile()) {
ALog.e(TAG, "路径【" + dirPath + "】是文件,请设置文件夹路径");
return false;
}
if (!mEntity.getDirPath().equals(dirPath)) {
if (!file.exists()) {
file.mkdirs();
}
mEntity.setDirPath(dirPath);
reChangeDirPath(dirPath);
mEntity.update();
}
/**
* 创建子任务
*/
private List<DownloadEntity> createSubTask() {
List<DownloadEntity> list = new ArrayList<>();
for (int i = 0, len = mUrls.size(); i < len; i++) {
DownloadEntity entity = new DownloadEntity();
entity.setUrl(mUrls.get(i));
String fileName =
mSubTaskFileName.isEmpty() ? createFileName(entity.getUrl()) : mSubTaskFileName.get(i);
entity.setDownloadPath(mEntity.getDirPath() + "/" + fileName);
entity.setGroupName(mGroupName);
entity.setGroupChild(true);
entity.setFileName(fileName);
entity.insert();
list.add(entity);
}
return list;
return true;
}
}

@ -0,0 +1,200 @@
/*
* 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.download;
import android.text.TextUtils;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
/**
* Created by Aria.Lao on 2017/7/26.
*/
abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
extends AbsDownloadTarget<TARGET, DownloadEntity, DownloadTaskEntity> {
private static final String TAG = "BaseNormalTarget";
/**
* 资源地址
*/
protected String url;
/**
* 通过实体初始化target
*/
void initTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
this.url = entity.getUrl();
mTargetName = targetName;
mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, entity);
}
mEntity = mTaskEntity.entity;
mTaskEntity.refreshInfo = refreshInfo;
}
/**
* 通过地址初始化target
*/
void initTarget(String url, String targetName, boolean refreshInfo) {
this.url = url;
mTargetName = targetName;
mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, url);
}
mEntity = mTaskEntity.entity;
mTaskEntity.refreshInfo = refreshInfo;
}
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
@Override public void setHighestPriority() {
super.setHighestPriority();
}
/**
* 下载任务是否存在
*
* @return {@code true}任务存在
*/
@Override public boolean taskExists() {
return DownloadTaskQueue.getInstance().getTask(mEntity.getUrl()) != null;
}
/**
* 获取下载实体
*/
public DownloadEntity getDownloadEntity() {
return mEntity;
}
/**
* 是否在下载该api后续版本会删除
*
* @deprecated {@link #isRunning()}
*/
@Deprecated
public boolean isDownloading() {
return isRunning();
}
/**
* 是否在下载
*
* @return {@code true}任务正在下载
*/
@Override public boolean isRunning() {
DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
}
/**
* 检查下载实体判断实体是否合法
* 合法标准为
* 1下载路径不为null并且下载路径是正常的http或ftp路径
* 2保存路径不为null并且保存路径是android文件系统路径
* 3保存路径不能重复
*
* @return {@code true}合法
*/
@Override
protected boolean checkEntity() {
return getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath();
}
/**
* 检查并设置普通任务的文件保存路径
*
* @return {@code true}保存路径合法
*/
private boolean checkFilePath() {
String filePath = mTempFilePath;
if (TextUtils.isEmpty(filePath)) {
ALog.e(TAG, "下载失败,文件保存路径为null");
return false;
} else if (!filePath.startsWith("/")) {
ALog.e(TAG, "下载失败,文件保存路径【" + filePath + "】错误");
return false;
}
File file = new File(filePath);
if (file.isDirectory()) {
if (getTargetType() == HTTP) {
ALog.e(TAG, "保存路径【" + filePath + "】不能为文件夹,路径需要是完整的文件路径,如:/mnt/sdcard/game.zip");
return false;
} else if (getTargetType() == FTP) {
filePath += mEntity.getFileName();
}
}
//设置文件保存路径,如果新文件路径和就文件路径不同,则修改路径
if (!filePath.equals(mEntity.getDownloadPath())) {
if (!mTaskEntity.refreshInfo && DbEntity.checkDataExist(DownloadEntity.class,
"downloadPath=?", filePath)) {
ALog.e(TAG, "保存路径【" + filePath + "】已经被其它任务占用,请设置其它保存路径");
return false;
}
File oldFile = new File(mEntity.getDownloadPath());
File newFile = new File(filePath);
if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) {
mEntity.setDownloadPath(filePath);
mEntity.setFileName(newFile.getName());
mTaskEntity.key = filePath;
mTaskEntity.update();
CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName());
}
}
return true;
}
/**
* 检查普通任务的下载地址
*
* @return {@code true}地址合法
*/
private boolean checkUrl() {
final String url = mEntity.getUrl();
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "下载失败,url为null");
return false;
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
ALog.e(TAG, "下载失败,url【" + url + "】错误");
return false;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "下载失败,url【" + url + "】不合法");
return false;
}
String temp = url.substring(index + 3, url.length());
if (temp.contains("//")) {
temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
mEntity.setUrl(temp);
mEntity.update();
}
return true;
}
}

@ -34,7 +34,7 @@ public class DownloadGroupEntity extends AbsGroupEntity {
/**
* 任务组下载文件的文件夹地址
*
* @see DownloadGroupTarget#setDownloadDirPath(String)
* @see DownloadGroupTarget#setDirPath(String)
*/
private String dirPath = "";

@ -15,21 +15,34 @@
*/
package com.arialyy.aria.core.download;
import com.arialyy.aria.core.inf.IEntity;
import android.text.TextUtils;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* Created by AriaL on 2017/6/29.
* 下载任务组
*/
public class DownloadGroupTarget
extends BaseGroupTarget<DownloadGroupTarget, DownloadGroupTaskEntity> {
public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
private final String TAG = "DownloadGroupTarget";
/**
* 子任务下载地址
*/
private List<String> mUrls = new ArrayList<>();
/**
* 子任务文件名
*/
private List<String> mSubNameTemp = new ArrayList<>();
DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
this.mTargetName = targetName;
@ -80,16 +93,190 @@ public class DownloadGroupTarget
* 如果你是使用{@link DownloadReceiver#load(DownloadGroupEntity)}进行下载操作那么你需要设置任务组的下载地址
*/
public DownloadGroupTarget setGroupUrl(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
mUrls.clear();
mUrls.addAll(urls);
mEntity.setGroupName(CommonUtil.getMd5Code(urls));
mEntity.update();
return this;
}
@Override public boolean isRunning() {
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
/**
* 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效
*
* @deprecated {@link #setSubFileName(List)} 请使用该api
*/
@Deprecated public DownloadGroupTarget setSubTaskFileName(List<String> subTaskFileName) {
return setSubFileName(subTaskFileName);
}
/**
* 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效
*/
public DownloadGroupTarget setSubFileName(List<String> subTaskFileName) {
if (subTaskFileName == null || subTaskFileName.isEmpty()) {
return this;
}
mSubNameTemp.clear();
mSubNameTemp.addAll(subTaskFileName);
return this;
}
/**
* 创建子任务
*/
private List<DownloadEntity> createSubTask() {
List<DownloadEntity> list = new ArrayList<>();
for (int i = 0, len = mUrls.size(); i < len; i++) {
DownloadEntity entity = new DownloadEntity();
entity.setUrl(mUrls.get(i));
String fileName =
mSubNameTemp.isEmpty() ? CommonUtil.createFileName(entity.getUrl()) : mSubNameTemp.get(i);
entity.setDownloadPath(mEntity.getDirPath() + "/" + fileName);
entity.setGroupName(mGroupName);
entity.setGroupChild(true);
entity.setFileName(fileName);
entity.insert();
list.add(entity);
}
return list;
}
@Override protected int getTargetType() {
return GROUP_HTTP;
}
@Override protected boolean checkEntity() {
if (getTargetType() == GROUP_HTTP) {
if (!checkDirPath()) {
return false;
}
if (!checkSubName()) {
return false;
}
if (!checkUrls()) {
return false;
}
//文件夹路径通过后,并且该实体没有子任务,则创建子任务
if (mEntity.getSubTask() == null || mEntity.getSubTask().isEmpty()) {
mEntity.setSubTasks(createSubTask());
mTaskEntity.update();
} else {
updateSingleSubFileName();
}
return true;
}
return false;
}
/**
* 更新所有改动的子任务文件名
*/
private void updateSingleSubFileName() {
List<DownloadEntity> entities = mEntity.getSubTask();
int i = 0;
for (DownloadEntity entity : entities) {
if (i < mSubNameTemp.size()) {
String newName = mSubNameTemp.get(i);
updateSingleSubFileName(entity, newName);
}
i++;
}
}
/**
* 检查urls是否合法并删除不合法的子任务
*
* @return {@code true} 合法
*/
private boolean checkUrls() {
if (mUrls.isEmpty()) {
ALog.e(TAG, "下载失败,子任务下载列表为null");
return false;
}
Set<Integer> delItem = new HashSet<>();
Map<Integer, String> reSetUrl = new WeakHashMap<>();
int i = 0;
for (String url : mUrls) {
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "子任务url为null,即将删除该子任务。");
delItem.add(i);
continue;
} else if (!url.startsWith("http")) {
//} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
ALog.e(TAG, "子任务url【" + url + "】错误,即将删除该子任务。");
delItem.add(i);
continue;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "子任务url【" + url + "】不合法,即将删除该子任务。");
delItem.add(i);
continue;
}
String temp = url.substring(index + 3, url.length());
if (temp.contains("//")) {
temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
reSetUrl.put(i, temp);
}
i++;
}
Set<Integer> keys = reSetUrl.keySet();
for (Integer index : keys) {
mUrls.set(index, reSetUrl.get(index));
}
for (int index : delItem) {
mUrls.remove(index);
if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) {
mSubNameTemp.remove(index);
}
}
mEntity.setGroupName(CommonUtil.getMd5Code(mUrls));
mEntity.update();
return true;
}
/**
* 更新单个子任务文件名
*/
private void updateSingleSubFileName(DownloadEntity entity, String newName) {
if (!newName.equals(entity.getFileName())) {
String oldPath = mEntity.getDirPath() + "/" + entity.getFileName();
String newPath = mEntity.getDirPath() + "/" + newName;
File oldFile = new File(oldPath);
if (oldFile.exists()) {
oldFile.renameTo(new File(newPath));
}
CommonUtil.renameDownloadConfig(oldFile.getName(), newName);
DbEntity.exeSql(
"UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
entity.setDownloadPath(newPath);
entity.setFileName(newName);
entity.update();
}
}
/**
* 如果用户设置了子任务文件名检查子任务文件名
*
* @return {@code true} 合法
*/
private boolean checkSubName() {
if (mSubNameTemp == null || mSubNameTemp.isEmpty()) {
return true;
}
if (mUrls.size() != mSubNameTemp.size()) {
ALog.e(TAG, "子任务文件名必须和子任务数量一致");
return false;
}
return true;
}
}

@ -27,7 +27,6 @@ import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.core.scheduler.ISchedulerListener;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
@ -41,7 +40,6 @@ import java.util.Set;
*/
public class DownloadReceiver extends AbsReceiver {
private final String TAG = "DownloadReceiver";
public ISchedulerListener<DownloadTask> listener;
/**
* 设置最大下载速度单位kb
@ -114,8 +112,18 @@ public class DownloadReceiver extends AbsReceiver {
/**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*
* @param urls 人刷谁
*/
@Deprecated
public DownloadGroupTarget load(List<String> urls) {
return loadGroup(urls);
}
/**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*/
public DownloadGroupTarget loadGroup(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
return new DownloadGroupTarget(urls, targetName);
}
@ -170,12 +178,24 @@ public class DownloadReceiver extends AbsReceiver {
}
/**
* 使用任务组实体执行任务组的实体执行任务组的下载操作
* 使用任务组实体执行任务组的实体执行任务组的下载操作后续版本会删除该api
*
* @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
* @deprecated {@link #loadGroup(DownloadGroupEntity)}
*/
@Deprecated
public DownloadGroupTarget load(DownloadGroupEntity groupEntity) {
return loadGroup(groupEntity);
}
/**
* 使用任务组实体执行任务组的实体执行任务组的下载操作
*
* @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
*/
public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) {
return new DownloadGroupTarget(groupEntity, targetName);
}
@ -232,7 +252,6 @@ public class DownloadReceiver extends AbsReceiver {
@Override public void destroy() {
targetName = null;
listener = null;
}
/**

@ -16,35 +16,27 @@
package com.arialyy.aria.core.download;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsDownloadTarget;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import java.util.Map;
/**
* Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria
*/
public class DownloadTarget
extends AbsDownloadTarget<DownloadTarget, DownloadEntity, DownloadTaskEntity> {
protected String url;
public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
implements IHttpHeaderTarget<DownloadTarget> {
private static final String TAG = "DownloadTarget";
private HttpHeaderDelegate<DownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
DownloadTarget(DownloadEntity entity, String targetName) {
this(entity, targetName, false);
}
DownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
this.url = entity.getUrl();
mTargetName = targetName;
mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, entity);
}
mEntity = mTaskEntity.entity;
mTaskEntity.refreshInfo = refreshInfo;
initTarget(entity, targetName, refreshInfo);
initTHis();
}
DownloadTarget(String url, String targetName) {
@ -52,14 +44,12 @@ public class DownloadTarget
}
DownloadTarget(String url, String targetName, boolean refreshInfo) {
this.url = url;
mTargetName = targetName;
mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, url);
initTarget(url, targetName, refreshInfo);
initTHis();
}
mEntity = mTaskEntity.entity;
mTaskEntity.refreshInfo = refreshInfo;
private void initTHis() {
mDelegate = new HttpHeaderDelegate<>(mTaskEntity);
}
/**
@ -75,25 +65,15 @@ public class DownloadTarget
}
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
@Override public void setHighestPriority() {
super.setHighestPriority();
}
/**
* 下载任务是否存在
* 设置文件存储路径
* 该api后续版本会删除
*
* @return {@code true}任务存在
* @param downloadPath 文件保存路径
* @deprecated {@link #setFilePath(String)} 请使用这个api
*/
@Override public boolean taskExists() {
return DownloadTaskQueue.getInstance().getTask(mEntity.getUrl()) != null;
@Deprecated
public DownloadTarget setDownloadPath(@NonNull String downloadPath) {
return setFilePath(downloadPath);
}
/**
@ -101,56 +81,49 @@ public class DownloadTarget
* 原文件路径 /mnt/sdcard/test.zip
* 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip
*
* @param downloadPath 路径必须为文件路径不能为文件夹路径
* @param filePath 路径必须为文件路径不能为文件夹路径
*/
public DownloadTarget setDownloadPath(@NonNull String downloadPath) {
if (TextUtils.isEmpty(downloadPath)) {
throw new IllegalArgumentException("文件保持路径不能为null");
public DownloadTarget setFilePath(@NonNull String filePath) {
mTempFilePath = filePath;
return this;
}
File file = new File(downloadPath);
if (file.isDirectory()) {
throw new IllegalArgumentException("保存路径不能为文件夹,路径需要是完整的文件路径,如:/mnt/sdcard/game.zip");
/**
* 从header中获取文件描述信息
*/
public String getContentDisposition() {
return mEntity.getDisposition();
}
if (!downloadPath.equals(mEntity.getDownloadPath())) {
if (!mTaskEntity.refreshInfo && DbEntity.checkDataExist(DownloadEntity.class,
"downloadPath=?", downloadPath)) {
throw new IllegalArgumentException("保存路径【" + downloadPath + "】已经被其它任务占用,请设置其它保存路径");
@Override protected int getTargetType() {
return HTTP;
}
File oldFile = new File(mEntity.getDownloadPath());
File newFile = new File(downloadPath);
if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) {
mEntity.setDownloadPath(downloadPath);
mEntity.setFileName(newFile.getName());
mTaskEntity.key = downloadPath;
mTaskEntity.update();
CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName());
@Override public DownloadTarget addHeader(@NonNull String key, @NonNull String value) {
return mDelegate.addHeader(key, value);
}
@Override public DownloadTarget addHeaders(Map<String, String> headers) {
return mDelegate.addHeaders(headers);
}
return this;
@Override public DownloadTarget setRequestMode(RequestEnum requestEnum) {
return mDelegate.setRequestMode(requestEnum);
}
public DownloadEntity getDownloadEntity() {
return mEntity;
@Override public DownloadTarget setHeaderMd5Key(String md5Key) {
return mDelegate.setHeaderMd5Key(md5Key);
}
/**
* 从header中获取文件描述信息
*/
public String getContentDisposition() {
return mEntity.getDisposition();
@Override public DownloadTarget setHeaderContentLengthKey(String contentLength) {
return mDelegate.setHeaderContentLengthKey(contentLength);
}
/**
* 是否在下载
*
* @deprecated {@link #isRunning()}
*/
public boolean isDownloading() {
return isRunning();
@Override public DownloadTarget setHeaderDispositionKey(String dispositionKey) {
return mDelegate.setHeaderDispositionKey(dispositionKey);
}
@Override public boolean isRunning() {
DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
@Override public DownloadTarget setHeaderDispositionFileKey(String dispositionFileKey) {
return mDelegate.setHeaderDispositionFileKey(dispositionFileKey);
}
}

@ -16,18 +16,20 @@
package com.arialyy.aria.core.download;
import android.text.TextUtils;
import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.util.ALog;
/**
* Created by Aria.Lao on 2017/7/26.
* ftp文件夹下载
*/
public class FtpDirDownloadTarget
extends BaseGroupTarget<FtpDirDownloadTarget, DownloadGroupTaskEntity> {
public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget> implements
IFtpTarget<FtpDirDownloadTarget> {
private final String TAG = "FtpDirDownloadTarget";
private FtpDelegate<FtpDirDownloadTarget, DownloadGroupEntity, DownloadGroupTaskEntity> mDelegate;
FtpDirDownloadTarget(String url, String targetName) {
mTargetName = targetName;
@ -42,51 +44,57 @@ public class FtpDirDownloadTarget
}
mTaskEntity.requestType = AbsTaskEntity.D_FTP_DIR;
mEntity = mTaskEntity.entity;
mDelegate = new FtpDelegate<>(mTaskEntity);
}
/**
* 设置字符编码
*/
public FtpDirDownloadTarget charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return this;
mTaskEntity.charSet = charSet;
return this;
@Override protected int getTargetType() {
return GROUP_FTP_DIR;
}
/**
* ftp 用户登录信息
*
* @param userName ftp用户名
* @param password ftp用户密码
*/
public FtpDirDownloadTarget login(String userName, String password) {
return login(userName, password, null);
@Override protected boolean checkEntity() {
return getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl();
}
/**
* ftp 用户登录信息
* 检查普通任务的下载地址
*
* @param userName ftp用户名
* @param password ftp用户密码
* @param account ftp账号
* @return {@code true}地址合法
*/
public FtpDirDownloadTarget login(String userName, String password, String account) {
if (TextUtils.isEmpty(userName)) {
ALog.e(TAG, "用户名不能为null");
return this;
} else if (TextUtils.isEmpty(password)) {
ALog.e(TAG, "密码不能为null");
return this;
private boolean checkUrl() {
final String url = mGroupName;
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "下载失败,url为null");
return false;
} else if (!url.startsWith("ftp")) {
ALog.e(TAG, "下载失败,url【" + url + "】错误");
return false;
}
mTaskEntity.urlEntity.needLogin = true;
mTaskEntity.urlEntity.user = userName;
mTaskEntity.urlEntity.password = password;
mTaskEntity.urlEntity.account = account;
return this;
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "下载失败,url【" + url + "】不合法");
return false;
}
String temp = url.substring(index + 3, url.length());
if (temp.contains("//")) {
temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
mGroupName = temp;
mEntity.setGroupName(temp);
mEntity.update();
}
return true;
}
@Override public FtpDirDownloadTarget charSet(String charSet) {
return mDelegate.charSet(charSet);
}
@Override public FtpDirDownloadTarget login(String userName, String password) {
return mDelegate.login(userName, password);
}
@Override public boolean isRunning() {
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
@Override public FtpDirDownloadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account);
}
}

@ -16,21 +16,22 @@
package com.arialyy.aria.core.download;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
/**
* Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria
*/
public class FtpDownloadTarget extends DownloadTarget {
public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
implements IFtpTarget<FtpDownloadTarget> {
private final String TAG = "FtpDownloadTarget";
private FtpDelegate<FtpDownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
super(entity, targetName, refreshInfo);
initTarget(entity, targetName, refreshInfo);
init(refreshInfo);
}
@ -39,7 +40,7 @@ public class FtpDownloadTarget extends DownloadTarget {
}
FtpDownloadTarget(String url, String targetName, boolean refreshInfo) {
super(url, targetName);
initTarget(url, targetName, refreshInfo);
init(refreshInfo);
}
@ -49,6 +50,19 @@ public class FtpDownloadTarget extends DownloadTarget {
mTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(url);
mTaskEntity.refreshInfo = refreshInfo;
mTaskEntity.requestType = AbsTaskEntity.D_FTP;
mDelegate = new FtpDelegate<>(mTaskEntity);
}
/**
* 设置文件保存文件夹路径
*
* @param filePath 文件保存路径
* @deprecated {@link #setFilePath(String)} 请使用这个api
*/
@Deprecated
public FtpDownloadTarget setDownloadPath(@NonNull String filePath) {
return setFilePath(filePath);
}
/**
@ -57,69 +71,26 @@ public class FtpDownloadTarget extends DownloadTarget {
* 1如果保存路径是该文件的保存路径/mnt/sdcard/file.zip则使用路径中的文件名file.zip
* 2如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名
*
* @param downloadPath 路径必须为文件路径不能为文件夹路径
* @param filePath 路径必须为文件路径不能为文件夹路径
*/
@Override public FtpDownloadTarget setDownloadPath(@NonNull String downloadPath) {
if (TextUtils.isEmpty(downloadPath)) {
throw new IllegalArgumentException("文件保持路径不能为null");
}
File file = new File(downloadPath);
if (file.isDirectory()) {
downloadPath += mEntity.getFileName();
}
if (!downloadPath.equals(mEntity.getDownloadPath())) {
File oldFile = new File(mEntity.getDownloadPath());
File newFile = new File(downloadPath);
if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) {
mEntity.setDownloadPath(downloadPath);
mEntity.setFileName(newFile.getName());
mTaskEntity.key = downloadPath;
mEntity.update();
mTaskEntity.update();
CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName());
}
}
public FtpDownloadTarget setFilePath(@NonNull String filePath) {
mTempFilePath = filePath;
return this;
}
/**
* 设置字符编码
*/
public FtpDownloadTarget charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return this;
mTaskEntity.charSet = charSet;
return this;
@Override protected int getTargetType() {
return FTP;
}
/**
* ftp 用户登录信息
*
* @param userName ftp用户名
* @param password ftp用户密码
*/
public FtpDownloadTarget login(String userName, String password) {
return login(userName, password, null);
@Override public FtpDownloadTarget charSet(String charSet) {
return mDelegate.charSet(charSet);
}
/**
* ftp 用户登录信息
*
* @param userName ftp用户名
* @param password ftp用户密码
* @param account ftp账号
*/
public FtpDownloadTarget login(String userName, String password, String account) {
if (TextUtils.isEmpty(userName)) {
ALog.e(TAG, "用户名不能为null");
return this;
} else if (TextUtils.isEmpty(password)) {
ALog.e(TAG, "密码不能为null");
return this;
@Override public FtpDownloadTarget login(String userName, String password) {
return mDelegate.login(userName, password);
}
mTaskEntity.urlEntity.needLogin = true;
mTaskEntity.urlEntity.user = userName;
mTaskEntity.urlEntity.password = password;
mTaskEntity.urlEntity.account = account;
return this;
@Override public FtpDownloadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account);
}
}

@ -1,151 +0,0 @@
/*
* 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.inf;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by lyy on 2017/2/28.
*/
public abstract class AbsDownloadTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
/**
* 如果你的下载链接的header中含有md5码信息那么你可以通过设置key来获取从header获取该md5码信息
* key默认值为Content-MD5
* 获取md5信息{@link DownloadEntity#getMd5Code()}
*/
public TARGET setHeaderMd5Key(String md5Key) {
if (TextUtils.isEmpty(md5Key)) return (TARGET) this;
mTaskEntity.md5Key = md5Key;
if (TextUtils.isEmpty(mTaskEntity.md5Key) || !mTaskEntity.md5Key.equals(md5Key)) {
mTaskEntity.update();
}
return (TARGET) this;
}
/**
* 如果你的文件长度是放在header中那么你需要配置key来让Aria知道正确的文件长度
* key默认值为Content-Length
*/
public TARGET setHeaderContentLengthKey(String contentLength) {
if (TextUtils.isEmpty(contentLength)) return (TARGET) this;
mTaskEntity.contentLength = contentLength;
if (TextUtils.isEmpty(mTaskEntity.contentLength) || !mTaskEntity.contentLength.equals(
contentLength)) {
mTaskEntity.update();
}
return (TARGET) this;
}
/**
* 如果你的下载链接的header中含有文件描述信息那么你可以通过设置key来获取从header获取该文件描述信息
* key默认值为Content-Disposition
* 获取文件描述信息{@link DownloadEntity#getDisposition()}
*/
public TARGET setHeaderDispositionKey(String dispositionKey) {
if (TextUtils.isEmpty(dispositionKey)) return (TARGET) this;
mTaskEntity.dispositionKey = dispositionKey;
if (TextUtils.isEmpty(mTaskEntity.dispositionKey) || !mTaskEntity.dispositionKey.equals(
dispositionKey)) {
mTaskEntity.save();
}
return (TARGET) this;
}
/**
* 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息你可以通过设置key来获取header中的文件名
* key默认值为attachment;filename
* 获取文件名信息{@link DownloadEntity#getServerFileName()}
*/
public TARGET setHeaderDispositionFileKey(String dispositionFileKey) {
if (TextUtils.isEmpty(dispositionFileKey)) return (TARGET) this;
mTaskEntity.dispositionFileKey = dispositionFileKey;
if (TextUtils.isEmpty(mTaskEntity.dispositionFileKey) || !mTaskEntity.dispositionFileKey.equals(
dispositionFileKey)) {
mTaskEntity.save();
}
return (TARGET) this;
}
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
protected void setHighestPriority() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
NormalCmdFactory.TASK_HIGHEST_PRIORITY, checkTaskType()))
.exe();
}
/**
* 重定向后新url的key默认为location
*/
public void setRedirectUrlKey(String redirectUrlKey) {
if (TextUtils.isEmpty(redirectUrlKey)) {
ALog.e("AbsDownloadTarget", "重定向后,新url的key不能为null");
return;
}
mTaskEntity.redirectUrlKey = redirectUrlKey;
}
/**
* 获取任务文件大小
*
* @return 文件大小
*/
public long getFileSize() {
return getSize();
}
/**
* 获取单位转换后的文件大小
*
* @return 文件大小{@code xxx mb}
*/
public String getConvertFileSize() {
return getConvertSize();
}
/**
* 添加任务
*/
public void add() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE,
checkTaskType()))
.exe();
}
/**
* 重新下载
*/
public void reStart() {
cancel();
start();
}
}

@ -15,13 +15,11 @@
*/
package com.arialyy.aria.core.inf;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.CancelCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.manager.TEManager;
@ -30,8 +28,6 @@ import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by AriaL on 2017/7/3.
@ -65,27 +61,12 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
}
}
/**
* 任务是否在执行
*
* @return {@code true} 任务正在执行
*/
public boolean isRunning() {
return false;
}
/**
* 任务是否存在
*/
public boolean taskExists() {
return false;
}
/**
* 获取任务进度如果任务存在则返回当前进度
*
* @return 该任务进度
*/
@Override
public long getCurrentProgress() {
return mEntity == null ? -1 : mEntity.getCurrentProgress();
}
@ -135,6 +116,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*
* @return {@link IEntity}
*/
@Override
public int getTaskState() {
return mEntity.getState();
}
@ -156,86 +138,34 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
}
/**
* 给url请求添加头部
* 检查实体是否合法
*
* @param key 头部key
* @param header 头部value
* @return {@code true} 合法
*/
public TARGET addHeader(@NonNull String key, @NonNull String header) {
return addHeader(key, header, false);
}
/**
* 给url请求添加头部
*
* @param key 头部key
* @param header 头部value
* @param refreshHeader 更新数据库中保存的头部信息
*/
public TARGET addHeader(@NonNull String key, @NonNull String header, boolean refreshHeader) {
mTaskEntity.headers.put(key, header);
if (refreshHeader) {
mTaskEntity.update();
}
return (TARGET) this;
}
protected abstract boolean checkEntity();
/**
* 给url请求添加头部
*/
public TARGET addHeaders(Map<String, String> headers) {
return addHeaders(headers, false);
}
/**
* 给url请求添加头部
*
* @param refreshHeader 更新数据库中保存的头部信息
*/
public TARGET addHeaders(Map<String, String> headers, boolean refreshHeader) {
if (headers != null && headers.size() > 0) {
Set<String> keys = headers.keySet();
for (String key : keys) {
mTaskEntity.headers.put(key, headers.get(key));
}
}
if (refreshHeader) {
mTaskEntity.update();
}
return (TARGET) this;
protected int checkTaskType() {
int taskType = 0;
if (mTaskEntity instanceof DownloadTaskEntity) {
taskType = ICmd.TASK_TYPE_DOWNLOAD;
} else if (mTaskEntity instanceof DownloadGroupTaskEntity) {
taskType = ICmd.TASK_TYPE_DOWNLOAD_GROUP;
} else if (mTaskEntity instanceof UploadTaskEntity) {
taskType = ICmd.TASK_TYPE_UPLOAD;
}
/**
* 设置请求类型POST或GET默认为在GET
* 只试用于HTTP请求
*
* @param requestEnum {@link RequestEnum}
*/
public TARGET setRequestMode(RequestEnum requestEnum) {
mTaskEntity.requestEnum = requestEnum;
return (TARGET) this;
return taskType;
}
/**
* 开始任务
*/
@Override public void start() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
checkTaskType()))
.exe();
}
protected int checkTaskType() {
int taskType = 0;
if (mTaskEntity instanceof DownloadTaskEntity) {
taskType = ICmd.TASK_TYPE_DOWNLOAD;
} else if (mTaskEntity instanceof DownloadGroupTaskEntity) {
taskType = ICmd.TASK_TYPE_DOWNLOAD_GROUP;
} else if (mTaskEntity instanceof UploadTaskEntity) {
taskType = ICmd.TASK_TYPE_UPLOAD;
}
return taskType;
}
/**
@ -244,48 +174,59 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
* @see #stop()
*/
@Deprecated public void pause() {
if (checkEntity()) {
stop();
}
}
@Override public void stop() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP,
checkTaskType()))
.exe();
}
}
/**
* 恢复任务
*/
@Override public void resume() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
checkTaskType()))
.exe();
}
}
/**
* 删除任务
*/
@Override public void cancel() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL,
checkTaskType()))
.exe();
}
}
/**
* 重试下载
* 任务重试
*/
public void reTry() {
if (checkEntity()) {
List<ICmd> cmds = new ArrayList<>();
int taskType = checkTaskType();
cmds.add(
CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP, taskType));
CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP,
taskType));
cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
taskType));
AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe();
}
}
/**
* 删除任务
@ -294,35 +235,23 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
* {@code false}如果任务已经完成只删除任务数据库记录
*/
public void cancel(boolean removeFile) {
if (checkEntity()) {
CancelCmd cancelCmd = (CancelCmd) CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
NormalCmdFactory.TASK_CANCEL, checkTaskType());
cancelCmd.removeFile = removeFile;
AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe();
}
}
/**
* 创建文件名如果url链接有后缀名则使用url中的后缀名
*
* @return url hashKey
* 重新下载
*/
protected String createFileName(String url) {
int end = url.indexOf("?");
String tempUrl, fileName = "";
if (end > 0) {
tempUrl = url.substring(0, end);
int tempEnd = tempUrl.lastIndexOf("/");
if (tempEnd > 0) {
fileName = tempUrl.substring(tempEnd + 1, tempUrl.length());
}
} else {
int tempEnd = url.lastIndexOf("/");
if (tempEnd > 0) {
fileName = url.substring(tempEnd + 1, url.length());
}
}
if (TextUtils.isEmpty(fileName)) {
fileName = CommonUtil.keyToHashKey(url);
public void reStart() {
if (checkEntity()) {
cancel();
start();
}
return fileName;
}
}

@ -1,65 +0,0 @@
/*
* 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.inf;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTask;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CheckUtil;
/**
* Created by AriaL on 2017/6/29.
* 任务组超类
*/
public abstract class AbsUploadTarget<TARGET extends AbsUploadTarget, ENTITY extends UploadEntity, TASK_ENTITY extends UploadTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
/**
* 设置上传路径
*
* @param uploadUrl 上传路径
*/
public TARGET setUploadUrl(@NonNull String uploadUrl) {
uploadUrl = CheckUtil.checkUrl(uploadUrl);
if (mEntity.getUrl().equals(uploadUrl)) return (TARGET) this;
mEntity.setUrl(uploadUrl);
mEntity.update();
return (TARGET) this;
}
/**
* 下载任务是否存在
*/
@Override public boolean taskExists() {
return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null;
}
/**
* 是否在下载
*
* @deprecated {@link #isRunning()}
*/
public boolean isUploading() {
return isRunning();
}
@Override public boolean isRunning() {
UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
}
}

@ -0,0 +1,45 @@
/*
* 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.inf;
/**
* Created by laoyuyu on 2018/3/9.
*/
public interface IFtpTarget<TARGET extends ITarget> {
/**
* 设置字符编码
*/
TARGET charSet(String charSet);
/**
* ftp 用户登录信
* 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)}
*
* @param userName ftp用户名
* @param password ftp用户密码
*/
TARGET login(String userName, String password);
/**
* ftp 用户登录信息
* 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)}
*
* @param userName ftp用户名
* @param password ftp用户密码
* @param account ftp账号
*/
TARGET login(String userName, String password, String account);
}

@ -0,0 +1,79 @@
/*
* 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.inf;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadEntity;
import java.util.Map;
/**
* Created by laoyuyu on 2018/3/9.
* HTTP Header功能接口
*/
public interface IHttpHeaderTarget<TARGET extends ITarget> {
/**
* 给url请求添加Header数据
* 如果新的header数据和数据保存的不一致则更新数据库中对应的header数据
*
* @param key header对应的key
* @param value header对应的value
*/
TARGET addHeader(@NonNull String key, @NonNull String value);
/**
* 给url请求添加一组header数据
* 如果新的header数据和数据保存的不一致则更新数据库中对应的header数据
*
* @param headers 一组http header数据
*/
TARGET addHeaders(Map<String, String> headers);
/**
* 设置HTTP请求类型
*
* @param requestEnum {@link RequestEnum}
*/
TARGET setRequestMode(RequestEnum requestEnum);
/**
* 如果你的下载链接的header中含有md5码信息那么你可以通过设置key来获取从header获取该md5码信息
* key默认值为Content-MD5
* 获取md5信息{@link DownloadEntity#getMd5Code()}
*/
TARGET setHeaderMd5Key(String md5Key);
/**
* 如果你的文件长度是放在header中那么你需要配置key来让Aria知道正确的文件长度
* key默认值为Content-Length
*/
TARGET setHeaderContentLengthKey(String contentLength);
/**
* 如果你的下载链接的header中含有文件描述信息那么你可以通过设置key来获取从header获取该文件描述信息
* key默认值为Content-Disposition
* 获取文件描述信息{@link DownloadEntity#getDisposition()}
*/
TARGET setHeaderDispositionKey(String dispositionKey);
/**
* 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息你可以通过设置key来获取header中的文件名
* key默认值为attachment;filename
* 获取文件名信息{@link DownloadEntity#getServerFileName()}
*/
TARGET setHeaderDispositionFileKey(String dispositionFileKey);
}

@ -15,53 +15,51 @@
*/
package com.arialyy.aria.core.inf;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum;
import java.util.Map;
/**
* Created by AriaL on 2017/6/29.
*/
public interface ITarget<TARGET extends ITarget> {
/**
* 任务文件大小
* 获取任务状态
*
* @return {@link IEntity}
*/
long getSize();
int getTaskState();
/**
* 转换后的大小
* 任务是否在执行
*
* @return {@code true} 任务正在执行
*/
String getConvertSize();
boolean isRunning();
/**
* 获取任务进度百分比
* 任务是否存在
*
* @return {@code true} 任务存在
*/
int getPercent();
boolean taskExists();
/**
* 获取任务进度如果任务存在则返回当前进度
* 任务文件大小
*/
long getCurrentProgress();
long getSize();
/**
* 给url请求添加头部
*
* @param key 头部key
* @param header 头部value
* 转换后的大小
*/
TARGET addHeader(@NonNull String key, @NonNull String header) ;
String getConvertSize();
/**
* 给url请求添加头部
* 获取任务进度百分比
*/
TARGET addHeaders(Map<String, String> headers);
int getPercent();
/**
* 设置请求类型
*
* @param requestEnum {@link RequestEnum}
* 获取任务进度如果任务存在则返回当前进度
*/
TARGET setRequestMode(RequestEnum requestEnum);
long getCurrentProgress();
/**
* 开始下载
@ -82,5 +80,4 @@ public interface ITarget<TARGET extends ITarget> {
* 取消下载
*/
void cancel();
}

@ -150,10 +150,10 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
}
}
@Override public TASK getTask(String url) {
TASK task = mExecutePool.getTask(url);
@Override public TASK getTask(String key) {
TASK task = mExecutePool.getTask(key);
if (task == null) {
task = mCachePool.getTask(url);
task = mCachePool.getTask(key);
}
return task;
}

@ -0,0 +1,28 @@
/*
* 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.upload;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskEntity;
/**
* Created by AriaL on 2017/6/29.
*/
abstract class AbsUploadTarget<TARGET extends AbsUploadTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
}

@ -0,0 +1,139 @@
/*
* 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.upload;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.util.ALog;
import java.io.File;
/**
* Created by AriaL on 2018/3/9.
*/
abstract class BaseNormalTarget<TARGET extends AbsUploadTarget>
extends AbsUploadTarget<TARGET, UploadEntity, UploadTaskEntity> {
private static final String TAG = "BaseNormalTarget";
protected void initTarget(String filePath) {
mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, filePath);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(UploadTaskEntity.class, filePath);
}
mEntity = mTaskEntity.entity;
File file = new File(filePath);
mEntity.setFileName(file.getName());
mEntity.setFileSize(file.length());
}
/**
* 设置上传路径
*
* @param uploadUrl 上传路径
*/
public abstract TARGET setUploadUrl(@NonNull String uploadUrl);
/**
* 上传任务是否存在
*
* @return {@code true}存在
*/
@Override public boolean taskExists() {
return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null;
}
/**
* 是否在上传
*
* @deprecated {@link #isRunning()}
*/
public boolean isUploading() {
return isRunning();
}
@Override public boolean isRunning() {
UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
}
@Override protected boolean checkEntity() {
return checkUrl() && checkFilePath();
}
/**
* 检查上传文件路径是否合法
*
* @return {@code true} 合法
*/
private boolean checkFilePath() {
String filePath = mEntity.getFilePath();
if (TextUtils.isEmpty(filePath)) {
ALog.e(TAG, "上传失败,文件路径为null");
return false;
} else if (!filePath.startsWith("/")) {
ALog.e(TAG, "上传失败,文件路径【" + filePath + "】不合法");
return false;
}
File file = new File(mEntity.getFilePath());
if (!file.exists()) {
ALog.e(TAG, "上传失败,文件【" + filePath + "】不存在");
return false;
}
if (file.isDirectory()) {
ALog.e(TAG, "上传失败,文件【" + filePath + "】不能死文件夹");
return false;
}
if (filePath.contains("//")) {
filePath = filePath.replaceAll("//", "/");
ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + filePath);
mEntity.setFilePath(filePath);
mEntity.update();
}
return true;
}
/**
* 检查普通任务的下载地址
*
* @return {@code true}地址合法
*/
private boolean checkUrl() {
final String url = mEntity.getUrl();
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "上传失败,url为null");
return false;
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
ALog.e(TAG, "上传失败,url【" + url + "】错误");
return false;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "上传失败,url【" + url + "】不合法");
return false;
}
String temp = url.substring(index + 3, url.length());
if (temp.contains("//")) {
temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
mEntity.setUrl(temp);
mEntity.update();
}
return true;
}
}

@ -16,13 +16,12 @@
package com.arialyy.aria.core.upload;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.AbsUploadTarget;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
@ -31,9 +30,10 @@ import java.io.File;
* Created by Aria.Lao on 2017/7/27.
* ftp单任务上传
*/
public class FtpUploadTarget
extends AbsUploadTarget<FtpUploadTarget, UploadEntity, UploadTaskEntity> {
public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
implements IFtpTarget<FtpUploadTarget> {
private final String TAG = "FtpUploadTarget";
private FtpDelegate<FtpUploadTarget, UploadEntity, UploadTaskEntity> mDelegate;
FtpUploadTarget(String filePath, String targetName) {
this.mTargetName = targetName;
@ -41,15 +41,9 @@ public class FtpUploadTarget
}
private void initTask(String filePath) {
mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, filePath);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(UploadTaskEntity.class, filePath);
}
mEntity = mTaskEntity.entity;
File file = new File(filePath);
mEntity.setFileName(file.getName());
mEntity.setFileSize(file.length());
initTarget(filePath);
mTaskEntity.requestType = AbsTaskEntity.U_FTP;
mDelegate = new FtpDelegate<>(mTaskEntity);
}
/**
@ -57,6 +51,7 @@ public class FtpUploadTarget
*
* @param uploadUrl 上传路径
*/
@Override
public FtpUploadTarget setUploadUrl(@NonNull String uploadUrl) {
uploadUrl = CheckUtil.checkUrl(uploadUrl);
if (!uploadUrl.endsWith("/")) {
@ -69,56 +64,27 @@ public class FtpUploadTarget
return this;
}
/**
* 设置字符编码
*/
public FtpUploadTarget charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return this;
mTaskEntity.charSet = charSet;
return this;
}
/**
* ftp 用户登录信
* 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)}
*
* @param userName ftp用户名
* @param password ftp用户密码
*/
public FtpUploadTarget login(String userName, String password) {
return login(userName, password, null);
}
/**
* ftp 用户登录信息
* 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)}
*
* @param userName ftp用户名
* @param password ftp用户密码
* @param account ftp账号
*/
public FtpUploadTarget login(String userName, String password, String account) {
if (TextUtils.isEmpty(userName)) {
ALog.e(TAG, "用户名不能为null");
return this;
} else if (TextUtils.isEmpty(password)) {
ALog.e(TAG, "密码不能为null");
return this;
}
mTaskEntity.urlEntity.needLogin = true;
mTaskEntity.urlEntity.user = userName;
mTaskEntity.urlEntity.password = password;
mTaskEntity.urlEntity.account = account;
return this;
}
/**
* 添加任务
*/
public void add() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE,
checkTaskType()))
.exe();
}
}
@Override public FtpUploadTarget charSet(String charSet) {
return mDelegate.charSet(charSet);
}
@Override public FtpUploadTarget login(String userName, String password) {
return mDelegate.login(userName, password);
}
@Override public FtpUploadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account);
}
}

@ -36,7 +36,6 @@ import java.util.Set;
*/
public class UploadReceiver extends AbsReceiver<UploadEntity> {
private static final String TAG = "UploadReceiver";
public ISchedulerListener<UploadTask> listener;
/**
* 加载HTTP单文件上传任务
@ -104,7 +103,6 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
@Override public void destroy() {
targetName = null;
listener = null;
}
/**

@ -16,16 +16,21 @@
package com.arialyy.aria.core.upload;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.inf.AbsUploadTarget;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import java.io.File;
import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import com.arialyy.aria.util.CheckUtil;
import java.util.Map;
/**
* Created by lyy on 2017/2/28.
* http 文件上传
* http 文件上传
*/
public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, UploadTaskEntity> {
public class UploadTarget extends BaseNormalTarget<UploadTarget>
implements IHttpHeaderTarget<UploadTarget> {
private static final String TAG = "UploadTarget";
private HttpHeaderDelegate<UploadTarget, UploadEntity, UploadTaskEntity> mDelegate;
UploadTarget(String filePath, String targetName) {
this.mTargetName = targetName;
@ -33,17 +38,22 @@ public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, Up
}
private void initTask(String filePath) {
mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, filePath);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(UploadTaskEntity.class, filePath);
}
mEntity = mTaskEntity.entity;
File file = new File(filePath);
mEntity.setFileName(file.getName());
mEntity.setFileSize(file.length());
initTarget(filePath);
//http暂时不支持断点上传
mTaskEntity.isSupportBP = false;
mTaskEntity.requestType = AbsTaskEntity.U_HTTP;
mDelegate = new HttpHeaderDelegate<>(mTaskEntity);
}
@Override public UploadTarget setUploadUrl(@NonNull String uploadUrl) {
uploadUrl = CheckUtil.checkUrl(uploadUrl);
if (mEntity.getUrl().equals(uploadUrl)) {
return this;
}
mEntity.setUrl(uploadUrl);
mEntity.update();
return this;
}
/**
@ -73,4 +83,32 @@ public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, Up
mTaskEntity.contentType = contentType;
return this;
}
@Override public UploadTarget addHeader(@NonNull String key, @NonNull String value) {
return mDelegate.addHeader(key, value);
}
@Override public UploadTarget addHeaders(Map<String, String> headers) {
return mDelegate.addHeaders(headers);
}
@Override public UploadTarget setRequestMode(RequestEnum requestEnum) {
return mDelegate.setRequestMode(requestEnum);
}
@Override public UploadTarget setHeaderMd5Key(String md5Key) {
return mDelegate.setHeaderMd5Key(md5Key);
}
@Override public UploadTarget setHeaderContentLengthKey(String contentLength) {
return mDelegate.setHeaderContentLengthKey(contentLength);
}
@Override public UploadTarget setHeaderDispositionKey(String dispositionKey) {
return mDelegate.setHeaderDispositionKey(dispositionKey);
}
@Override public UploadTarget setHeaderDispositionFileKey(String dispositionFileKey) {
return mDelegate.setHeaderDispositionFileKey(dispositionFileKey);
}
}

@ -109,6 +109,34 @@ public class CheckUtil {
return url;
}
///**
// * 检查普通任务的下载地址
// *
// * @return {@code true}地址合法
// */
//public static boolean checkUrl(DownloadEntity entity, String url) {
// if (TextUtils.isEmpty(url)) {
// ALog.e(TAG, "下载失败,url为null");
// return false;
// } else if (!url.startsWith("http") && !url.startsWith("ftp")) {
// ALog.e(TAG, "下载失败,url【" + url + "】错误");
// return false;
// }
// int index = url.indexOf("://");
// if (index == -1) {
// ALog.e(TAG, "下载失败,url【" + url + "】不合法");
// return false;
// }
// String temp = url.substring(index + 3, url.length());
// if (temp.contains("//")) {
// temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
// ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
// entity.setUrl(temp);
// entity.update();
// }
// return true;
//}
/**
* 检测下载链接组是否为null
*/

@ -73,6 +73,32 @@ import java.util.regex.Pattern;
public class CommonUtil {
private static final String TAG = "CommonUtil";
/**
* 创建文件名如果url链接有后缀名则使用url中的后缀名
*
* @return url hashKey
*/
public static String createFileName(String url) {
int end = url.indexOf("?");
String tempUrl, fileName = "";
if (end > 0) {
tempUrl = url.substring(0, end);
int tempEnd = tempUrl.lastIndexOf("/");
if (tempEnd > 0) {
fileName = tempUrl.substring(tempEnd + 1, tempUrl.length());
}
} else {
int tempEnd = url.lastIndexOf("/");
if (tempEnd > 0) {
fileName = url.substring(tempEnd + 1, url.length());
}
}
if (TextUtils.isEmpty(fileName)) {
fileName = CommonUtil.keyToHashKey(url);
}
return fileName;
}
/**
* 分割获取url协议ip/域名端口内容
*

@ -80,7 +80,7 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
case R.id.start:
Aria.download(this)
.load(mUrls)
.setDownloadDirPath(
.setDirPath(
Environment.getExternalStorageDirectory().getPath() + "/Download/group_test_3")
.setGroupAlias("任务组测试")
.setSubFileName(getModule(GroupModule.class).getSubName())

@ -66,7 +66,7 @@ public class FTPDirDownloadActivity extends BaseActivity<ActivityDownloadGroupBi
case R.id.start:
Aria.download(this)
.loadFtpDir(dir)
.setDownloadDirPath(
.setDirPath(
Environment.getExternalStorageDirectory().getPath() + "/Download/ftp_dir")
.setGroupAlias("ftp文件夹下载")
//.setSubTaskFileName(getModule(GroupModule.class).getSubName())

Loading…
Cancel
Save