diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/AbsDGTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDGTarget.java index d5d0257a..c51871cc 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/AbsDGTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDGTarget.java @@ -33,18 +33,18 @@ import java.util.List; */ abstract class AbsDGTarget extends AbsTarget { - /** - * 组任务名 - */ - String mGroupHash; - /** - * 文件夹临时路径 - */ - String mDirPathTemp; - /** - * 是否需要修改路径 - */ - boolean needModifyPath = false; + ///** + // * 组任务名 + // */ + //String mGroupHash; + ///** + // * 文件夹临时路径 + // */ + //String mDirPathTemp; + ///** + // * 是否需要修改路径 + // */ + //boolean needModifyPath = false; private SubTaskManager mSubTaskManager; @@ -79,93 +79,93 @@ abstract class AbsDGTarget extends AbsTarget return (TARGET) this; } - @Override public boolean taskExists() { - return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", mGroupHash); - } + //@Override public boolean taskExists() { + // return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", mGroupHash); + //} - /** - * 设置任务组的文件夹路径,在Aria中,任务组的所有子任务都会下载到以任务组组名的文件夹中。 - * 如:groupDirPath = "/mnt/sdcard/download/group_test" - *
-   *   {@code
-   *      + mnt
-   *        + sdcard
-   *          + download
-   *            + group_test
-   *              - task1.apk
-   *              - task2.apk
-   *              - task3.apk
-   *              ....
-   *
-   *   }
-   * 
- * - * @param dirPath 任务组保存文件夹路径 - */ - @CheckResult - public TARGET setDirPath(String dirPath) { - mDirPathTemp = dirPath; - return (TARGET) this; - } + ///** + // * 设置任务组的文件夹路径,在Aria中,任务组的所有子任务都会下载到以任务组组名的文件夹中。 + // * 如:groupDirPath = "/mnt/sdcard/download/group_test" + // *
+  // *   {@code
+  // *      + mnt
+  // *        + sdcard
+  // *          + download
+  // *            + group_test
+  // *              - task1.apk
+  // *              - task2.apk
+  // *              - task3.apk
+  // *              ....
+  // *
+  // *   }
+  // * 
+ // * + // * @param dirPath 任务组保存文件夹路径 + // */ + //@CheckResult + //public TARGET setDirPath(String dirPath) { + // mDirPathTemp = dirPath; + // return (TARGET) this; + //} - @Override public boolean isRunning() { - DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(getEntity().getKey()); - return task != null && task.isRunning(); - } + //@Override public boolean isRunning() { + // DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(getEntity().getKey()); + // return task != null && task.isRunning(); + //} - /** - * 改变任务组文件夹路径,修改文件夹路径会将子任务所有路径更换 - * - * @param newDirPath 新的文件夹路径 - */ - void reChangeDirPath(String newDirPath) { - List subTasks = getTaskWrapper().getSubTaskWrapper(); - if (subTasks != null && !subTasks.isEmpty()) { - List des = new ArrayList<>(); - for (DTaskWrapper dte : subTasks) { - DownloadEntity de = dte.getEntity(); - String oldPath = de.getDownloadPath(); - String newPath = newDirPath + "/" + de.getFileName(); - File file = new File(oldPath); - if (file.exists()) { - file.renameTo(new File(newPath)); - } - de.setDownloadPath(newPath); - des.add(de); - } - AbsEntity.saveAll(des); - } - } - - /** - * 检查并设置文件夹路径 - * - * @return {@code true} 合法 - */ - boolean checkDirPath() { - if (TextUtils.isEmpty(mDirPathTemp)) { - ALog.e(TAG, "文件夹路径不能为null"); - return false; - } else if (!mDirPathTemp.startsWith("/")) { - ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误"); - return false; - } - File file = new File(mDirPathTemp); - if (file.isFile()) { - ALog.e(TAG, "路径【" + mDirPathTemp + "】是文件,请设置文件夹路径"); - return false; - } + ///** + // * 改变任务组文件夹路径,修改文件夹路径会将子任务所有路径更换 + // * + // * @param newDirPath 新的文件夹路径 + // */ + //void reChangeDirPath(String newDirPath) { + // List subTasks = getTaskWrapper().getSubTaskWrapper(); + // if (subTasks != null && !subTasks.isEmpty()) { + // List des = new ArrayList<>(); + // for (DTaskWrapper dte : subTasks) { + // DownloadEntity de = dte.getEntity(); + // String oldPath = de.getDownloadPath(); + // String newPath = newDirPath + "/" + de.getFileName(); + // File file = new File(oldPath); + // if (file.exists()) { + // file.renameTo(new File(newPath)); + // } + // de.setDownloadPath(newPath); + // des.add(de); + // } + // AbsEntity.saveAll(des); + // } + //} - if (TextUtils.isEmpty(getEntity().getDirPath()) || !getEntity().getDirPath() - .equals(mDirPathTemp)) { - if (!file.exists()) { - file.mkdirs(); - } - needModifyPath = true; - getEntity().setDirPath(mDirPathTemp); - ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mDirPathTemp)); - } - - return true; - } + ///** + // * 检查并设置文件夹路径 + // * + // * @return {@code true} 合法 + // */ + //boolean checkDirPath() { + // if (TextUtils.isEmpty(mDirPathTemp)) { + // ALog.e(TAG, "文件夹路径不能为null"); + // return false; + // } else if (!mDirPathTemp.startsWith("/")) { + // ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误"); + // return false; + // } + // File file = new File(mDirPathTemp); + // if (file.isFile()) { + // ALog.e(TAG, "路径【" + mDirPathTemp + "】是文件,请设置文件夹路径"); + // return false; + // } + // + // if (TextUtils.isEmpty(getEntity().getDirPath()) || !getEntity().getDirPath() + // .equals(mDirPathTemp)) { + // if (!file.exists()) { + // file.mkdirs(); + // } + // needModifyPath = true; + // getEntity().setDirPath(mDirPathTemp); + // ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mDirPathTemp)); + // } + // + // return true; + //} } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDTarget.java similarity index 93% rename from Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java rename to Aria/src/main/java/com/arialyy/aria/core/download/AbsDTarget.java index 9cca1f8e..121c1d37 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDTarget.java @@ -23,7 +23,7 @@ import com.arialyy.aria.util.CommonUtil; /** * Created by lyy on 2017/2/28. */ -abstract class AbsDownloadTarget extends AbsTarget { +abstract class AbsDTarget extends AbsTarget { /** * 更新下载url diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/AbsGroupDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/download/AbsGroupDelegate.java new file mode 100644 index 00000000..b2fe174b --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/AbsGroupDelegate.java @@ -0,0 +1,159 @@ +/* + * 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.support.annotation.CheckResult; +import android.text.TextUtils; +import com.arialyy.aria.core.inf.AbsEntity; +import com.arialyy.aria.core.inf.IGroupTarget; +import com.arialyy.aria.core.queue.DownloadGroupTaskQueue; +import com.arialyy.aria.orm.DbEntity; +import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by lyy on 2019/4/9. + * 下载组合任务功能 + */ +abstract class AbsGroupDelegate implements IGroupTarget { + protected String TAG; + private TARGET mTarget; + private DGTaskWrapper mWrapper; + /** + * 组任务名 + */ + private String mGroupHash; + /** + * 文件夹临时路径 + */ + private String mDirPathTemp; + /** + * 是否需要修改路径 + */ + private boolean needModifyPath = false; + + AbsGroupDelegate(TARGET target, DGTaskWrapper wrapper) { + TAG = CommonUtil.getClassName(getClass()); + mTarget = target; + mWrapper = wrapper; + setGroupHash(wrapper.getKey()); + mTarget.setTaskWrapper(wrapper); + if (getEntity() != null) { + mDirPathTemp = getEntity().getDirPath(); + } + } + + @Override public boolean isRunning() { + DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(getEntity().getKey()); + return task != null && task.isRunning(); + } + + @CheckResult + TARGET setDirPath(String dirPath) { + mDirPathTemp = dirPath; + return mTarget; + } + + /** + * 改变任务组文件夹路径,修改文件夹路径会将子任务所有路径更换 + * + * @param newDirPath 新的文件夹路径 + */ + void reChangeDirPath(String newDirPath) { + List subTasks = mWrapper.getSubTaskWrapper(); + if (subTasks != null && !subTasks.isEmpty()) { + List des = new ArrayList<>(); + for (DTaskWrapper dte : subTasks) { + DownloadEntity de = dte.getEntity(); + String oldPath = de.getDownloadPath(); + String newPath = newDirPath + "/" + de.getFileName(); + File file = new File(oldPath); + if (file.exists()) { + file.renameTo(new File(newPath)); + } + de.setDownloadPath(newPath); + des.add(de); + } + AbsEntity.saveAll(des); + } + } + + /** + * 检查并设置文件夹路径 + * + * @return {@code true} 合法 + */ + @Override public boolean checkDirPath() { + if (TextUtils.isEmpty(mDirPathTemp)) { + ALog.e(TAG, "文件夹路径不能为null"); + return false; + } else if (!mDirPathTemp.startsWith("/")) { + ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误"); + return false; + } + File file = new File(mDirPathTemp); + if (file.isFile()) { + ALog.e(TAG, "路径【" + mDirPathTemp + "】是文件,请设置文件夹路径"); + return false; + } + + if (TextUtils.isEmpty(getEntity().getDirPath()) || !getEntity().getDirPath() + .equals(mDirPathTemp)) { + if (!file.exists()) { + file.mkdirs(); + } + needModifyPath = true; + getEntity().setDirPath(mDirPathTemp); + ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mDirPathTemp)); + } + return true; + } + + @Override public DownloadGroupEntity getEntity() { + return mWrapper.getEntity(); + } + + @Override public boolean taskExists() { + return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", mWrapper.getKey()); + } + + DGTaskWrapper getTaskWrapper() { + return mWrapper; + } + + boolean isNeedModifyPath() { + return needModifyPath; + } + + String getDirPathTemp() { + return mDirPathTemp; + } + + TARGET getTarget() { + return mTarget; + } + + public String getGroupHash() { + return mGroupHash; + } + + public void setGroupHash(String groupHash) { + this.mGroupHash = groupHash; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DNormalDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/download/DNormalDelegate.java index a4e32c2d..5b24c8a8 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DNormalDelegate.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DNormalDelegate.java @@ -17,7 +17,7 @@ package com.arialyy.aria.core.download; import android.text.TextUtils; import com.arialyy.aria.core.inf.ITargetHandler; -import com.arialyy.aria.core.inf.ITargetNormal; +import com.arialyy.aria.core.inf.INormalTarget; import com.arialyy.aria.core.manager.TaskWrapperManager; import com.arialyy.aria.core.queue.DownloadTaskQueue; import com.arialyy.aria.orm.DbEntity; @@ -29,7 +29,7 @@ import java.io.File; * Created by AriaL on 2019/4/5. * 普通下载任务通用功能处理 */ -class DNormalDelegate implements ITargetNormal { +class DNormalDelegate implements INormalTarget { private final String TAG = "DNormalDelegate"; private DownloadEntity mEntity; @@ -54,7 +54,7 @@ class DNormalDelegate implements ITargetNormal initTarget(url, targetName); } - @Override public void initTarget(String url, String targetName) { + private void initTarget(String url, String targetName) { DTaskWrapper taskWrapper = TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, url); mEntity = taskWrapper.getEntity(); @@ -67,7 +67,7 @@ class DNormalDelegate implements ITargetNormal } } - @Override public TARGET updateUrl(String newUrl) { + TARGET updateUrl(String newUrl) { if (TextUtils.isEmpty(newUrl)) { ALog.e(TAG, "url更新失败,newUrl为null"); return mTarget; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java index c43710dd..bf38e13a 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java @@ -17,21 +17,15 @@ package com.arialyy.aria.core.download; import android.support.annotation.CheckResult; import android.support.annotation.NonNull; -import android.text.TextUtils; -import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.http.HttpHeaderDelegate; import com.arialyy.aria.core.common.http.PostDelegate; import com.arialyy.aria.core.inf.IHttpHeaderDelegate; import com.arialyy.aria.core.manager.TaskWrapperManager; -import com.arialyy.aria.orm.DbEntity; +import com.arialyy.aria.exception.ParamException; import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.CommonUtil; import java.net.Proxy; -import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; /** * Created by AriaL on 2017/6/29. @@ -39,43 +33,33 @@ import java.util.Set; */ public class DownloadGroupTarget extends AbsDGTarget implements IHttpHeaderDelegate { - private HttpHeaderDelegate mDelegate; - /** - * 子任务下载地址, - */ - private List mUrls = new ArrayList<>(); - - /** - * 子任务文件名 - */ - private List mSubNameTemp = new ArrayList<>(); + private HttpHeaderDelegate mHeaderDelegate; + private HttpGroupDelegate mGroupDelegate; - public DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) { + DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) { setTargetName(targetName); if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) { - this.mUrls.addAll(groupEntity.getUrls()); + init(groupEntity.getUrls()); + } else { + throw new ParamException("组合任务只任务下载地址为空"); } - init(); } DownloadGroupTarget(List urls, String targetName) { setTargetName(targetName); - this.mUrls = urls; - init(); + init(urls); } - private void init() { - mGroupHash = CommonUtil.getMd5Code(mUrls); - setTaskWrapper(TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, mUrls)); - if (getEntity() != null) { - mDirPathTemp = getEntity().getDirPath(); - } - mDelegate = new HttpHeaderDelegate<>(this); + private void init(List urls) { + mGroupDelegate = new HttpGroupDelegate(this, + TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, urls)); + mHeaderDelegate = new HttpHeaderDelegate<>(this); } /** * Post处理 */ + @CheckResult public PostDelegate asPost() { return new PostDelegate<>(this); } @@ -87,24 +71,7 @@ public class DownloadGroupTarget extends AbsDGTarget implem */ @CheckResult public DownloadGroupTarget updateUrls(List urls) { - if (urls == null || urls.isEmpty()) { - throw new NullPointerException("下载地址列表为空"); - } - if (urls.size() != mUrls.size()) { - throw new IllegalArgumentException("新下载地址数量和旧下载地址数量不一致"); - } - mUrls.clear(); - mUrls.addAll(urls); - mGroupHash = CommonUtil.getMd5Code(urls); - getEntity().setGroupHash(mGroupHash); - getEntity().update(); - if (getEntity().getSubEntities() != null && !getEntity().getSubEntities().isEmpty()) { - for (DownloadEntity de : getEntity().getSubEntities()) { - de.setGroupHash(mGroupHash); - de.update(); - } - } - return this; + return mGroupDelegate.updateUrls(urls); } /** @@ -132,9 +99,7 @@ public class DownloadGroupTarget extends AbsDGTarget implem */ @CheckResult public DownloadGroupTarget setGroupUrl(List urls) { - mUrls.clear(); - mUrls.addAll(urls); - return this; + return mGroupDelegate.setGroupUrl(urls); } /** @@ -147,22 +112,36 @@ public class DownloadGroupTarget extends AbsDGTarget implem return setSubFileName(subTaskFileName); } + /** + * 设置任务组的文件夹路径,在Aria中,任务组的所有子任务都会下载到以任务组组名的文件夹中。 + * 如:groupDirPath = "/mnt/sdcard/download/group_test" + *
+   *   {@code
+   *      + mnt
+   *        + sdcard
+   *          + download
+   *            + group_test
+   *              - task1.apk
+   *              - task2.apk
+   *              - task3.apk
+   *              ....
+   *
+   *   }
+   * 
+ * + * @param dirPath 任务组保存文件夹路径 + */ + @CheckResult + public DownloadGroupTarget setDirPath(String dirPath) { + return mGroupDelegate.setDirPath(dirPath); + } + /** * 设置子任务文件名,该方法必须在{@link #setDirPath(String)}之后调用,否则不生效 */ @CheckResult public DownloadGroupTarget setSubFileName(List subTaskFileName) { - if (subTaskFileName == null || subTaskFileName.isEmpty()) { - ALog.e(TAG, "修改子任务的文件名失败:列表为null"); - return this; - } - if (subTaskFileName.size() != getTaskWrapper().getSubTaskWrapper().size()) { - ALog.e(TAG, "修改子任务的文件名失败:子任务文件名列表数量和子任务的数量不匹配"); - return this; - } - mSubNameTemp.clear(); - mSubNameTemp.addAll(subTaskFileName); - return this; + return mGroupDelegate.setSubFileName(subTaskFileName); } @Override public int getTargetType() { @@ -170,161 +149,35 @@ public class DownloadGroupTarget extends AbsDGTarget implem } @Override protected boolean checkEntity() { - if (getTargetType() == GROUP_HTTP) { - if (!checkDirPath()) { - return false; - } - - if (!checkSubName()) { - return false; - } - - if (!checkUrls()) { - return false; - } - - if (getTaskWrapper().getEntity().getFileSize() == 0) { - ALog.e(TAG, "组合任务必须设置文件文件大小"); - return false; - } - - if (getTaskWrapper().asHttp().getRequestEnum() == RequestEnum.POST) { - for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) { - subTask.asHttp().setRequestEnum(RequestEnum.POST); - } - } - - getEntity().save(); - - if (needModifyPath) { - reChangeDirPath(mDirPathTemp); - } - - if (!mSubNameTemp.isEmpty()) { - updateSingleSubFileName(); - } - return true; - } - return false; - } - - /** - * 更新所有改动的子任务文件名 - */ - private void updateSingleSubFileName() { - List entities = getTaskWrapper().getSubTaskWrapper(); - int i = 0; - for (DTaskWrapper 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 delItem = new HashSet<>(); - - 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; - } - - i++; - } - - for (int index : delItem) { - mUrls.remove(index); - if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) { - mSubNameTemp.remove(index); - } - } - - getEntity().setGroupHash(CommonUtil.getMd5Code(mUrls)); - - return true; + return mGroupDelegate.checkEntity(); } - /** - * 更新单个子任务文件名 - */ - private void updateSingleSubFileName(DTaskWrapper taskEntity, String newName) { - DownloadEntity entity = taskEntity.getEntity(); - if (!newName.equals(entity.getFileName())) { - String oldPath = getEntity().getDirPath() + "/" + entity.getFileName(); - String newPath = getEntity().getDirPath() + "/" + newName; - if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=? or isComplete='true'", - newPath)) { - ALog.w(TAG, String.format("更新文件名失败,路径【%s】已存在或文件已下载", newPath)); - return; - } - - CommonUtil.modifyTaskRecord(oldPath, newPath); - entity.setDownloadPath(newPath); - entity.setFileName(newName); - entity.update(); - } + @Override public boolean isRunning() { + return mGroupDelegate.isRunning(); } - /** - * 如果用户设置了子任务文件名,检查子任务文件名 - * - * @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; + @Override public boolean taskExists() { + return mGroupDelegate.taskExists(); } @CheckResult @Override public DownloadGroupTarget addHeader(@NonNull String key, @NonNull String value) { for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) { - mDelegate.addHeader(subTask, key, value); + mHeaderDelegate.addHeader(subTask, key, value); } - return mDelegate.addHeader(key, value); + return mHeaderDelegate.addHeader(key, value); } @CheckResult @Override public DownloadGroupTarget addHeaders(Map headers) { for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) { - mDelegate.addHeaders(subTask, headers); + mHeaderDelegate.addHeaders(subTask, headers); } - return mDelegate.addHeaders(headers); + return mHeaderDelegate.addHeaders(headers); } @CheckResult @Override public DownloadGroupTarget setUrlProxy(Proxy proxy) { - return mDelegate.setUrlProxy(proxy); + return mHeaderDelegate.setUrlProxy(proxy); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java index d5814539..3ccbeba3 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java @@ -1,475 +1,475 @@ -/* - * 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.support.annotation.CheckResult; -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.CancelAllCmd; -import com.arialyy.aria.core.command.normal.NormalCmdFactory; -import com.arialyy.aria.core.common.ProxyHelper; -import com.arialyy.aria.core.inf.AbsEntity; -import com.arialyy.aria.core.inf.AbsReceiver; -import com.arialyy.aria.core.inf.ReceiverType; -import com.arialyy.aria.core.manager.TaskWrapperManager; -import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers; -import com.arialyy.aria.core.scheduler.DownloadSchedulers; -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.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * Created by lyy on 2016/12/5. - * 下载功能接收器 - */ -public class DownloadReceiver extends AbsReceiver { - private final String TAG = "DownloadReceiver"; - - /** - * 设置最大下载速度,单位:kb - * - * @param maxSpeed 为0表示不限速 - * @deprecated {@code Aria.get(Context).getDownloadConfig().setMaxSpeed(int)} - */ - @Deprecated - public DownloadReceiver setMaxSpeed(int maxSpeed) { - AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMaxSpeed(maxSpeed); - return this; - } - - /** - * 使用下载实体执行下载操作 - * - * @param entity 下载实体 - */ - @CheckResult - public DownloadTarget load(DownloadEntity entity) { - CheckUtil.checkUrlInvalidThrow(entity.getUrl()); - return new DownloadTarget(entity, targetName); - } - - /** - * 加载Http、https单任务下载地址 - * - * @param url 下载地址 - */ - @CheckResult - public DownloadTarget load(@NonNull String url) { - CheckUtil.checkUrlInvalidThrow(url); - return new DownloadTarget(url, targetName); - } - - /** - * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组 - * - * @param urls 任务组子任务下载地址列表 - * @deprecated {@link #loadGroup(DownloadGroupEntity)} - */ - @Deprecated - @CheckResult - public DownloadGroupTarget load(List urls) { - return loadGroup(urls); - } - - /** - * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组 - */ - @CheckResult - public DownloadGroupTarget loadGroup(List urls) { - CheckUtil.checkDownloadUrls(urls); - return new DownloadGroupTarget(urls, targetName); - } - - /** - * 使用下载实体执行FTP下载操作 - * - * @param entity 下载实体 - */ - @CheckResult - public FtpDownloadTarget loadFtp(DownloadEntity entity) { - CheckUtil.checkUrlInvalidThrow(entity.getUrl()); - return new FtpDownloadTarget(entity, targetName); - } - - /** - * 加载ftp单任务下载地址 - */ - @CheckResult - public FtpDownloadTarget loadFtp(@NonNull String url) { - CheckUtil.checkUrlInvalidThrow(url); - return new FtpDownloadTarget(url, targetName); - } - - /** - * 使用任务组实体执行任务组的实体执行任务组的下载操作,后续版本会删除该api - * - * @param groupEntity 如果加载的任务实体没有子项的下载地址, - * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 - * @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)} - */ - @Deprecated - @CheckResult - public DownloadGroupTarget load(DownloadGroupEntity groupEntity) { - CheckUtil.checkDownloadUrls(groupEntity.getUrls()); - return loadGroup(groupEntity); - } - - /** - * 使用任务组实体执行任务组的实体执行任务组的下载操作 - * - * @param groupEntity 如果加载的任务实体没有子项的下载地址, - * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 - */ - @CheckResult - public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) { - CheckUtil.checkDownloadUrls(groupEntity.getUrls()); - return new DownloadGroupTarget(groupEntity, targetName); - } - - /** - * 加载ftp文件夹下载地址 - */ - @CheckResult - public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) { - CheckUtil.checkUrlInvalidThrow(dirUrl); - return new FtpDirDownloadTarget(dirUrl, targetName); - } - - /** - * 将当前类注册到Aria - */ - public void register() { - if (TextUtils.isEmpty(targetName)) { - ALog.e(TAG, "download register target null"); - return; - } - Object obj = OBJ_MAP.get(getKey()); - if (obj == null) { - ALog.e(TAG, String.format("【%s】观察者为空", targetName)); - return; - } - Set set = ProxyHelper.getInstance().checkProxyType(obj.getClass()); - if (set != null && !set.isEmpty()) { - for (Integer type : set) { - if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD) { - DownloadSchedulers.getInstance().register(obj); - } else if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) { - DownloadGroupSchedulers.getInstance().register(obj); - } - } - } else { - ALog.w(TAG, "没有Aria的注解方法"); - } - } - - /** - * 取消注册,如果是Activity或fragment,Aria会界面销毁时自动调用该方法,不需要你手动调用。 - * 注意事项: - * 1、如果在activity中一定要调用该方法,那么请在{@code onDestroy()}中调用 - * 2、不要在activity的{@code onStop()}中调用改方法 - * 3、如果是Dialog或popupwindow,需要你在撤销界面时调用该方法 - * 4、如果你是在Module(非android组件类)中注册了Aria,那么你也需要在Module类中调用该方法,而不是在组件类中 - * 调用销毁,详情见 - * - * @see module类中销毁 - */ - @Override public void unRegister() { - if (needRmListener) { - unRegisterListener(); - } - AriaManager.getInstance(AriaManager.APP).removeReceiver(OBJ_MAP.get(getKey())); - } - - @Override public String getType() { - return ReceiverType.DOWNLOAD; - } - - @Override protected void unRegisterListener() { - if (TextUtils.isEmpty(targetName)) { - ALog.e(TAG, "download unRegisterListener target null"); - return; - } - Object obj = OBJ_MAP.get(getKey()); - if (obj == null) { - ALog.e(TAG, String.format("【%s】观察者为空", targetName)); - return; - } - Set set = ProxyHelper.getInstance().mProxyCache.get(obj.getClass().getName()); - if (set != null) { - for (Integer integer : set) { - if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) { - DownloadSchedulers.getInstance().unRegister(obj); - } else if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) { - DownloadGroupSchedulers.getInstance().unRegister(obj); - } - } - } - } - - /** - * 通过下载链接获取下载实体 - * - * @return 如果url错误或查找不到数据,则返回null - */ - public DownloadEntity getDownloadEntity(String downloadUrl) { - if (!CheckUtil.checkUrl(downloadUrl)) { - return null; - } - return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl); - } - - /** - * 通过下载地址和文件保存路径获取下载任务实体 - * - * @param downloadUrl 下载地址 - * @return 如果url错误或查找不到数据,则返回null - */ - public DTaskWrapper getDownloadTask(String downloadUrl) { - if (!CheckUtil.checkUrl(downloadUrl)) { - return null; - } - if (!taskExists(downloadUrl)) { - return null; - } - return TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, downloadUrl); - } - - /** - * 通过下载链接获取保存在数据库的下载任务组实体 - * - * @param urls 任务组子任务下载地址列表 - * @return 返回对应的任务组实体;如果查找不到对应的数据或子任务列表为null,返回null - */ - public DGTaskWrapper getGroupTask(List urls) { - if (urls == null || urls.isEmpty()) { - ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null"); - return null; - } - if (!taskExists(urls)) { - return null; - } - return TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, urls); - } - - /** - * 获取FTP文件夹下载任务实体 - * - * @param dirUrl FTP文件夹本地下载路径 - * @return 返回对应的任务组实体;如果查找不到对应的数据或路径为null,返回null - */ - public DGTaskWrapper getFtpDirTask(String dirUrl) { - if (TextUtils.isEmpty(dirUrl)) { - ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null"); - return null; - } - boolean b = - DownloadGroupEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", dirUrl) != null; - if (!b) { - return null; - } - return TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, dirUrl); - } - - /** - * 下载任务是否存在 - * - * @return {@code true}存在,{@code false} 不存在 - */ - public boolean taskExists(String downloadUrl) { - return DbEntity.checkDataExist(DownloadEntity.class, "url=?", downloadUrl); - } - - /** - * 判断任务组是否存在 - * - * @return {@code true} 存在;{@code false} 不存在 - */ - public boolean taskExists(List urls) { - if (urls == null || urls.isEmpty()) { - return false; - } - String groupHash = CommonUtil.getMd5Code(urls); - return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", groupHash); - } - - /** - * 获取所有普通下载任务 - * 获取未完成的普通任务列表{@link #getAllNotCompleteTask()} - * 获取已经完成的普通任务列表{@link #getAllCompleteTask()} - */ - public List getTaskList() { - return DbEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''", - "false"); - } - - /** - * 分页获取所有普通下载任务 - * 获取未完成的普通任务列表{@link #getAllNotCompleteTask()} - * 获取已经完成的普通任务列表{@link #getAllCompleteTask()} - * - * @param page 当前页,不能小于1 - * @param num 每页数量,不能小于1 - * @return 如果页数大于总页数,返回null - */ - public List getTaskList(int page, int num) { - CheckUtil.checkPageParams(page, num); - return DbEntity.findDatas(DownloadEntity.class, page, num, - "isGroupChild=? and downloadPath!=''", "false"); - } - - /** - * 获取所有未完成的普通下载任务 - */ - public List getAllNotCompleteTask() { - return DbEntity.findDatas(DownloadEntity.class, - "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false"); - } - - /** - * 分页获取所有未完成的普通下载任务 - * - * @param page 当前页,不能小于1 - * @param num 每页数量,不能小于1 - * @return 如果页数大于总页数,返回null - */ - public List getAllNotCompleteTask(int page, int num) { - CheckUtil.checkPageParams(page, num); - return DbEntity.findDatas(DownloadEntity.class, page, num, - "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false"); - } - - /** - * 获取所有已经完成的普通任务 - */ - public List getAllCompleteTask() { - return DbEntity.findDatas(DownloadEntity.class, - "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true"); - } - - /** - * 分页获取所有已经完成的普通任务 - * - * @param page 当前页,不能小于1 - * @param num 每页数量,不能小于1 - * @return 如果页数大于总页数,返回null - */ - public List getAllCompleteTask(int page, int num) { - CheckUtil.checkPageParams(page, num); - return DbEntity.findDatas(DownloadEntity.class, - "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true"); - } - - /** - * 获取任务组列表 - * - * @return 如果没有任务组列表,则返回null - */ - public List getGroupTaskList() { - List wrappers = DbEntity.findRelationData(DGEntityWrapper.class); - if (wrappers == null || wrappers.isEmpty()) { - return null; - } - List entities = new ArrayList<>(); - for (DGEntityWrapper wrapper : wrappers) { - entities.add(wrapper.groupEntity); - } - return entities; - } - - /** - * 分页获取祝贺任务列表 - * - * @param page 当前页,不能小于1 - * @param num 每页数量,不能小于1 - * @return 如果没有任务组列表,则返回null - */ - public List getGroupTaskList(int page, int num) { - List wrappers = DbEntity.findRelationData(DGEntityWrapper.class, page, num); - if (wrappers == null || wrappers.isEmpty()) { - return null; - } - List entities = new ArrayList<>(); - for (DGEntityWrapper wrapper : wrappers) { - entities.add(wrapper.groupEntity); - } - return entities; - } - - /** - * 获取普通任务和任务组的任务列表 - */ - public List getTotalTaskList() { - List list = new ArrayList<>(); - List simpleTask = getTaskList(); - List groupTask = getGroupTaskList(); - if (simpleTask != null && !simpleTask.isEmpty()) { - list.addAll(simpleTask); - } - if (groupTask != null && !groupTask.isEmpty()) { - list.addAll(groupTask); - } - return list; - } - - /** - * 停止所有正在下载的任务,并清空等待队列。 - */ - public void stopAllTask() { - AriaManager.getInstance(AriaManager.APP) - .setCmd(NormalCmdFactory.getInstance() - .createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_STOP_ALL, - ICmd.TASK_TYPE_DOWNLOAD)) - .exe(); - } - - /** - * 恢复所有正在下载的任务 - * 1.如果执行队列没有满,则开始下载任务,直到执行队列满 - * 2.如果队列执行队列已经满了,则将所有任务添加到等待队列中 - */ - public void resumeAllTask() { - AriaManager.getInstance(AriaManager.APP) - .setCmd(NormalCmdFactory.getInstance() - .createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_RESUME_ALL, - ICmd.TASK_TYPE_DOWNLOAD)) - .exe(); - } - - /** - * 删除所有任务 - * - * @param removeFile {@code true} 删除已经下载完成的任务,不仅删除下载记录,还会删除已经下载完成的文件,{@code false} - * 如果文件已经下载完成,只删除下载记录 - */ - public void removeAllTask(boolean removeFile) { - final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP); - CancelAllCmd cancelCmd = - (CancelAllCmd) CommonUtil.createNormalCmd(new DTaskWrapper(null), - NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_DOWNLOAD); - cancelCmd.removeFile = removeFile; - ariaManager.setCmd(cancelCmd).exe(); - Set keys = ariaManager.getReceiver().keySet(); - for (String key : keys) { - ariaManager.getReceiver().remove(key); - } - } +/* + * 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.support.annotation.CheckResult; +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.CancelAllCmd; +import com.arialyy.aria.core.command.normal.NormalCmdFactory; +import com.arialyy.aria.core.common.ProxyHelper; +import com.arialyy.aria.core.inf.AbsEntity; +import com.arialyy.aria.core.inf.AbsReceiver; +import com.arialyy.aria.core.inf.ReceiverType; +import com.arialyy.aria.core.manager.TaskWrapperManager; +import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers; +import com.arialyy.aria.core.scheduler.DownloadSchedulers; +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.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Created by lyy on 2016/12/5. + * 下载功能接收器 + */ +public class DownloadReceiver extends AbsReceiver { + private final String TAG = "DownloadReceiver"; + + /** + * 设置最大下载速度,单位:kb + * + * @param maxSpeed 为0表示不限速 + * @deprecated {@code Aria.get(Context).getDownloadConfig().setMaxSpeed(int)} + */ + @Deprecated + public DownloadReceiver setMaxSpeed(int maxSpeed) { + AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMaxSpeed(maxSpeed); + return this; + } + + /** + * 使用下载实体执行下载操作 + * + * @param entity 下载实体 + */ + @CheckResult + public DownloadTarget load(DownloadEntity entity) { + CheckUtil.checkUrlInvalidThrow(entity.getUrl()); + return new DownloadTarget(entity, targetName); + } + + /** + * 加载Http、https单任务下载地址 + * + * @param url 下载地址 + */ + @CheckResult + public DownloadTarget load(@NonNull String url) { + CheckUtil.checkUrlInvalidThrow(url); + return new DownloadTarget(url, targetName); + } + + /** + * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组 + * + * @param urls 任务组子任务下载地址列表 + * @deprecated {@link #loadGroup(DownloadGroupEntity)} + */ + @Deprecated + @CheckResult + public DownloadGroupTarget load(List urls) { + return loadGroup(urls); + } + + /** + * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组 + */ + @CheckResult + public DownloadGroupTarget loadGroup(List urls) { + CheckUtil.checkDownloadUrls(urls); + return new DownloadGroupTarget(urls, targetName); + } + + /** + * 使用下载实体执行FTP下载操作 + * + * @param entity 下载实体 + */ + @CheckResult + public FtpDownloadTarget loadFtp(DownloadEntity entity) { + CheckUtil.checkUrlInvalidThrow(entity.getUrl()); + return new FtpDownloadTarget(entity, targetName); + } + + /** + * 加载ftp单任务下载地址 + */ + @CheckResult + public FtpDownloadTarget loadFtp(@NonNull String url) { + CheckUtil.checkUrlInvalidThrow(url); + return new FtpDownloadTarget(url, targetName); + } + + /** + * 使用任务组实体执行任务组的实体执行任务组的下载操作,后续版本会删除该api + * + * @param groupEntity 如果加载的任务实体没有子项的下载地址, + * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 + * @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)} + */ + @Deprecated + @CheckResult + public DownloadGroupTarget load(DownloadGroupEntity groupEntity) { + CheckUtil.checkDownloadUrls(groupEntity.getUrls()); + return loadGroup(groupEntity); + } + + /** + * 使用任务组实体执行任务组的实体执行任务组的下载操作 + * + * @param groupEntity 如果加载的任务实体没有子项的下载地址, + * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 + */ + @CheckResult + public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) { + CheckUtil.checkDownloadUrls(groupEntity.getUrls()); + return new DownloadGroupTarget(groupEntity, targetName); + } + + /** + * 加载ftp文件夹下载地址 + */ + @CheckResult + public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) { + CheckUtil.checkUrlInvalidThrow(dirUrl); + return new FtpDirDownloadTarget(dirUrl, targetName); + } + + /** + * 将当前类注册到Aria + */ + public void register() { + if (TextUtils.isEmpty(targetName)) { + ALog.e(TAG, "download register target null"); + return; + } + Object obj = OBJ_MAP.get(getKey()); + if (obj == null) { + ALog.e(TAG, String.format("【%s】观察者为空", targetName)); + return; + } + Set set = ProxyHelper.getInstance().checkProxyType(obj.getClass()); + if (set != null && !set.isEmpty()) { + for (Integer type : set) { + if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD) { + DownloadSchedulers.getInstance().register(obj); + } else if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) { + DownloadGroupSchedulers.getInstance().register(obj); + } + } + } else { + ALog.w(TAG, "没有Aria的注解方法"); + } + } + + /** + * 取消注册,如果是Activity或fragment,Aria会界面销毁时自动调用该方法,不需要你手动调用。 + * 注意事项: + * 1、如果在activity中一定要调用该方法,那么请在{@code onDestroy()}中调用 + * 2、不要在activity的{@code onStop()}中调用改方法 + * 3、如果是Dialog或popupwindow,需要你在撤销界面时调用该方法 + * 4、如果你是在Module(非android组件类)中注册了Aria,那么你也需要在Module类中调用该方法,而不是在组件类中 + * 调用销毁,详情见 + * + * @see module类中销毁 + */ + @Override public void unRegister() { + if (needRmListener) { + unRegisterListener(); + } + AriaManager.getInstance(AriaManager.APP).removeReceiver(OBJ_MAP.get(getKey())); + } + + @Override public String getType() { + return ReceiverType.DOWNLOAD; + } + + @Override protected void unRegisterListener() { + if (TextUtils.isEmpty(targetName)) { + ALog.e(TAG, "download unRegisterListener target null"); + return; + } + Object obj = OBJ_MAP.get(getKey()); + if (obj == null) { + ALog.e(TAG, String.format("【%s】观察者为空", targetName)); + return; + } + Set set = ProxyHelper.getInstance().mProxyCache.get(obj.getClass().getName()); + if (set != null) { + for (Integer integer : set) { + if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) { + DownloadSchedulers.getInstance().unRegister(obj); + } else if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) { + DownloadGroupSchedulers.getInstance().unRegister(obj); + } + } + } + } + + /** + * 通过下载链接获取下载实体 + * + * @return 如果url错误或查找不到数据,则返回null + */ + public DownloadEntity getDownloadEntity(String downloadUrl) { + if (!CheckUtil.checkUrl(downloadUrl)) { + return null; + } + return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl); + } + + /** + * 通过下载地址和文件保存路径获取下载任务实体 + * + * @param downloadUrl 下载地址 + * @return 如果url错误或查找不到数据,则返回null + */ + public DTaskWrapper getDownloadTask(String downloadUrl) { + if (!CheckUtil.checkUrl(downloadUrl)) { + return null; + } + if (!taskExists(downloadUrl)) { + return null; + } + return TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, downloadUrl); + } + + /** + * 通过下载链接获取保存在数据库的下载任务组实体 + * + * @param urls 任务组子任务下载地址列表 + * @return 返回对应的任务组实体;如果查找不到对应的数据或子任务列表为null,返回null + */ + public DGTaskWrapper getGroupTask(List urls) { + if (urls == null || urls.isEmpty()) { + ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null"); + return null; + } + if (!taskExists(urls)) { + return null; + } + return TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, urls); + } + + /** + * 获取FTP文件夹下载任务实体 + * + * @param dirUrl FTP文件夹本地下载路径 + * @return 返回对应的任务组实体;如果查找不到对应的数据或路径为null,返回null + */ + public DGTaskWrapper getFtpDirTask(String dirUrl) { + if (TextUtils.isEmpty(dirUrl)) { + ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null"); + return null; + } + boolean b = + DownloadGroupEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", dirUrl) != null; + if (!b) { + return null; + } + return TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, dirUrl); + } + + /** + * 下载任务是否存在 + * + * @return {@code true}存在,{@code false} 不存在 + */ + public boolean taskExists(String downloadUrl) { + return DbEntity.checkDataExist(DownloadEntity.class, "url=?", downloadUrl); + } + + /** + * 判断任务组是否存在 + * + * @return {@code true} 存在;{@code false} 不存在 + */ + public boolean taskExists(List urls) { + if (urls == null || urls.isEmpty()) { + return false; + } + String groupHash = CommonUtil.getMd5Code(urls); + return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", groupHash); + } + + /** + * 获取所有普通下载任务 + * 获取未完成的普通任务列表{@link #getAllNotCompleteTask()} + * 获取已经完成的普通任务列表{@link #getAllCompleteTask()} + */ + public List getTaskList() { + return DbEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''", + "false"); + } + + /** + * 分页获取所有普通下载任务 + * 获取未完成的普通任务列表{@link #getAllNotCompleteTask()} + * 获取已经完成的普通任务列表{@link #getAllCompleteTask()} + * + * @param page 当前页,不能小于1 + * @param num 每页数量,不能小于1 + * @return 如果页数大于总页数,返回null + */ + public List getTaskList(int page, int num) { + CheckUtil.checkPageParams(page, num); + return DbEntity.findDatas(DownloadEntity.class, page, num, + "isGroupChild=? and downloadPath!=''", "false"); + } + + /** + * 获取所有未完成的普通下载任务 + */ + public List getAllNotCompleteTask() { + return DbEntity.findDatas(DownloadEntity.class, + "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false"); + } + + /** + * 分页获取所有未完成的普通下载任务 + * + * @param page 当前页,不能小于1 + * @param num 每页数量,不能小于1 + * @return 如果页数大于总页数,返回null + */ + public List getAllNotCompleteTask(int page, int num) { + CheckUtil.checkPageParams(page, num); + return DbEntity.findDatas(DownloadEntity.class, page, num, + "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false"); + } + + /** + * 获取所有已经完成的普通任务 + */ + public List getAllCompleteTask() { + return DbEntity.findDatas(DownloadEntity.class, + "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true"); + } + + /** + * 分页获取所有已经完成的普通任务 + * + * @param page 当前页,不能小于1 + * @param num 每页数量,不能小于1 + * @return 如果页数大于总页数,返回null + */ + public List getAllCompleteTask(int page, int num) { + CheckUtil.checkPageParams(page, num); + return DbEntity.findDatas(DownloadEntity.class, + "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true"); + } + + /** + * 获取任务组列表 + * + * @return 如果没有任务组列表,则返回null + */ + public List getGroupTaskList() { + List wrappers = DbEntity.findRelationData(DGEntityWrapper.class); + if (wrappers == null || wrappers.isEmpty()) { + return null; + } + List entities = new ArrayList<>(); + for (DGEntityWrapper wrapper : wrappers) { + entities.add(wrapper.groupEntity); + } + return entities; + } + + /** + * 分页获取祝贺任务列表 + * + * @param page 当前页,不能小于1 + * @param num 每页数量,不能小于1 + * @return 如果没有任务组列表,则返回null + */ + public List getGroupTaskList(int page, int num) { + List wrappers = DbEntity.findRelationData(DGEntityWrapper.class, page, num); + if (wrappers == null || wrappers.isEmpty()) { + return null; + } + List entities = new ArrayList<>(); + for (DGEntityWrapper wrapper : wrappers) { + entities.add(wrapper.groupEntity); + } + return entities; + } + + /** + * 获取普通任务和任务组的任务列表 + */ + public List getTotalTaskList() { + List list = new ArrayList<>(); + List simpleTask = getTaskList(); + List groupTask = getGroupTaskList(); + if (simpleTask != null && !simpleTask.isEmpty()) { + list.addAll(simpleTask); + } + if (groupTask != null && !groupTask.isEmpty()) { + list.addAll(groupTask); + } + return list; + } + + /** + * 停止所有正在下载的任务,并清空等待队列。 + */ + public void stopAllTask() { + AriaManager.getInstance(AriaManager.APP) + .setCmd(NormalCmdFactory.getInstance() + .createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_STOP_ALL, + ICmd.TASK_TYPE_DOWNLOAD)) + .exe(); + } + + /** + * 恢复所有正在下载的任务 + * 1.如果执行队列没有满,则开始下载任务,直到执行队列满 + * 2.如果队列执行队列已经满了,则将所有任务添加到等待队列中 + */ + public void resumeAllTask() { + AriaManager.getInstance(AriaManager.APP) + .setCmd(NormalCmdFactory.getInstance() + .createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_RESUME_ALL, + ICmd.TASK_TYPE_DOWNLOAD)) + .exe(); + } + + /** + * 删除所有任务 + * + * @param removeFile {@code true} 删除已经下载完成的任务,不仅删除下载记录,还会删除已经下载完成的文件,{@code false} + * 如果文件已经下载完成,只删除下载记录 + */ + public void removeAllTask(boolean removeFile) { + final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP); + CancelAllCmd cancelCmd = + (CancelAllCmd) CommonUtil.createNormalCmd(new DTaskWrapper(null), + NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_DOWNLOAD); + cancelCmd.removeFile = removeFile; + ariaManager.setCmd(cancelCmd).exe(); + Set keys = ariaManager.getReceiver().keySet(); + for (String key : keys) { + ariaManager.getReceiver().remove(key); + } + } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java index 045d2d89..eca02c0d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java @@ -28,7 +28,7 @@ import java.util.Map; * Created by lyy on 2016/12/5. * https://github.com/AriaLyy/Aria */ -public class DownloadTarget extends AbsDownloadTarget +public class DownloadTarget extends AbsDTarget implements IHttpHeaderDelegate { private HttpHeaderDelegate mHeaderDelegate; private DNormalDelegate mNormalDelegate; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDelegate.java new file mode 100644 index 00000000..12cc9a10 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDelegate.java @@ -0,0 +1,91 @@ +/* + * 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.FtpUrlEntity; +import com.arialyy.aria.core.inf.AbsTaskWrapper; +import com.arialyy.aria.util.ALog; + +/** + * Created by lyy on 2017/4/9. + * ftp文件夹下载功能代理 + */ +class FtpDirDelegate extends AbsGroupDelegate { + FtpDirDelegate(FtpDirDownloadTarget target, DGTaskWrapper wrapper) { + super(target, wrapper); + wrapper.setRequestType(AbsTaskWrapper.D_FTP_DIR); + } + + @Override public boolean checkEntity() { + boolean b = checkDirPath() && checkUrl(); + if (b) { + getEntity().save(); + if (getTaskWrapper().getSubTaskWrapper() != null) { + //初始化子项的登录信息 + FtpUrlEntity tUrlEntity = getTaskWrapper().asFtp().getUrlEntity(); + for (DTaskWrapper wrapper : getTaskWrapper().getSubTaskWrapper()) { + FtpUrlEntity urlEntity = wrapper.asFtp().getUrlEntity(); + urlEntity.needLogin = tUrlEntity.needLogin; + urlEntity.account = tUrlEntity.account; + urlEntity.user = tUrlEntity.user; + urlEntity.password = tUrlEntity.password; + // 处理ftps详细 + if (tUrlEntity.isFtps) { + urlEntity.isFtps = true; + urlEntity.protocol = tUrlEntity.protocol; + urlEntity.storePath = tUrlEntity.storePath; + urlEntity.storePass = tUrlEntity.storePass; + urlEntity.keyAlias = tUrlEntity.keyAlias; + } + } + } + } + if (getTaskWrapper().asFtp().getUrlEntity().isFtps) { + if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().storePath)) { + ALog.e(TAG, "证书路径为空"); + return false; + } + if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().keyAlias)) { + ALog.e(TAG, "证书别名为空"); + return false; + } + } + return b; + } + + /** + * 检查普通任务的下载地址 + * + * @return {@code true}地址合法 + */ + private boolean checkUrl() { + final String url = getGroupHash(); + if (TextUtils.isEmpty(url)) { + ALog.e(TAG, "下载失败,url为null"); + return false; + } else if (!url.startsWith("ftp")) { + ALog.e(TAG, "下载失败,url【" + url + "】错误"); + return false; + } + int index = url.indexOf("://"); + if (index == -1) { + ALog.e(TAG, "下载失败,url【" + url + "】不合法"); + return false; + } + return true; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java index 289600c7..af7c081b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java @@ -16,14 +16,10 @@ package com.arialyy.aria.core.download; import android.support.annotation.CheckResult; -import android.text.TextUtils; -import com.arialyy.aria.core.FtpUrlEntity; import com.arialyy.aria.core.common.ftp.FTPSDelegate; import com.arialyy.aria.core.common.ftp.FtpDelegate; -import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.IFtpTarget; import com.arialyy.aria.core.manager.TaskWrapperManager; -import com.arialyy.aria.util.ALog; import java.net.Proxy; /** @@ -32,7 +28,8 @@ import java.net.Proxy; */ public class FtpDirDownloadTarget extends AbsDGTarget implements IFtpTarget { - private FtpDelegate mDelegate; + private FtpDelegate mFtpDelegate; + private FtpDirDelegate mDirDelegate; FtpDirDownloadTarget(String url, String targetName) { setTargetName(targetName); @@ -40,13 +37,9 @@ public class FtpDirDownloadTarget extends AbsDGTarget } private void init(String key) { - mGroupHash = key; - setTaskWrapper(TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, key)); - getTaskWrapper().setRequestType(AbsTaskWrapper.D_FTP_DIR); - if (getEntity() != null) { - mDirPathTemp = getEntity().getDirPath(); - } - mDelegate = new FtpDelegate<>(this); + mDirDelegate = new FtpDirDelegate(this, + TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, key)); + mFtpDelegate = new FtpDelegate<>(this); } @Override public int getTargetType() { @@ -54,62 +47,39 @@ public class FtpDirDownloadTarget extends AbsDGTarget } @Override protected boolean checkEntity() { - boolean b = getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl(); - if (b) { - getEntity().save(); - if (getTaskWrapper().getSubTaskWrapper() != null) { - //初始化子项的登录信息 - FtpUrlEntity tUrlEntity = getTaskWrapper().asFtp().getUrlEntity(); - for (DTaskWrapper wrapper : getTaskWrapper().getSubTaskWrapper()) { - FtpUrlEntity urlEntity = wrapper.asFtp().getUrlEntity(); - urlEntity.needLogin = tUrlEntity.needLogin; - urlEntity.account = tUrlEntity.account; - urlEntity.user = tUrlEntity.user; - urlEntity.password = tUrlEntity.password; - // 处理ftps详细 - if (tUrlEntity.isFtps) { - urlEntity.isFtps = true; - urlEntity.protocol = tUrlEntity.protocol; - urlEntity.storePath = tUrlEntity.storePath; - urlEntity.storePass = tUrlEntity.storePass; - urlEntity.keyAlias = tUrlEntity.keyAlias; - } - } - } - } - if (getTaskWrapper().asFtp().getUrlEntity().isFtps) { - if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().storePath)) { - ALog.e(TAG, "证书路径为空"); - return false; - } - if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().keyAlias)) { - ALog.e(TAG, "证书别名为空"); - return false; - } - } - return b; + return mDirDelegate.checkEntity(); + } + + @Override public boolean isRunning() { + return mDirDelegate.isRunning(); + } + + @Override public boolean taskExists() { + return mDirDelegate.taskExists(); } /** - * 检查普通任务的下载地址 + * 设置任务组的文件夹路径,在Aria中,任务组的所有子任务都会下载到以任务组组名的文件夹中。 + * 如:groupDirPath = "/mnt/sdcard/download/group_test" + *
+   *   {@code
+   *      + mnt
+   *        + sdcard
+   *          + download
+   *            + group_test
+   *              - task1.apk
+   *              - task2.apk
+   *              - task3.apk
+   *              ....
+   *
+   *   }
+   * 
* - * @return {@code true}地址合法 + * @param dirPath 任务组保存文件夹路径 */ - private boolean checkUrl() { - final String url = mGroupHash; - if (TextUtils.isEmpty(url)) { - ALog.e(TAG, "下载失败,url为null"); - return false; - } else if (!url.startsWith("ftp")) { - ALog.e(TAG, "下载失败,url【" + url + "】错误"); - return false; - } - int index = url.indexOf("://"); - if (index == -1) { - ALog.e(TAG, "下载失败,url【" + url + "】不合法"); - return false; - } - return true; + @CheckResult + public FtpDirDownloadTarget setDirPath(String dirPath) { + return mDirDelegate.setDirPath(dirPath); } /** @@ -125,20 +95,20 @@ public class FtpDirDownloadTarget extends AbsDGTarget @CheckResult @Override public FtpDirDownloadTarget charSet(String charSet) { - return mDelegate.charSet(charSet); + return mFtpDelegate.charSet(charSet); } @CheckResult @Override public FtpDirDownloadTarget login(String userName, String password) { - return mDelegate.login(userName, password); + return mFtpDelegate.login(userName, password); } @CheckResult @Override public FtpDirDownloadTarget login(String userName, String password, String account) { - return mDelegate.login(userName, password, account); + return mFtpDelegate.login(userName, password, account); } @Override public FtpDirDownloadTarget setProxy(Proxy proxy) { - return mDelegate.setProxy(proxy); + return mFtpDelegate.setProxy(proxy); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java index 8cd35c31..e4461d0d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java @@ -30,7 +30,7 @@ import java.net.Proxy; * Created by lyy on 2016/12/5. * https://github.com/AriaLyy/Aria */ -public class FtpDownloadTarget extends AbsDownloadTarget +public class FtpDownloadTarget extends AbsDTarget implements IFtpTarget { private FtpDelegate mFtpDelegate; private DNormalDelegate mNormalDelegate; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/HttpGroupDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/download/HttpGroupDelegate.java new file mode 100644 index 00000000..2175c311 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/HttpGroupDelegate.java @@ -0,0 +1,238 @@ +/* + * 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.support.annotation.CheckResult; +import android.text.TextUtils; +import com.arialyy.aria.core.common.RequestEnum; +import com.arialyy.aria.orm.DbEntity; +import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Created by lyy on 2019/4/9. + * + * http组合任务功能代理 + */ +class HttpGroupDelegate extends AbsGroupDelegate { + + /** + * 子任务下载地址, + */ + private List mUrls = new ArrayList<>(); + + /** + * 子任务文件名 + */ + private List mSubNameTemp = new ArrayList<>(); + + HttpGroupDelegate(DownloadGroupTarget target, DGTaskWrapper wrapper) { + super(target, wrapper); + mUrls.addAll(wrapper.getEntity().getUrls()); + } + + @CheckResult + DownloadGroupTarget setGroupUrl(List urls) { + mUrls.clear(); + mUrls.addAll(urls); + return getTarget(); + } + + /** + * 设置子任务文件名,该方法必须在{@link #setDirPath(String)}之后调用,否则不生效 + */ + @CheckResult + DownloadGroupTarget setSubFileName(List subTaskFileName) { + if (subTaskFileName == null || subTaskFileName.isEmpty()) { + ALog.e(TAG, "修改子任务的文件名失败:列表为null"); + return getTarget(); + } + if (subTaskFileName.size() != getTaskWrapper().getSubTaskWrapper().size()) { + ALog.e(TAG, "修改子任务的文件名失败:子任务文件名列表数量和子任务的数量不匹配"); + return getTarget(); + } + mSubNameTemp.clear(); + mSubNameTemp.addAll(subTaskFileName); + return getTarget(); + } + + /** + * 更新组合任务下载地址 + * + * @param urls 新的组合任务下载地址列表 + */ + @CheckResult + DownloadGroupTarget updateUrls(List urls) { + if (urls == null || urls.isEmpty()) { + throw new NullPointerException("下载地址列表为空"); + } + if (urls.size() != mUrls.size()) { + throw new IllegalArgumentException("新下载地址数量和旧下载地址数量不一致"); + } + mUrls.clear(); + mUrls.addAll(urls); + String newHash = CommonUtil.getMd5Code(urls); + setGroupHash(newHash); + getEntity().setGroupHash(newHash); + getEntity().update(); + if (getEntity().getSubEntities() != null && !getEntity().getSubEntities().isEmpty()) { + for (DownloadEntity de : getEntity().getSubEntities()) { + de.setGroupHash(newHash); + de.update(); + } + } + return getTarget(); + } + + @Override public boolean checkEntity() { + if (!checkDirPath()) { + return false; + } + + if (!checkSubName()) { + return false; + } + + if (!checkUrls()) { + return false; + } + + if (getTaskWrapper().getEntity().getFileSize() == 0) { + ALog.e(TAG, "组合任务必须设置文件文件大小"); + return false; + } + + if (getTaskWrapper().asHttp().getRequestEnum() == RequestEnum.POST) { + for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) { + subTask.asHttp().setRequestEnum(RequestEnum.POST); + } + } + + getEntity().save(); + + if (isNeedModifyPath()) { + reChangeDirPath(getDirPathTemp()); + } + + if (!mSubNameTemp.isEmpty()) { + updateSingleSubFileName(); + } + return true; + } + + /** + * 更新所有改动的子任务文件名 + */ + private void updateSingleSubFileName() { + List entities = getTaskWrapper().getSubTaskWrapper(); + int i = 0; + for (DTaskWrapper 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 delItem = new HashSet<>(); + + 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; + } + + i++; + } + + for (int index : delItem) { + mUrls.remove(index); + if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) { + mSubNameTemp.remove(index); + } + } + + getEntity().setGroupHash(CommonUtil.getMd5Code(mUrls)); + + return true; + } + + /** + * 更新单个子任务文件名 + */ + private void updateSingleSubFileName(DTaskWrapper taskEntity, String newName) { + DownloadEntity entity = taskEntity.getEntity(); + if (!newName.equals(entity.getFileName())) { + String oldPath = getEntity().getDirPath() + "/" + entity.getFileName(); + String newPath = getEntity().getDirPath() + "/" + newName; + if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=? or isComplete='true'", + newPath)) { + ALog.w(TAG, String.format("更新文件名失败,路径【%s】已存在或文件已下载", newPath)); + return; + } + + CommonUtil.modifyTaskRecord(oldPath, newPath); + 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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IGroupTarget.java new file mode 100644 index 00000000..48cdd758 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IGroupTarget.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.core.inf; + +/** + * Created by lyy on 2019/4/5. + * 组合任务接收器功能接口 + */ +public interface IGroupTarget { + + /** + * 获取实体 + */ + AbsEntity getEntity(); + + /** + * 任务是否存在 + * + * @return {@code true}任务存在,{@code false} 任务不存在 + */ + boolean taskExists(); + + /** + * 任务是否在执行 + * + * @return {@code true} 任务正在执行,{@code false} 任务没有执行 + */ + boolean isRunning(); + + /** + * 检查实体是否合法 + * + * @return {@code true}合法 + */ + boolean checkEntity(); + + /** + * 检查文件夹路径 + * 1、文件夹路径不能为空 + * 2、文件夹路径不能是文件 + * + * @return {@code true} 合法 + */ + boolean checkDirPath(); +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ITargetNormal.java b/Aria/src/main/java/com/arialyy/aria/core/inf/INormalTarget.java similarity index 82% rename from Aria/src/main/java/com/arialyy/aria/core/inf/ITargetNormal.java rename to Aria/src/main/java/com/arialyy/aria/core/inf/INormalTarget.java index a2d4a9e4..5fbb62be 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/ITargetNormal.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/INormalTarget.java @@ -19,22 +19,7 @@ package com.arialyy.aria.core.inf; * Created by lyy on 2019/4/5. * 普通任务接收器功能接口 */ -public interface ITargetNormal { - - /** - * 通过地址初始化target - * - * @param url 下载url、上传url - * @param targetName 接收器名称 - */ - void initTarget(String url, String targetName); - - /** - * 更新下载url - * - * @param newUrl 新的下载url - */ - TARGET updateUrl(String newUrl); +public interface INormalTarget { /** * 获取实体 diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UNormalDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UNormalDelegate.java index f296177c..f0d98079 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UNormalDelegate.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UNormalDelegate.java @@ -17,7 +17,7 @@ package com.arialyy.aria.core.upload; import android.text.TextUtils; import com.arialyy.aria.core.inf.AbsEntity; -import com.arialyy.aria.core.inf.ITargetNormal; +import com.arialyy.aria.core.inf.INormalTarget; import com.arialyy.aria.core.manager.TaskWrapperManager; import com.arialyy.aria.core.queue.UploadTaskQueue; import com.arialyy.aria.orm.DbEntity; @@ -29,7 +29,7 @@ import java.io.File; * Created by Aria.Lao on 2019/4/5. * 普通上传任务通用功能处理 */ -class UNormalDelegate implements ITargetNormal { +class UNormalDelegate implements INormalTarget { private String TAG = "UNormalDelegate"; private UploadEntity mEntity; private TARGET mTarget; @@ -43,7 +43,7 @@ class UNormalDelegate implements ITargetNormal implements ITargetNormal tables = DBConfig.mapping.keySet(); - for (String tableName : tables) { - Class clazz = null; - clazz = DBConfig.mapping.get(tableName); - - if (!delegate.tableExists(db, clazz)) { - delegate.createTable(db, clazz); - } - } - } - } - return INSTANCE; - } - - private SqlHelper(Context context, DelegateCommon delegate) { - super(DBConfig.SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null, - DBConfig.VERSION); - mDelegate = delegate; - } - - @Override public void onCreate(SQLiteDatabase db) { - - } - - @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion < newVersion) { - if (oldVersion < 31) { - handle314AriaUpdate(db); - } else if (oldVersion < 45) { - handle360AriaUpdate(db); - } else { - handleDbUpdate(db, null, null); - } - } - } - - @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion > newVersion) { - handleDbUpdate(db, null, null); - } - } - - /** - * 处理数据库升级,该段代码无法修改表字段 - * - * @param modifyColumns 需要修改的表字段的映射,key为表名, - * value{@code Map}中的Map的key为老字段名称,value为该老字段对应的新字段名称 - * @param delColumns 需要删除的表字段,key为表名,value{@code List}为需要删除的字段列表 - */ - private void handleDbUpdate(SQLiteDatabase db, Map> modifyColumns, - Map> delColumns) { - if (db == null) { - ALog.e("SqlHelper", "db 为 null"); - return; - } else if (!db.isOpen()) { - ALog.e("SqlHelper", "db已关闭"); - return; - } - - try { - db.beginTransaction(); - Set tables = DBConfig.mapping.keySet(); - for (String tableName : tables) { - Class clazz = DBConfig.mapping.get(tableName); - if (mDelegate.tableExists(db, clazz)) { - db = mDelegate.checkDb(db); - //修改表名为中介表名 - String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName); - db.execSQL(alertSql); - - //创建新表 - mDelegate.createTable(db, clazz); - - String sql = String.format("SELECT COUNT(*) FROM %s_temp", tableName); - Cursor cursor = db.rawQuery(sql, null); - cursor.moveToFirst(); - long count = cursor.getLong(0); - cursor.close(); - - if (count > 0) { - // 获取所有表字段名称 - Cursor columnC = - db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null); - StringBuilder params = new StringBuilder(); - - while (columnC.moveToNext()) { - String columnName = columnC.getString(columnC.getColumnIndex("name")); - if (delColumns != null && delColumns.get(tableName) != null) { - List delColumn = delColumns.get(tableName); - if (delColumn != null && !delColumn.isEmpty()) { - if (delColumn.contains(columnName)) { - continue; - } - } - } - - params.append(columnName).append(","); - } - columnC.close(); - - String oldParamStr = params.toString(); - oldParamStr = oldParamStr.substring(0, oldParamStr.length() - 1); - String newParamStr = oldParamStr; - // 处理字段名称改变 - if (modifyColumns != null) { - //newParamStr = params.toString(); - Map columnMap = modifyColumns.get(tableName); - if (columnMap != null && !columnMap.isEmpty()) { - Set keys = columnMap.keySet(); - for (String key : keys) { - if (newParamStr.contains(key)) { - newParamStr = newParamStr.replace(key, columnMap.get(key)); - } - } - } - } - //恢复数据 - String insertSql = - String.format("INSERT INTO %s (%s) SELECT %s FROM %s_temp", tableName, newParamStr, - oldParamStr, tableName); - ALog.d(TAG, "insertSql = " + insertSql); - db.execSQL(insertSql); - } - //删除中介表 - mDelegate.dropTable(db, tableName + "_temp"); - } - } - db.setTransactionSuccessful(); - } catch (Exception e) { - ALog.e(TAG, e); - } finally { - db.endTransaction(); - } - - mDelegate.close(db); - } - - /** - * 处理3.6以下版本的数据库升级 - */ - private void handle360AriaUpdate(SQLiteDatabase db) { - String[] taskTables = - new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" }; - for (String taskTable : taskTables) { - if (mDelegate.tableExists(db, taskTable)) { - mDelegate.dropTable(db, taskTable); - } - } - Map> columnMap = new HashMap<>(); - Map map = new HashMap<>(); - map.put("groupName", "groupHash"); - columnMap.put("DownloadEntity", map); - columnMap.put("DownloadGroupEntity", map); - handleDbUpdate(db, columnMap, null); - } - - /** - * 处理3.4版本之前数据库迁移,主要是修改子表外键字段对应的值 - */ - private void handle314AriaUpdate(SQLiteDatabase db) { - String[] taskTables = - new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" }; - for (String taskTable : taskTables) { - if (mDelegate.tableExists(db, taskTable)) { - mDelegate.dropTable(db, taskTable); - } - } - - //删除所有主键为null和逐渐重复的数据 - String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" }; - String[] keys = new String[] { "downloadPath", "groupName" }; - int i = 0; - for (String tableName : tables) { - String pColumn = keys[i]; - String nullSql = - String.format("DELETE FROM %s WHERE %s='' OR %s IS NULL", tableName, pColumn, pColumn); - ALog.d(TAG, nullSql); - db.execSQL(nullSql); - - //删除所有主键重复的数据 - String repeatSql = - String.format( - "DELETE FROM %s WHERE %s IN(SELECT %s FROM %s GROUP BY %s HAVING COUNT(%s) > 1)", - tableName, pColumn, pColumn, tableName, pColumn, pColumn); - - ALog.d(TAG, repeatSql); - db.execSQL(repeatSql); - i++; - } - - Map> modifyColumnMap = new HashMap<>(); - Map map = new HashMap<>(); - map.put("groupName", "groupHash"); - modifyColumnMap.put("DownloadEntity", map); - modifyColumnMap.put("DownloadGroupEntity", map); - - Map> delColumnMap = new HashMap<>(); - List dEntityDel = new ArrayList<>(); - dEntityDel.add("taskKey"); - delColumnMap.put("DownloadEntity", dEntityDel); - List dgEntityDel = new ArrayList<>(); - dgEntityDel.add("subtask"); - delColumnMap.put("DownloadGroupEntity", dgEntityDel); - - handleDbUpdate(db, modifyColumnMap, delColumnMap); - } +/* + * 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.orm; + +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import com.arialyy.aria.util.ALog; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Created by lyy on 2015/11/2. + * sql帮助类 + */ +final class SqlHelper extends SQLiteOpenHelper { + private static final String TAG = "SqlHelper"; + static volatile SqlHelper INSTANCE = null; + + private DelegateCommon mDelegate; + + synchronized static SqlHelper init(Context context) { + if (INSTANCE == null) { + synchronized (SqlHelper.class) { + DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class); + INSTANCE = new SqlHelper(context.getApplicationContext(), delegate); + SQLiteDatabase db = INSTANCE.getWritableDatabase(); + db = delegate.checkDb(db); + // SQLite在3.6.19版本中开始支持外键约束, + // 而在Android中 2.1以前的版本使用的SQLite版本是3.5.9, 在2.2版本中使用的是3.6.22. + // 但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能 + // 需要使用如下语句: + db.execSQL("PRAGMA foreign_keys=ON;"); + Set tables = DBConfig.mapping.keySet(); + for (String tableName : tables) { + Class clazz = DBConfig.mapping.get(tableName); + + if (!delegate.tableExists(db, clazz)) { + delegate.createTable(db, clazz); + } + } + } + } + return INSTANCE; + } + + private SqlHelper(Context context, DelegateCommon delegate) { + super(DBConfig.SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null, + DBConfig.VERSION); + mDelegate = delegate; + } + + @Override public void onCreate(SQLiteDatabase db) { + + } + + @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion < newVersion) { + if (oldVersion < 31) { + handle314AriaUpdate(db); + } else if (oldVersion < 45) { + handle360AriaUpdate(db); + } else { + handleDbUpdate(db, null, null); + } + } + } + + @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion > newVersion) { + handleDbUpdate(db, null, null); + } + } + + /** + * 处理数据库升级,该段代码无法修改表字段 + * + * @param modifyColumns 需要修改的表字段的映射,key为表名, + * value{@code Map}中的Map的key为老字段名称,value为该老字段对应的新字段名称 + * @param delColumns 需要删除的表字段,key为表名,value{@code List}为需要删除的字段列表 + */ + private void handleDbUpdate(SQLiteDatabase db, Map> modifyColumns, + Map> delColumns) { + if (db == null) { + ALog.e("SqlHelper", "db 为 null"); + return; + } else if (!db.isOpen()) { + ALog.e("SqlHelper", "db已关闭"); + return; + } + + try { + db.beginTransaction(); + Set tables = DBConfig.mapping.keySet(); + for (String tableName : tables) { + Class clazz = DBConfig.mapping.get(tableName); + if (mDelegate.tableExists(db, clazz)) { + db = mDelegate.checkDb(db); + //修改表名为中介表名 + String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName); + db.execSQL(alertSql); + + //创建新表 + mDelegate.createTable(db, clazz); + + String sql = String.format("SELECT COUNT(*) FROM %s_temp", tableName); + Cursor cursor = db.rawQuery(sql, null); + cursor.moveToFirst(); + long count = cursor.getLong(0); + cursor.close(); + + if (count > 0) { + // 获取所有表字段名称 + Cursor columnC = + db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null); + StringBuilder params = new StringBuilder(); + + while (columnC.moveToNext()) { + String columnName = columnC.getString(columnC.getColumnIndex("name")); + if (delColumns != null && delColumns.get(tableName) != null) { + List delColumn = delColumns.get(tableName); + if (delColumn != null && !delColumn.isEmpty()) { + if (delColumn.contains(columnName)) { + continue; + } + } + } + + params.append(columnName).append(","); + } + columnC.close(); + + String oldParamStr = params.toString(); + oldParamStr = oldParamStr.substring(0, oldParamStr.length() - 1); + String newParamStr = oldParamStr; + // 处理字段名称改变 + if (modifyColumns != null) { + //newParamStr = params.toString(); + Map columnMap = modifyColumns.get(tableName); + if (columnMap != null && !columnMap.isEmpty()) { + Set keys = columnMap.keySet(); + for (String key : keys) { + if (newParamStr.contains(key)) { + newParamStr = newParamStr.replace(key, columnMap.get(key)); + } + } + } + } + //恢复数据 + String insertSql = + String.format("INSERT INTO %s (%s) SELECT %s FROM %s_temp", tableName, newParamStr, + oldParamStr, tableName); + ALog.d(TAG, "insertSql = " + insertSql); + db.execSQL(insertSql); + } + //删除中介表 + mDelegate.dropTable(db, tableName + "_temp"); + } + } + db.setTransactionSuccessful(); + } catch (Exception e) { + ALog.e(TAG, e); + } finally { + db.endTransaction(); + } + + mDelegate.close(db); + } + + /** + * 处理3.6以下版本的数据库升级 + */ + private void handle360AriaUpdate(SQLiteDatabase db) { + String[] taskTables = + new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" }; + for (String taskTable : taskTables) { + if (mDelegate.tableExists(db, taskTable)) { + mDelegate.dropTable(db, taskTable); + } + } + Map> columnMap = new HashMap<>(); + Map map = new HashMap<>(); + map.put("groupName", "groupHash"); + columnMap.put("DownloadEntity", map); + columnMap.put("DownloadGroupEntity", map); + handleDbUpdate(db, columnMap, null); + } + + /** + * 处理3.4版本之前数据库迁移,主要是修改子表外键字段对应的值 + */ + private void handle314AriaUpdate(SQLiteDatabase db) { + String[] taskTables = + new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" }; + for (String taskTable : taskTables) { + if (mDelegate.tableExists(db, taskTable)) { + mDelegate.dropTable(db, taskTable); + } + } + + //删除所有主键为null和逐渐重复的数据 + String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" }; + String[] keys = new String[] { "downloadPath", "groupName" }; + int i = 0; + for (String tableName : tables) { + String pColumn = keys[i]; + String nullSql = + String.format("DELETE FROM %s WHERE %s='' OR %s IS NULL", tableName, pColumn, pColumn); + ALog.d(TAG, nullSql); + db.execSQL(nullSql); + + //删除所有主键重复的数据 + String repeatSql = + String.format( + "DELETE FROM %s WHERE %s IN(SELECT %s FROM %s GROUP BY %s HAVING COUNT(%s) > 1)", + tableName, pColumn, pColumn, tableName, pColumn, pColumn); + + ALog.d(TAG, repeatSql); + db.execSQL(repeatSql); + i++; + } + + Map> modifyColumnMap = new HashMap<>(); + Map map = new HashMap<>(); + map.put("groupName", "groupHash"); + modifyColumnMap.put("DownloadEntity", map); + modifyColumnMap.put("DownloadGroupEntity", map); + + Map> delColumnMap = new HashMap<>(); + List dEntityDel = new ArrayList<>(); + dEntityDel.add("taskKey"); + delColumnMap.put("DownloadEntity", dEntityDel); + List dgEntityDel = new ArrayList<>(); + dgEntityDel.add("subtask"); + delColumnMap.put("DownloadGroupEntity", dgEntityDel); + + handleDbUpdate(db, modifyColumnMap, delColumnMap); + } } \ No newline at end of file diff --git a/README.md b/README.md index 249a8790..6e5333f2 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,9 @@ Aria项目源于工作中遇到的一个文件下载管理的需求,当时被 Aria有以下特点: + 简单、方便 - 可以在Activity、Service、Fragment、Dialog、popupWindow、Notification等组件中使用 - - 支持HTTP\FTP断点续传、多任务自动调度 - - 支持HTTP任务组\FTP文件夹,断点续传下载 + - 支持HTTP\FTP断点续传下载、多任务自动调度 + - 支持多文件打包下载,多文件共享同一进度(如:视频 + 封面 + 字幕) + - 支持下载FTP文件夹 - 支持HTTP表单上传 - 支持文件FTP断点续传上传 - 支持FTPS/SFTP断点续传,[see](https://aria.laoyuyu.me/aria_doc/download/ftps.html) @@ -23,12 +24,17 @@ Aria有以下特点: 如果你觉得Aria对你有帮助,您的star和issues将是对我最大支持.`^_^` ## 示例 +* 多任务下载 ![多任务下载](https://github.com/AriaLyy/DownloadUtil/blob/master/img/download_img.gif) + +* 速度限制 ![网速下载限制](https://github.com/AriaLyy/DownloadUtil/blob/master/img/max_speed.gif) -![下载任务组](https://github.com/AriaLyy/DownloadUtil/blob/master/img/download_group.gif) + +* 多文件打包下载 +![多文件打包下载](https://github.com/AriaLyy/DownloadUtil/blob/master/img/group_task.gif) -## 下载 +## 引入库 [![Core](https://api.bintray.com/packages/arialyy/maven/AriaApi/images/download.svg)](https://bintray.com/arialyy/maven/AriaApi/_latestVersion) [![Compiler](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion) diff --git a/img/group_task.gif b/img/group_task.gif new file mode 100644 index 00000000..799fa907 Binary files /dev/null and b/img/group_task.gif differ