Parcourir la source

使用aria 3.2.14尝试修复升级后部分手机下载进度不正常的问题

zengjiebin il y a 8 ans
Parent
commit
9cfdb04886
100 fichiers modifiés avec 2420 ajouts et 5515 suppressions
  1. 2 5
      Aria/build.gradle
  2. 144 44
      Aria/src/main/java/com/arialyy/aria/core/Aria.java
  3. 63 195
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  4. 38 150
      Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
  5. 129 343
      Aria/src/main/java/com/arialyy/aria/core/Configuration.java
  6. 0 83
      Aria/src/main/java/com/arialyy/aria/core/FtpUrlEntity.java
  7. 7 35
      Aria/src/main/java/com/arialyy/aria/core/WidgetLiftManager.java
  8. 1 2
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
  9. 2 4
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java
  10. 0 13
      Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java
  11. 6 33
      Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
  12. 3 5
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java
  13. 19 26
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java
  14. 40 5
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
  15. 3 5
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java
  16. 13 49
      Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java
  17. 5 6
      Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
  18. 35 9
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
  19. 3 10
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
  20. 3 9
      Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
  21. 19 22
      Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java
  22. 25 84
      Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
  23. 9 103
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
  24. 2 2
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java
  25. 4 4
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
  26. 123 239
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  27. 0 298
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpInfoThread.java
  28. 0 141
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpThreadTask.java
  29. 65 126
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  30. 0 31
      Aria/src/main/java/com/arialyy/aria/core/common/CompleteInfo.java
  31. 9 9
      Aria/src/main/java/com/arialyy/aria/core/common/IUtil.java
  32. 0 32
      Aria/src/main/java/com/arialyy/aria/core/common/OnFileInfoCallback.java
  33. 7 36
      Aria/src/main/java/com/arialyy/aria/core/common/ProxyHelper.java
  34. 0 45
      Aria/src/main/java/com/arialyy/aria/core/common/RecordWrapper.java
  35. 8 8
      Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java
  36. 1 1
      Aria/src/main/java/com/arialyy/aria/core/common/SubThreadConfig.java
  37. 0 82
      Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java
  38. 0 50
      Aria/src/main/java/com/arialyy/aria/core/common/ThreadRecord.java
  39. 0 66
      Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java
  40. 0 139
      Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java
  41. 0 97
      Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java
  42. 19 47
      Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java
  43. 116 79
      Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java
  44. 0 182
      Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
  45. 15 16
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java
  46. 38 15
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
  47. 4 34
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
  48. 21 201
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  49. 18 35
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
  50. 4 36
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java
  51. 1 1
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadListener.java
  52. 67 217
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  53. 94 46
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  54. 24 29
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
  55. 8 79
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java
  56. 58 60
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
  57. 74 46
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  58. 155 0
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsFtpInfoThread.java
  59. 142 270
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  60. 8 30
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
  61. 21 43
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  62. 29 32
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  63. 118 0
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpClientHelp.java
  64. 14 33
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
  65. 11 36
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java
  66. 0 16
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java
  67. 45 53
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  68. 40 115
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  69. 37 104
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
  70. 1 10
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadGroupListener.java
  71. 17 0
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/OnFileInfoCallback.java
  72. 14 22
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
  73. 0 44
      Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGEWrapper.java
  74. 0 44
      Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGSTEWrapper.java
  75. 0 65
      Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGTEWrapper.java
  76. 0 46
      Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DTEWrapper.java
  77. 150 0
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java
  78. 4 27
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
  79. 4 32
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java
  80. 5 39
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
  81. 0 26
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTaskEntity.java
  82. 5 3
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java
  83. 3 2
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java
  84. 0 23
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTaskEntity.java
  85. 1 8
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java
  86. 75 110
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  87. 18 32
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
  88. 36 154
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java
  89. 80 0
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java
  90. 0 34
      Aria/src/main/java/com/arialyy/aria/core/inf/GroupSendParams.java
  91. 3 3
      Aria/src/main/java/com/arialyy/aria/core/inf/IEntity.java
  92. 1 3
      Aria/src/main/java/com/arialyy/aria/core/inf/IEventListener.java
  93. 0 43
      Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java
  94. 0 52
      Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java
  95. 5 1
      Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java
  96. 24 20
      Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
  97. 3 2
      Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
  98. 2 0
      Aria/src/main/java/com/arialyy/aria/core/inf/IUploadListener.java
  99. 0 169
      Aria/src/main/java/com/arialyy/aria/core/manager/DGTEFactory.java
  100. 0 0
      Aria/src/main/java/com/arialyy/aria/core/manager/DTEFactory.java

+ 2 - 5
Aria/build.gradle

@@ -16,16 +16,13 @@ android {
       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
     }
   }
-  lintOptions {
-    abortOnError false
-  }
 }
 
 dependencies {
   compile 'com.android.support:appcompat-v7:27.1.0'
   compile project(':AriaAnnotations')
-  compile 'com.arialyy.aria:aria-ftp-plug:1.0.3'
+  compile 'com.arialyy.aria:aria-ftp-plug:1.0.0'
+//  compile project(':AriaFtpPlug')
 
-  //  compile project(':AriaFtpPlug')
 }
 apply from: 'bintray-release.gradle'

+ 144 - 44
Aria/src/main/java/com/arialyy/aria/core/Aria.java

@@ -17,10 +17,23 @@
 package com.arialyy.aria.core;
 
 import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.Application;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.app.Service;
 import android.content.Context;
 import android.os.Build;
+import android.widget.PopupWindow;
+import com.arialyy.annotations.Download;
+import com.arialyy.annotations.Upload;
 import com.arialyy.aria.core.download.DownloadReceiver;
+import com.arialyy.aria.core.scheduler.IDownloadSchedulerListener;
+import com.arialyy.aria.core.scheduler.ISchedulerListener;
+import com.arialyy.aria.core.download.DownloadTask;
 import com.arialyy.aria.core.upload.UploadReceiver;
+import com.arialyy.aria.core.upload.UploadTask;
 
 /**
  * Created by lyy on 2016/12/1.
@@ -44,24 +57,6 @@ import com.arialyy.aria.core.upload.UploadReceiver;
  *        .start();
  *   </code>
  * </pre>
- *
- * 如果你需要在【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】
- * 之外的java中使用Aria,那么你应该在Application或Activity初始化的时候调用{@link #init(Context)}对Aria进行初始化
- * 然后才能使用{@link #download(Object)}、{@link #upload(Object)}
- *
- * <pre>
- *   <code>
- *       Aria.init(getContext());
- *
- *      Aria.download(this)
- *       .load(URL)     //下载地址,必填
- *       //文件保存路径,必填
- *       .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk")
- *       .start();
- *
- *   </code>
- *
- * </pre>
  */
 @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) public class Aria {
 
@@ -71,53 +66,158 @@ import com.arialyy.aria.core.upload.UploadReceiver;
   /**
    * 初始化下载
    *
-   * @param context 支持类型有【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】
+   * @param obj 支持类型有【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】
    */
-  public static DownloadReceiver download(Context context) {
-    return get(context).download(context);
+  public static DownloadReceiver download(Object obj) {
+    return get(obj).download(obj);
   }
 
   /**
    * 初始化上传
    *
-   * @param context 支持类型有【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】
+   * @param obj 支持类型有【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】
    */
-  public static UploadReceiver upload(Context context) {
-    return get(context).upload(context);
+  public static UploadReceiver upload(Object obj) {
+    return get(obj).upload(obj);
   }
 
   /**
-   * 在任意对象中初始化下载,前提是你需要在Application或Activity初始化的时候调用{@link #init(Context)}对Aria进行初始化
+   * 处理通用事件
    *
-   * @param obj 任意对象
+   * @param obj 支持类型有【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】
    */
-  public static DownloadReceiver download(Object obj) {
-    return AriaManager.getInstance().download(obj);
+  public static AriaManager get(Object obj) {
+    if (obj instanceof Activity || obj instanceof Service || obj instanceof Application) {
+      return AriaManager.getInstance((Context) obj);
+    } else if (obj instanceof DialogFragment) {
+      DialogFragment dialog = (DialogFragment) obj;
+      return AriaManager.getInstance(
+          Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? dialog.getContext()
+              : dialog.getActivity());
+    } else if (obj instanceof android.support.v4.app.Fragment) {
+      android.support.v4.app.Fragment fragment = (android.support.v4.app.Fragment) obj;
+      return AriaManager.getInstance(
+          Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
+              : fragment.getActivity());
+    } else if (obj instanceof Fragment) {
+      Fragment fragment = (Fragment) obj;
+      return AriaManager.getInstance(
+          Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
+              : fragment.getActivity());
+    } else if (obj instanceof PopupWindow) {
+      PopupWindow popupWindow = (PopupWindow) obj;
+      return AriaManager.getInstance(popupWindow.getContentView().getContext());
+    } else if (obj instanceof Dialog) {
+      Dialog dialog = (Dialog) obj;
+      return AriaManager.getInstance(dialog.getContext());
+    } else {
+      throw new IllegalArgumentException("不支持的类型");
+    }
   }
 
   /**
-   * 在任意对象中初始化上传,前提是你需要在Application或Activity初始化的时候调用{@link #init(Context)}对Aria进行初始化
+   * 上传任务状态监听
    *
-   * @param obj 任意对象
+   * @see Upload
+   * @deprecated 请使用注解函数的方式来实现事件的获取
    */
-  public static UploadReceiver upload(Object obj) {
-    return AriaManager.getInstance().upload(obj);
-  }
+  @Deprecated public static class UploadSchedulerListener
+      implements ISchedulerListener<UploadTask> {
 
-  /**
-   * 处理通用事件
-   */
-  public static AriaManager get(Context context) {
-    return AriaManager.getInstance(context);
+    /**
+     * 预处理,有时有些地址链接比较慢,这时可以先在这个地方出来一些界面上的UI,如按钮的状态。
+     *
+     * @param task 上传文物实体
+     */
+    @Override public void onPre(UploadTask task) {
+
+    }
+
+    @Override public void onTaskPre(UploadTask task) {
+
+    }
+
+    @Override public void onTaskResume(UploadTask task) {
+
+    }
+
+    @Override public void onTaskStart(UploadTask task) {
+
+    }
+
+    @Override public void onTaskStop(UploadTask task) {
+
+    }
+
+    @Override public void onTaskCancel(UploadTask task) {
+
+    }
+
+    @Override public void onTaskFail(UploadTask task) {
+
+    }
+
+    @Override public void onTaskComplete(UploadTask task) {
+
+    }
+
+    @Override public void onTaskRunning(UploadTask task) {
+
+    }
   }
 
   /**
-   * 初始化Aria,如果你需要在【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】
-   * 之外的java中使用Aria,那么你应该在Application或Activity初始化的时候调用本方法对Aria进行初始化
-   * 只需要初始化一次就可以
-   * {@link #download(Object)}、{@link #upload(Object)}
+   * 下载任务状态监听
+   *
+   * @see Download
+   * @deprecated 请使用注解函数的方式来实现事件的获取
    */
-  public static AriaManager init(Context context) {
-    return AriaManager.getInstance(context);
+  @Deprecated public static class DownloadSchedulerListener
+      implements IDownloadSchedulerListener<DownloadTask> {
+    /**
+     * 预处理,有时有些地址链接比较慢,这时可以先在这个地方出来一些界面上的UI,如按钮的状态。
+     * 需要注意的是,在该回调中,是得不到文件长度的,如果需要获取文件长度,需要在onTaskPre中获取
+     *
+     * @param task 下载任务
+     */
+    @Override public void onPre(DownloadTask task) {
+
+    }
+
+    @Override public void onTaskPre(DownloadTask task) {
+
+    }
+
+    @Override public void onTaskResume(DownloadTask task) {
+
+    }
+
+    @Override public void onTaskStart(DownloadTask task) {
+
+    }
+
+    @Override public void onTaskStop(DownloadTask task) {
+
+    }
+
+    @Override public void onTaskCancel(DownloadTask task) {
+
+    }
+
+    @Override public void onTaskFail(DownloadTask task) {
+
+    }
+
+    @Override public void onTaskComplete(DownloadTask task) {
+
+    }
+
+    @Override public void onTaskRunning(DownloadTask task) {
+
+    }
+
+    @Override public void onNoSupportBreakPoint(DownloadTask task) {
+
+    }
   }
 }

+ 63 - 195
Aria/src/main/java/com/arialyy/aria/core/AriaManager.java

@@ -20,28 +20,20 @@ import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.Application;
 import android.app.Dialog;
+import android.app.Service;
 import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
 import android.support.v4.app.Fragment;
+import android.text.TextUtils;
+import android.util.Log;
 import android.widget.PopupWindow;
-import com.arialyy.aria.core.command.ICmd;
 import com.arialyy.aria.core.common.QueueMod;
-import com.arialyy.aria.core.download.DownloadEntity;
-import com.arialyy.aria.core.download.DownloadGroupEntity;
-import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
 import com.arialyy.aria.core.download.DownloadReceiver;
-import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.inf.AbsReceiver;
+import com.arialyy.aria.core.command.ICmd;
 import com.arialyy.aria.core.inf.IReceiver;
-import com.arialyy.aria.core.upload.UploadEntity;
 import com.arialyy.aria.core.upload.UploadReceiver;
-import com.arialyy.aria.core.upload.UploadTaskEntity;
-import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.orm.DelegateWrapper;
-import com.arialyy.aria.util.ALog;
-import com.arialyy.aria.util.AriaCrashHandler;
+import com.arialyy.aria.orm.DbUtil;
 import com.arialyy.aria.util.CommonUtil;
 import java.io.File;
 import java.io.IOException;
@@ -67,21 +59,18 @@ import org.xml.sax.SAXException;
   public static final Object LOCK = new Object();
   public static final String DOWNLOAD_TEMP_DIR = "/Aria/temp/download/";
   public static final String UPLOAD_TEMP_DIR = "/Aria/temp/upload/";
-
   @SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null;
-  private Map<String, AbsReceiver> mReceivers = new ConcurrentHashMap<>();
+  private Map<String, IReceiver> mReceivers = new ConcurrentHashMap<>();
   public static Context APP;
   private List<ICmd> mCommands = new ArrayList<>();
   private Configuration.DownloadConfig mDConfig;
   private Configuration.UploadConfig mUConfig;
-  private Configuration.AppConfig mAConfig;
 
   private AriaManager(Context context) {
+    DbUtil.init(context.getApplicationContext());
     APP = context.getApplicationContext();
-    initDb(APP);
     regAppLifeCallback(context);
     initConfig();
-    initAria();
   }
 
   public static AriaManager getInstance(Context context) {
@@ -93,67 +82,25 @@ import org.xml.sax.SAXException;
     return INSTANCE;
   }
 
-  static AriaManager getInstance() {
-    if (INSTANCE == null) {
-      throw new NullPointerException("请在Application或Activity初始化时调用一次Aria.init(context)方法进行初始化操作");
-    }
-    return INSTANCE;
-  }
-
-  private void initDb(Context context) {
-    String dbBase = context.getFilesDir().getPath() + context.getPackageName() + "/databases/";
-    File db = new File(dbBase + "AriaLyyDb");
-    File dbConfig = new File(dbBase + "AriaLyyDb-journal");
-    if (db.exists()) {
-      db.renameTo(new File(dbBase + "AndroidAria.db"));
-      // 如果数据库是在/data/data/{packagename}/databases/下面,journal文件因权限问题将无法删除和重命名
-      if (dbConfig.exists()) {
-        dbConfig.delete();
-      }
-    }
-    DelegateWrapper.init(context.getApplicationContext());
-  }
-
-  private void initAria() {
-    if (mAConfig.getUseAriaCrashHandler()) {
-      Thread.setDefaultUncaughtExceptionHandler(new AriaCrashHandler());
-    }
-    mAConfig.setLogLevel(mAConfig.getLogLevel());
-  }
-
-  public Map<String, AbsReceiver> getReceiver() {
+  public Map<String, IReceiver> getReceiver() {
     return mReceivers;
   }
 
   /**
-   * 设置上传任务的执行队列类型,后续版本会删除该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;
@@ -186,13 +133,6 @@ import org.xml.sax.SAXException;
   }
 
   /**
-   * 获取APP配置
-   */
-  public Configuration.AppConfig getAppConfig() {
-    return mAConfig;
-  }
-
-  /**
    * 设置命令
    */
   public AriaManager setCmd(ICmd command) {
@@ -242,127 +182,74 @@ import org.xml.sax.SAXException;
     return (receiver instanceof UploadReceiver) ? (UploadReceiver) receiver : null;
   }
 
-  /**
-   * 删除任务记录
-   *
-   * @param type 需要删除的任务类型,1、表示单任务下载。2、表示任务组下载。3、单任务上传
-   * @param key 下载为保存路径、任务组为任务组名、上传为上传文件路径
-   */
-  public void delRecord(int type, String key) {
-    switch (type) {
-      case 1:
-        DbEntity.deleteData(DownloadEntity.class, "url=?", key);
-        DbEntity.deleteData(DownloadTaskEntity.class, "key=? and isGroupTask='false'", key);
-        break;
-      case 2:
-        DbEntity.deleteData(DownloadGroupEntity.class, "groupName=?", key);
-        DbEntity.deleteData(DownloadGroupTaskEntity.class, "key=?", key);
-        break;
-      case 3:
-        DbEntity.deleteData(UploadEntity.class, "filePath=?", key);
-        DbEntity.deleteData(UploadTaskEntity.class, "key=?", key);
-        break;
-    }
-  }
-
   private IReceiver putReceiver(boolean isDownload, Object obj) {
     final String key = getKey(isDownload, obj);
     IReceiver receiver = mReceivers.get(key);
-    boolean needRmReceiver = false;
-    // 监控Dialog、fragment、popupWindow的生命周期
     final WidgetLiftManager widgetLiftManager = new WidgetLiftManager();
     if (obj instanceof Dialog) {
-      needRmReceiver = widgetLiftManager.handleDialogLift((Dialog) obj);
+      widgetLiftManager.handleDialogLift((Dialog) obj);
     } else if (obj instanceof PopupWindow) {
-      needRmReceiver = widgetLiftManager.handlePopupWindowLift((PopupWindow) obj);
-    } else if (obj instanceof DialogFragment) {
-      needRmReceiver = widgetLiftManager.handleDialogFragmentLift((DialogFragment) obj);
-    } else if (obj instanceof android.app.DialogFragment) {
-      needRmReceiver = widgetLiftManager.handleDialogFragmentLift((android.app.DialogFragment) obj);
+      widgetLiftManager.handlePopupWindowLift((PopupWindow) obj);
     }
 
     if (receiver == null) {
-      AbsReceiver absReceiver;
       if (isDownload) {
-        absReceiver = new DownloadReceiver();
+        DownloadReceiver dReceiver = new DownloadReceiver();
+        dReceiver.targetName = obj.getClass().getName();
+        dReceiver.obj = obj;
+        mReceivers.put(key, dReceiver);
+        receiver = dReceiver;
       } else {
-        absReceiver = new UploadReceiver();
+        UploadReceiver uReceiver = new UploadReceiver();
+        uReceiver.targetName = obj.getClass().getName();
+        uReceiver.obj = obj;
+        mReceivers.put(key, uReceiver);
+        receiver = uReceiver;
       }
-      receiver = checkTarget(key, absReceiver, obj, needRmReceiver);
     }
     return receiver;
   }
 
   /**
-   * 不允许在"onDestroy"、"finish"、"onStop"这三个方法中添加注册器
-   */
-  private AbsReceiver checkTarget(String key, AbsReceiver receiver, Object obj,
-      boolean needRmReceiver) {
-    StackTraceElement[] stack = Thread.currentThread().getStackTrace();
-    int i = 0;
-    for (StackTraceElement e : stack) {
-      String name = e.getClassName();
-      if (!name.equals(AriaManager.class.getName())) {
-        i++;
-      } else {
-        break;
-      }
-    }
-    i += 4;
-    String methodName = stack[i].getMethodName();
-    boolean isDestroyed =
-        methodName.equals("onDestroy") || methodName.equals("finish") || methodName.equals(
-            "onStop");
-
-    if (isDestroyed) {
-      ALog.e(TAG,
-          "请不要在Activity或Fragment的onDestroy、finish、onStop等方法中注册Aria,Aria的unRegister会在Activity页面销毁时自动执行");
-    }
-
-    if (obj instanceof Activity && isDestroyed) {
-      return receiver;
-    } else if (obj instanceof Fragment && isDestroyed) {
-      return receiver;
-    }
-    receiver.targetName = obj.getClass().getName();
-    receiver.obj = obj;
-    receiver.needRmListener = needRmReceiver;
-    mReceivers.put(key, receiver);
-    return receiver;
-  }
-
-  /**
    * 根据功能类型和控件类型获取对应的key
    */
   private String getKey(boolean isDownload, Object obj) {
     String clsName = obj.getClass().getName();
-    String key;
-    if (obj instanceof DialogFragment) {
-      key = clsName + "_" + ((DialogFragment) obj).getActivity().getClass().getName();
-    } else if (obj instanceof android.app.DialogFragment) {
-      key = clsName + "_" + ((android.app.DialogFragment) obj).getActivity().getClass().getName();
-    } else if (obj instanceof android.support.v4.app.Fragment) {
-      key = clsName + "_" + ((Fragment) obj).getActivity().getClass().getName();
-    } else if (obj instanceof android.app.Fragment) {
-      key = clsName + "_" + ((android.app.Fragment) obj).getActivity().getClass().getName();
-    } else if (obj instanceof Dialog) {
-      Activity activity = ((Dialog) obj).getOwnerActivity();
-      if (activity != null) {
-        key = clsName + "_" + activity.getClass().getName();
-      } else {
+    String key = "";
+    if (!(obj instanceof Activity)) {
+      if (obj instanceof android.support.v4.app.Fragment) {
+        key = clsName + "_" + ((Fragment) obj).getActivity().getClass().getName();
+      } else if (obj instanceof android.app.Fragment) {
+        key = clsName + "_" + ((android.app.Fragment) obj).getActivity().getClass().getName();
+      } else if (obj instanceof Dialog) {
+        Activity activity = ((Dialog) obj).getOwnerActivity();
+        if (activity != null) {
+          key = clsName + "_" + activity.getClass().getName();
+        } else {
+          key = clsName;
+        }
+      } else if (obj instanceof PopupWindow) {
+        Context context = ((PopupWindow) obj).getContentView().getContext();
+        if (context instanceof Activity) {
+          key = clsName + "_" + context.getClass().getName();
+        } else {
+          key = clsName;
+        }
+      } else if (obj instanceof Service) {
         key = clsName;
-      }
-    } else if (obj instanceof PopupWindow) {
-      Context context = ((PopupWindow) obj).getContentView().getContext();
-      if (context instanceof Activity) {
-        key = clsName + "_" + context.getClass().getName();
-      } else {
+      } else if (obj instanceof Application) {
         key = clsName;
       }
-    } else {
+    }
+    if (obj instanceof Activity || obj instanceof Service) {
       key = clsName;
+    } else if (obj instanceof Application) {
+      key = clsName;
+    }
+    if (TextUtils.isEmpty(key)) {
+      throw new IllegalArgumentException("未知类型");
     }
-    key += (isDownload ? DOWNLOAD : UPLOAD) + obj.hashCode();
+    key += isDownload ? DOWNLOAD : UPLOAD;
     return key;
   }
 
@@ -377,7 +264,7 @@ import org.xml.sax.SAXException;
     } else {
       try {
         String md5Code = CommonUtil.getFileMD5(xmlFile);
-        File file = new File(APP.getFilesDir().getPath() + "/temp.xml");
+        File file = new File(APP.getFilesDir().getPath() + "temp.xml");
         if (file.exists()) {
           file.delete();
         }
@@ -392,7 +279,6 @@ import org.xml.sax.SAXException;
     }
     mDConfig = Configuration.DownloadConfig.getInstance();
     mUConfig = Configuration.UploadConfig.getInstance();
-    mAConfig = Configuration.AppConfig.getInstance();
     if (tempDir.exists()) {
       File newDir = new File(APP.getFilesDir().getPath() + DOWNLOAD_TEMP_DIR);
       newDir.mkdirs();
@@ -412,7 +298,7 @@ import org.xml.sax.SAXException;
       CommonUtil.createFileFormInputStream(APP.getAssets().open("aria_config.xml"),
           APP.getFilesDir().getPath() + Configuration.XML_FILE);
     } catch (ParserConfigurationException | IOException | SAXException e) {
-      ALog.e(TAG, e.toString());
+      Log.e(TAG, e.toString());
     }
   }
 
@@ -422,42 +308,25 @@ import org.xml.sax.SAXException;
   private void regAppLifeCallback(Context context) {
     Context app = context.getApplicationContext();
     if (app instanceof Application) {
-      LifeCallback lifeCallback = new LifeCallback();
-      ((Application) app).registerActivityLifecycleCallbacks(lifeCallback);
-    }
-  }
-
-  /**
-   * 移除指定对象的receiver
-   */
-  public void removeReceiver(Object obj) {
-    if (obj == null) return;
-    String clsName = obj.getClass().getName();
-    for (Iterator<Map.Entry<String, AbsReceiver>> iter = mReceivers.entrySet().iterator();
-        iter.hasNext(); ) {
-      Map.Entry<String, AbsReceiver> entry = iter.next();
-      String key = entry.getKey();
-      if (key.contains(clsName)) {
-        iter.remove();
-      }
+      LifeCallback mLifeCallback = new LifeCallback();
+      ((Application) app).registerActivityLifecycleCallbacks(mLifeCallback);
     }
   }
 
   /**
-   * Aria注册对象被销毁时调用
+   * onDestroy
    */
   void destroySchedulerListener(Object obj) {
     String clsName = obj.getClass().getName();
-    for (Iterator<Map.Entry<String, AbsReceiver>> iter = mReceivers.entrySet().iterator();
+    for (Iterator<Map.Entry<String, IReceiver>> iter = mReceivers.entrySet().iterator();
         iter.hasNext(); ) {
-      Map.Entry<String, AbsReceiver> entry = iter.next();
+      Map.Entry<String, IReceiver> entry = iter.next();
       String key = entry.getKey();
       if (key.contains(clsName)) {
-        AbsReceiver receiver = mReceivers.get(key);
-        if (receiver != null) {
-          receiver.unRegisterListener();
-          receiver.destroy();
-        }
+        IReceiver receiver = mReceivers.get(key);
+        receiver.removeSchedulerListener();
+        receiver.unRegister();
+        receiver.destroy();
         iter.remove();
       }
     }
@@ -494,7 +363,6 @@ import org.xml.sax.SAXException;
 
     @Override public void onActivityDestroyed(Activity activity) {
       destroySchedulerListener(activity);
-      // TODO: 2018/4/11 维护一个activity堆栈,应用被kill,activity会回调onDestroy方法,需要考虑server后台情况
     }
   }
 }

+ 38 - 150
Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java

@@ -16,7 +16,7 @@
 package com.arialyy.aria.core;
 
 import android.text.TextUtils;
-import com.arialyy.aria.util.ALog;
+import android.util.Log;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
@@ -28,10 +28,9 @@ import org.xml.sax.helpers.DefaultHandler;
 class ConfigHelper extends DefaultHandler {
   private final String TAG = "ConfigHelper";
 
-  private boolean isDownloadConfig = false, isUploadConfig = false, isAppConfig = false;
+  private boolean isDownloadConfig = false, isUploadConfig;
   private Configuration.DownloadConfig mDownloadConfig = Configuration.DownloadConfig.getInstance();
   private Configuration.UploadConfig mUploadConfig = Configuration.UploadConfig.getInstance();
-  private Configuration.AppConfig mAppConfig = Configuration.AppConfig.getInstance();
 
   @Override public void startDocument() throws SAXException {
     super.startDocument();
@@ -44,24 +43,14 @@ class ConfigHelper extends DefaultHandler {
     if (qName.equals("download")) {
       isDownloadConfig = true;
       isUploadConfig = false;
-      isAppConfig = false;
     } else if (qName.equals("upload")) {
       isUploadConfig = true;
       isDownloadConfig = false;
-      isAppConfig = false;
-    } else if (qName.equals("app")) {
-      isUploadConfig = false;
-      isDownloadConfig = false;
-      isAppConfig = true;
     }
-
     if (isDownloadConfig || isUploadConfig) {
 
       String value = attributes.getValue("value");
       switch (qName) {
-        case "openDynamicFile":
-          loadOpenDynamicFile(value);
-          break;
         case "threadNum":
           loadThreadNum(value);
           break;
@@ -97,73 +86,7 @@ class ConfigHelper extends DefaultHandler {
         case "queueMod":
           loadQueueMod(value);
           break;
-        case "updateInterval":
-          loadUpdateInterval(value);
-          break;
-        case "notNetRetry":
-          loadNotNetRetry(value);
-          break;
       }
-    } else if (isAppConfig) {
-      String value = attributes.getValue("value");
-      switch (qName) {
-        case "useAriaCrashHandler":
-          loadUseAriaCrashHandler(value);
-          break;
-        case "logLevel":
-          loadLogLevel(value);
-          break;
-      }
-    }
-  }
-
-  private void loadOpenDynamicFile(String value) {
-    if (isDownloadConfig) {
-      mDownloadConfig.openDynamicFile = checkBoolean(value) ? Boolean.valueOf(value) : false;
-    }
-  }
-
-  private void loadNotNetRetry(String value) {
-    if (isDownloadConfig) {
-      mDownloadConfig.notNetRetry = checkBoolean(value) ? Boolean.valueOf(value) : false;
-    }
-    if (isUploadConfig) {
-      mUploadConfig.notNetRetry = checkBoolean(value) ? Boolean.valueOf(value) : false;
-    }
-  }
-
-  private void loadLogLevel(String value) {
-    int level;
-    try {
-      level = Integer.parseInt(value);
-    } catch (NumberFormatException e) {
-      e.printStackTrace();
-      level = ALog.LOG_LEVEL_VERBOSE;
-    }
-    if (level < ALog.LOG_LEVEL_VERBOSE || level > ALog.LOG_CLOSE) {
-      ALog.w(TAG, "level【" + level + "】错误");
-      mAppConfig.logLevel = ALog.LOG_LEVEL_VERBOSE;
-    } else {
-      mAppConfig.logLevel = level;
-    }
-  }
-
-  private void loadUseAriaCrashHandler(String value) {
-    if (checkBoolean(value)) {
-      mAppConfig.useAriaCrashHandler = Boolean.parseBoolean(value);
-    } else {
-      ALog.w(TAG, "useAriaCrashHandler【" + value + "】错误");
-      mAppConfig.useAriaCrashHandler = true;
-    }
-  }
-
-  private void loadUpdateInterval(String value) {
-    long temp = checkLong(value) ? Long.parseLong(value) : 1000;
-    if (isDownloadConfig) {
-      mDownloadConfig.updateInterval = temp;
-    }
-    if (isUploadConfig) {
-      mUploadConfig.updateInterval = temp;
     }
   }
 
@@ -182,18 +105,17 @@ class ConfigHelper extends DefaultHandler {
   }
 
   private void loadMaxSpeed(String value) {
-    int maxSpeed = checkInt(value) ? Integer.parseInt(value) : 0;
+    double maxSpeed = 0.0;
+    if (!TextUtils.isEmpty(value)) {
+      maxSpeed = Double.parseDouble(value);
+    }
     if (isDownloadConfig) {
-      mDownloadConfig.maxSpeed = maxSpeed;
+      mDownloadConfig.msxSpeed = maxSpeed;
     }
   }
 
   private void loadConvertSpeed(String value) {
-    boolean open = true;
-    if (checkBoolean(value)) {
-      open = Boolean.parseBoolean(value);
-    }
-
+    boolean open = Boolean.parseBoolean(value);
     if (isDownloadConfig) {
       mDownloadConfig.isConvertSpeed = open;
     }
@@ -203,7 +125,10 @@ class ConfigHelper extends DefaultHandler {
   }
 
   private void loadReTryInterval(String value) {
-    int time = checkInt(value) ? Integer.parseInt(value) : 2 * 1000;
+    int time = 2 * 1000;
+    if (!TextUtils.isEmpty(value)) {
+      time = Integer.parseInt(value);
+    }
 
     if (time < 2 * 1000) {
       time = 2 * 1000;
@@ -222,7 +147,10 @@ class ConfigHelper extends DefaultHandler {
   }
 
   private void loadBuffSize(String value) {
-    int buffSize = checkInt(value) ? Integer.parseInt(value) : 8192;
+    int buffSize = 8192;
+    if (!TextUtils.isEmpty(value)) {
+      buffSize = Integer.parseInt(value);
+    }
 
     if (buffSize < 2048) {
       buffSize = 2048;
@@ -231,14 +159,13 @@ class ConfigHelper extends DefaultHandler {
     if (isDownloadConfig) {
       mDownloadConfig.buffSize = buffSize;
     }
-
-    if (isUploadConfig) {
-      mUploadConfig.buffSize = buffSize;
-    }
   }
 
   private void loadIOTimeout(String value) {
-    int time = checkInt(value) ? Integer.parseInt(value) : 10 * 1000;
+    int time = 10 * 1000;
+    if (!TextUtils.isEmpty(value)) {
+      time = Integer.parseInt(value);
+    }
 
     if (time < 10 * 1000) {
       time = 10 * 1000;
@@ -247,14 +174,13 @@ class ConfigHelper extends DefaultHandler {
     if (isDownloadConfig) {
       mDownloadConfig.iOTimeOut = time;
     }
-
-    if (isUploadConfig) {
-      mUploadConfig.iOTimeOut = time;
-    }
   }
 
   private void loadConnectTime(String value) {
-    int time = checkInt(value) ? Integer.parseInt(value) : 5 * 1000;
+    int time = 5 * 1000;
+    if (!TextUtils.isEmpty(value)) {
+      time = Integer.parseInt(value);
+    }
 
     if (isDownloadConfig) {
       mDownloadConfig.connectTimeOut = time;
@@ -265,7 +191,10 @@ class ConfigHelper extends DefaultHandler {
   }
 
   private void loadReTry(String value) {
-    int num = checkInt(value) ? Integer.parseInt(value) : 0;
+    int num = 0;
+    if (!TextUtils.isEmpty(value)) {
+      num = Integer.parseInt(value);
+    }
 
     if (isDownloadConfig) {
       mDownloadConfig.reTryNum = num;
@@ -276,9 +205,12 @@ class ConfigHelper extends DefaultHandler {
   }
 
   private void loadMaxQueue(String value) {
-    int num = checkInt(value) ? Integer.parseInt(value) : 2;
+    int num = 2;
+    if (!TextUtils.isEmpty(value)) {
+      num = Integer.parseInt(value);
+    }
     if (num < 1) {
-      ALog.w(TAG, "任务队列数不能小于 1");
+      Log.e(TAG, "任务队列数不能小于 1");
       num = 2;
     }
     if (isDownloadConfig) {
@@ -290,9 +222,12 @@ class ConfigHelper extends DefaultHandler {
   }
 
   private void loadThreadNum(String value) {
-    int num = checkInt(value) ? Integer.parseInt(value) : 3;
+    int num = 3;
+    if (!TextUtils.isEmpty(value)) {
+      num = Integer.parseInt(value);
+    }
     if (num < 1) {
-      ALog.e(TAG, "下载线程数不能小于 1");
+      Log.e(TAG, "下载线程数不能小于 1");
       num = 1;
     }
     if (isDownloadConfig) {
@@ -300,52 +235,6 @@ class ConfigHelper extends DefaultHandler {
     }
   }
 
-  /**
-   * 检查是否int值是否合法
-   *
-   * @return {@code true} 合法
-   */
-  private boolean checkInt(String value) {
-    if (TextUtils.isEmpty(value)) {
-      return false;
-    }
-    try {
-      Integer l = Integer.parseInt(value);
-      return true;
-    } catch (NumberFormatException e) {
-      e.printStackTrace();
-      return false;
-    }
-  }
-
-  /**
-   * 检查是否long值是否合法
-   *
-   * @return {@code true} 合法
-   */
-  private boolean checkLong(String value) {
-    if (TextUtils.isEmpty(value)) {
-      return false;
-    }
-    try {
-      Long l = Long.parseLong(value);
-      return true;
-    } catch (NumberFormatException e) {
-      e.printStackTrace();
-      return false;
-    }
-  }
-
-  /**
-   * 检查boolean值是否合法
-   *
-   * @return {@code true} 合法
-   */
-  private boolean checkBoolean(String value) {
-    return !TextUtils.isEmpty(value) && (value.equalsIgnoreCase("true") || value.equalsIgnoreCase(
-        "false"));
-  }
-
   @Override public void characters(char[] ch, int start, int length) throws SAXException {
     super.characters(ch, start, length);
   }
@@ -358,6 +247,5 @@ class ConfigHelper extends DefaultHandler {
     super.endDocument();
     mDownloadConfig.saveAll();
     mUploadConfig.saveAll();
-    mAppConfig.saveAll();
   }
 }

+ 129 - 343
Aria/src/main/java/com/arialyy/aria/core/Configuration.java

@@ -18,11 +18,7 @@ package com.arialyy.aria.core;
 import android.text.TextUtils;
 import com.arialyy.aria.core.common.QueueMod;
 import com.arialyy.aria.core.queue.DownloadTaskQueue;
-import com.arialyy.aria.core.queue.UploadTaskQueue;
-import com.arialyy.aria.util.ALog;
-import com.arialyy.aria.util.AriaCrashHandler;
 import com.arialyy.aria.util.CommonUtil;
-import com.arialyy.aria.util.ErrorHelp;
 import java.io.File;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -34,175 +30,14 @@ import java.util.Properties;
  * 信息配置
  */
 class Configuration {
-  static final String TAG = "Configuration";
   static final String DOWNLOAD_CONFIG_FILE = "/Aria/DownloadConfig.properties";
   static final String UPLOAD_CONFIG_FILE = "/Aria/UploadConfig.properties";
-  static final String APP_CONFIG_FILE = "/Aria/AppConfig.properties";
   static final String XML_FILE = "/Aria/aria_config.xml";
-  static final int TYPE_DOWNLOAD = 1;
-  static final int TYPE_UPLOAD = 2;
-  static final int TYPE_APP = 3;
-
-  abstract static class BaseConfig {
-
-    /**
-     * 类型
-     *
-     * @return {@link #TYPE_DOWNLOAD}、{@link #TYPE_UPLOAD}、{@link #TYPE_APP}
-     */
-    abstract int getType();
-
-    /**
-     * 加载配置
-     */
-    void loadConfig() {
-      String path = null;
-      Class clazz = null;
-      switch (getType()) {
-        case TYPE_DOWNLOAD:
-          path = DOWNLOAD_CONFIG_FILE;
-          clazz = DownloadConfig.class;
-          break;
-        case TYPE_UPLOAD:
-          path = UPLOAD_CONFIG_FILE;
-          clazz = UploadConfig.class;
-          break;
-        case TYPE_APP:
-          path = APP_CONFIG_FILE;
-          clazz = AppConfig.class;
-          break;
-      }
-      if (TextUtils.isEmpty(path)) {
-        ALog.e(TAG, "读取配置失败:未知文件类型");
-        ErrorHelp.saveError(TAG, "读取配置失败:未知文件类型", "");
-        return;
-      }
-
-      File file = new File(AriaManager.APP.getFilesDir().getPath() + path);
-      if (file.exists()) {
-        Properties properties = CommonUtil.loadConfig(file);
-        List<Field> fields = CommonUtil.getAllFields(clazz);
-        try {
-          for (Field field : fields) {
-            int m = field.getModifiers();
-            String fileName = field.getName();
-            if (fileName.equals("oldMaxTaskNum")
-                || field.isSynthetic()
-                || Modifier.isFinal(m)
-                || Modifier.isStatic(m)
-                || fileName.equals("shadow$_klass_")
-                || fileName.equals("shadow$_monitor_")) {
-              continue;
-            }
-            field.setAccessible(true);
-            String value = properties.getProperty(field.getName());
-            if (TextUtils.isEmpty(value) || value.equalsIgnoreCase("null")) continue;
-            Class<?> type = field.getType();
-            if (type == String.class) {
-              field.set(this, value);
-            } else if (type == int.class || type == Integer.class) {
-              if (fileName.equalsIgnoreCase("maxSpeed")) { //兼容以前版本,以前maxSpeed是double类型的
-                Double d = Double.parseDouble(value);
-                field.setInt(this, (int) d.doubleValue());
-              } else {
-                field.setInt(this, Integer.parseInt(value));
-              }
-            } else if (type == float.class || type == Float.class) {
-              field.setFloat(this, Float.parseFloat(value));
-            } else if (type == double.class || type == Double.class) {
-              if (TextUtils.isEmpty(value)) {
-                value = "0";
-              }
-              field.setDouble(this, Double.parseDouble(value));
-            } else if (type == long.class || type == Long.class) {
-              field.setLong(this, Long.parseLong(value));
-            } else if (type == boolean.class || type == Boolean.class) {
-              field.setBoolean(this, Boolean.parseBoolean(value));
-            }
-          }
-        } catch (IllegalAccessException e) {
-          e.printStackTrace();
-        }
-      }
-    }
-
-    /**
-     * 保存key
-     */
-    void saveKey(String key, String value) {
-      String path = null;
-      switch (getType()) {
-        case TYPE_DOWNLOAD:
-          path = DOWNLOAD_CONFIG_FILE;
-          break;
-        case TYPE_UPLOAD:
-          path = UPLOAD_CONFIG_FILE;
-          break;
-        case TYPE_APP:
-          path = APP_CONFIG_FILE;
-          break;
-      }
-      File file = new File(
-          AriaManager.APP.getFilesDir().getPath() + path);
-      if (file.exists()) {
-        Properties properties = CommonUtil.loadConfig(file);
-        properties.setProperty(key, value);
-        CommonUtil.saveConfig(file, properties);
-      }
-    }
-
-    /**
-     * 保存配置
-     */
-    void saveAll() {
-      List<Field> fields = CommonUtil.getAllFields(getClass());
-      try {
-        String path = null;
-        switch (getType()) {
-          case TYPE_DOWNLOAD:
-            path = DOWNLOAD_CONFIG_FILE;
-            break;
-          case TYPE_UPLOAD:
-            path = UPLOAD_CONFIG_FILE;
-            break;
-          case TYPE_APP:
-            path = APP_CONFIG_FILE;
-            break;
-        }
-        File file = new File(
-            AriaManager.APP.getFilesDir().getPath() + path);
-        Properties properties = CommonUtil.loadConfig(file);
-        for (Field field : fields) {
-          int m = field.getModifiers();
-          if (field.isSynthetic() || Modifier.isFinal(m) || Modifier.isStatic(m) || field.getName()
-              .equals("shadow$_klass_") || field.getName().equals("shadow$_monitor_")) {
-            continue;
-          }
-          field.setAccessible(true);
-          properties.setProperty(field.getName(), field.get(this) + "");
-        }
-        CommonUtil.saveConfig(file, properties);
-      } catch (IllegalAccessException e) {
-        e.printStackTrace();
-      }
-    }
-  }
 
   /**
-   * 通用任务配置
+   * 通用配置
    */
-  abstract static class BaseTaskConfig extends BaseConfig {
-
-    /**
-     * 设置写文件buff大小,该数值大小不能小于2048,数值变小,下载速度会变慢
-     */
-    int buffSize = 8192;
-
-    /**
-     * 进度刷新间隔,默认1秒
-     */
-    long updateInterval = 1000;
-
+  public static class BaseConfig {
     /**
      * 旧任务数
      */
@@ -235,42 +70,13 @@ class Configuration {
      *
      * @see QueueMod
      */
-    String queueMod = "wait";
-
-    /**
-     * 断网的时候是否重试,{@code true}断网也重试;{@code false}断网不重试,直接走失败的回调
-     */
-    boolean notNetRetry = false;
-
-    /**
-     * 设置IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒
-     */
-    int iOTimeOut = 20 * 1000;
-
-    public long getUpdateInterval() {
-      return updateInterval;
-    }
-
-    /**
-     * 设置进度更新间隔,该设置对正在运行的任务无效,默认为1000毫秒
-     *
-     * @param updateInterval 不能小于0
-     */
-    public BaseTaskConfig setUpdateInterval(long updateInterval) {
-      if (updateInterval <= 0) {
-        ALog.w("Configuration", "进度更新间隔不能小于0");
-        return this;
-      }
-      this.updateInterval = updateInterval;
-      saveKey("updateInterval", String.valueOf(updateInterval));
-      return this;
-    }
+    String queueMod = "now";
 
     public String getQueueMod() {
       return queueMod;
     }
 
-    public BaseTaskConfig setQueueMod(String queueMod) {
+    public BaseConfig setQueueMod(String queueMod) {
       this.queueMod = queueMod;
       saveKey("queueMod", queueMod);
       return this;
@@ -280,13 +86,21 @@ class Configuration {
       return maxTaskNum;
     }
 
+    public BaseConfig setMaxTaskNum(int maxTaskNum) {
+      oldMaxTaskNum = this.maxTaskNum;
+      this.maxTaskNum = maxTaskNum;
+      saveKey("maxTaskNum", maxTaskNum + "");
+      DownloadTaskQueue.getInstance().setMaxTaskNum(maxTaskNum);
+      return this;
+    }
+
     public int getReTryNum() {
       return reTryNum;
     }
 
-    public BaseTaskConfig setReTryNum(int reTryNum) {
+    public BaseConfig setReTryNum(int reTryNum) {
       this.reTryNum = reTryNum;
-      saveKey("reTryNum", String.valueOf(reTryNum));
+      saveKey("reTryNum", reTryNum + "");
       return this;
     }
 
@@ -294,9 +108,9 @@ class Configuration {
       return reTryInterval;
     }
 
-    public BaseTaskConfig setReTryInterval(int reTryInterval) {
+    public BaseConfig setReTryInterval(int reTryInterval) {
       this.reTryInterval = reTryInterval;
-      saveKey("reTryInterval", String.valueOf(reTryInterval));
+      saveKey("reTryInterval", reTryInterval + "");
       return this;
     }
 
@@ -304,9 +118,9 @@ class Configuration {
       return isConvertSpeed;
     }
 
-    public BaseTaskConfig setConvertSpeed(boolean convertSpeed) {
+    public BaseConfig setConvertSpeed(boolean convertSpeed) {
       isConvertSpeed = convertSpeed;
-      saveKey("isConvertSpeed", String.valueOf(isConvertSpeed));
+      saveKey("isConvertSpeed", isConvertSpeed + "");
       return this;
     }
 
@@ -314,48 +128,110 @@ class Configuration {
       return connectTimeOut;
     }
 
-    public BaseTaskConfig setConnectTimeOut(int connectTimeOut) {
+    public BaseConfig setConnectTimeOut(int connectTimeOut) {
       this.connectTimeOut = connectTimeOut;
-      saveKey("connectTimeOut", String.valueOf(connectTimeOut));
-      return this;
-    }
-
-    public boolean isNotNetRetry() {
-      return notNetRetry;
-    }
-
-    public BaseTaskConfig setNotNetRetry(boolean notNetRetry) {
-      this.notNetRetry = notNetRetry;
-      saveKey("notNetRetry", String.valueOf(notNetRetry));
+      saveKey("connectTimeOut", connectTimeOut + "");
       return this;
     }
 
-    public int getIOTimeOut() {
-      return iOTimeOut;
-    }
-
-    public BaseTaskConfig setIOTimeOut(int iOTimeOut) {
-      this.iOTimeOut = iOTimeOut;
-      saveKey("iOTimeOut", String.valueOf(iOTimeOut));
-      return this;
+    /**
+     * 保存key
+     */
+    void saveKey(String key, String value) {
+      boolean isDownload = this instanceof DownloadConfig;
+      File file = new File(
+          AriaManager.APP.getFilesDir().getPath() + (isDownload ? DOWNLOAD_CONFIG_FILE
+              : UPLOAD_CONFIG_FILE));
+      if (file.exists()) {
+        Properties properties = CommonUtil.loadConfig(file);
+        properties.setProperty(key, value);
+        CommonUtil.saveConfig(file, properties);
+      }
     }
 
-    public int getBuffSize() {
-      return buffSize;
+    /**
+     * 加载配置
+     */
+    void loadConfig() {
+      boolean isDownload = this instanceof DownloadConfig;
+      File file = new File(
+          AriaManager.APP.getFilesDir().getPath() + (isDownload ? DOWNLOAD_CONFIG_FILE
+              : UPLOAD_CONFIG_FILE));
+      if (file.exists()) {
+        Properties properties = CommonUtil.loadConfig(file);
+        List<Field> fields = CommonUtil.getAllFields(getClass());
+        try {
+          for (Field field : fields) {
+            int m = field.getModifiers();
+            if (field.getName().equals("oldMaxTaskNum") || Modifier.isFinal(m) || Modifier.isStatic(
+                m)) {
+              continue;
+            }
+            field.setAccessible(true);
+            String value = properties.getProperty(field.getName());
+            if (TextUtils.isEmpty(value) || value.equalsIgnoreCase("null")) continue;
+            Class<?> type = field.getType();
+            if (type == String.class) {
+              field.set(this, value);
+            } else if (type == int.class || type == Integer.class) {
+              field.setInt(this, Integer.parseInt(value));
+            } else if (type == float.class || type == Float.class) {
+              field.setFloat(this, Float.parseFloat(value));
+            } else if (type == double.class || type == Double.class) {
+              if (TextUtils.isEmpty(value)) {
+                value = "0.0";
+              }
+              field.setDouble(this, Double.parseDouble(value));
+            } else if (type == long.class || type == Long.class) {
+              field.setLong(this, Long.parseLong(value));
+            } else if (type == boolean.class || type == Boolean.class) {
+              field.setBoolean(this, Boolean.parseBoolean(value));
+            }
+          }
+        } catch (IllegalAccessException e) {
+          e.printStackTrace();
+        }
+      }
     }
 
-    public BaseTaskConfig setBuffSize(int buffSize) {
-      this.buffSize = buffSize;
-      saveKey("buffSize", String.valueOf(buffSize));
-      return this;
+    /**
+     * 保存配置
+     */
+    void saveAll() {
+      List<Field> fields = CommonUtil.getAllFields(getClass());
+      boolean isDownload = this instanceof DownloadConfig;
+      try {
+        File file = new File(
+            AriaManager.APP.getFilesDir().getPath() + (isDownload ? DOWNLOAD_CONFIG_FILE
+                : UPLOAD_CONFIG_FILE));
+        Properties properties = CommonUtil.loadConfig(file);
+        for (Field field : fields) {
+          int m = field.getModifiers();
+          if (Modifier.isFinal(m) || Modifier.isStatic(m)) {
+            continue;
+          }
+          field.setAccessible(true);
+          properties.setProperty(field.getName(), field.get(this) + "");
+        }
+        CommonUtil.saveConfig(file, properties);
+      } catch (IllegalAccessException e) {
+        e.printStackTrace();
+      }
     }
   }
 
   /**
    * 下载配置
    */
-  public static class DownloadConfig extends BaseTaskConfig {
-
+  public static class DownloadConfig extends BaseConfig {
+    /**
+     * 设置IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒
+     */
+    int iOTimeOut = 20 * 1000;
+    /**
+     * 设置写文件buff大小,该数值大小不能小于2048,数值变小,下载速度会变慢
+     */
+    int buffSize = 8192;
     /**
      * 设置https ca 证书信息;path 为assets目录下的CA证书完整路径
      */
@@ -372,50 +248,37 @@ class Configuration {
     /**
      * 设置最大下载速度,单位:kb, 为0表示不限速
      */
-    int maxSpeed = 0;
-
-    /**
-     * 是否开启动态文件,开启动态文件后初始化时将不占用磁盘空间,下载多少byte,占多少空间,效果见chrome的下载
-     * 注意:
-     * 1、使用该功能,将自动关闭多线程下载;
-     * 2、对于已经采用了多线程的任务,依然采用原来的下载方式;
-     * 3、原本参数是true,任务没下载完成,就参数改为false,那么没下载完成的任务还是会按照参数修改前的方式下载,只有新任务才会根据参数调用不同的下载方式
-     * {@code true}使用
-     */
-    boolean openDynamicFile = true;
+    double msxSpeed = 0.0;
 
-    public DownloadConfig setOpenDynamicFile(boolean openDynamicFile) {
-      this.openDynamicFile = openDynamicFile;
-      saveKey("openDynamicFile", String.valueOf(openDynamicFile));
-      return this;
+    public int getIOTimeOut() {
+      return iOTimeOut;
     }
 
-    public boolean isOpenDynamicFile() {
-      return openDynamicFile;
+    public double getMsxSpeed() {
+      return msxSpeed;
     }
 
-    public DownloadConfig setMaxTaskNum(int maxTaskNum) {
-      oldMaxTaskNum = this.maxTaskNum;
-      this.maxTaskNum = maxTaskNum;
-      saveKey("maxTaskNum", String.valueOf(maxTaskNum));
-      DownloadTaskQueue.getInstance().setMaxTaskNum(maxTaskNum);
+    public DownloadConfig setMsxSpeed(double msxSpeed) {
+      this.msxSpeed = msxSpeed;
+      saveKey("msxSpeed", String.valueOf(msxSpeed));
+      DownloadTaskQueue.getInstance().setMaxSpeed(msxSpeed);
       return this;
     }
 
-    public int getMaxSpeed() {
-      return maxSpeed;
+    public DownloadConfig setIOTimeOut(int iOTimeOut) {
+      this.iOTimeOut = iOTimeOut;
+      saveKey("iOTimeOut", iOTimeOut + "");
+      return this;
     }
 
-    public DownloadConfig setMaxSpeed(int maxSpeed) {
-      this.maxSpeed = maxSpeed;
-      saveKey("maxSpeed", String.valueOf(maxSpeed));
-      DownloadTaskQueue.getInstance().setMaxSpeed(maxSpeed);
-      return this;
+    public int getBuffSize() {
+      return buffSize;
     }
 
-    public void setThreadNum(int threadNum) {
-      this.threadNum = threadNum;
-      saveKey("threadNum", String.valueOf(threadNum));
+    public DownloadConfig setBuffSize(int buffSize) {
+      this.buffSize = buffSize;
+      saveKey("buffSize", buffSize + "");
+      return this;
     }
 
     public String getCaPath() {
@@ -456,29 +319,18 @@ class Configuration {
       }
       return INSTANCE;
     }
-
-    @Override int getType() {
-      return TYPE_DOWNLOAD;
-    }
   }
 
   /**
    * 上传配置
    */
-  public static class UploadConfig extends BaseTaskConfig {
-    private static UploadConfig INSTANCE = null;
+  public static class UploadConfig extends BaseConfig {
 
     private UploadConfig() {
       loadConfig();
     }
 
-    public UploadConfig setMaxTaskNum(int maxTaskNum) {
-      oldMaxTaskNum = this.maxTaskNum;
-      this.maxTaskNum = maxTaskNum;
-      saveKey("maxTaskNum", String.valueOf(maxTaskNum));
-      UploadTaskQueue.getInstance().setMaxTaskNum(maxTaskNum);
-      return this;
-    }
+    private static UploadConfig INSTANCE = null;
 
     static UploadConfig getInstance() {
       if (INSTANCE == null) {
@@ -488,71 +340,5 @@ class Configuration {
       }
       return INSTANCE;
     }
-
-    @Override int getType() {
-      return TYPE_UPLOAD;
-    }
-  }
-
-  /**
-   * 应用配置
-   */
-  public static class AppConfig extends BaseConfig {
-    private static AppConfig INSTANCE = null;
-    /**
-     * 是否使用{@link AriaCrashHandler}来捕获异常
-     * {@code true} 使用;{@code false} 不使用
-     */
-    boolean useAriaCrashHandler;
-
-    /**
-     * 设置Aria的日志级别
-     *
-     * {@link ALog#LOG_LEVEL_VERBOSE}
-     */
-    int logLevel;
-
-    AppConfig() {
-      loadConfig();
-    }
-
-    static AppConfig getInstance() {
-      if (INSTANCE == null) {
-        synchronized (AppConfig.class) {
-          INSTANCE = new AppConfig();
-        }
-      }
-      return INSTANCE;
-    }
-
-    public AppConfig setLogLevel(int level) {
-      this.logLevel = level;
-      ALog.LOG_LEVEL = level;
-      saveKey("logLevel", String.valueOf(logLevel));
-      return this;
-    }
-
-    public int getLogLevel() {
-      return logLevel;
-    }
-
-    public boolean getUseAriaCrashHandler() {
-      return useAriaCrashHandler;
-    }
-
-    public AppConfig setUseAriaCrashHandler(boolean useAriaCrashHandler) {
-      this.useAriaCrashHandler = useAriaCrashHandler;
-      saveKey("useAriaCrashHandler", String.valueOf(useAriaCrashHandler));
-      if (useAriaCrashHandler) {
-        Thread.setDefaultUncaughtExceptionHandler(new AriaCrashHandler());
-      } else {
-        Thread.setDefaultUncaughtExceptionHandler(null);
-      }
-      return this;
-    }
-
-    @Override int getType() {
-      return TYPE_APP;
-    }
   }
 }

+ 0 - 83
Aria/src/main/java/com/arialyy/aria/core/FtpUrlEntity.java

@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.arialyy.aria.core;
-
-import java.net.InetAddress;
-
-/**
- * Created by Aria.Lao on 2017/10/24.
- * ftp url 信息链接实体
- */
-public class FtpUrlEntity implements Cloneable {
-  /**
-   * 如:ftp://127.0.0.1:21/download/AriaPrj.zip
-   * remotePath便是:download/AriaPrj.zip
-   */
-  public String remotePath;
-
-  public String account;
-
-  /**
-   * 原始url
-   */
-  public String url;
-
-  /**
-   * ftp协议:ftp
-   */
-  public String protocol;
-
-  /**
-   * 登录的用户名
-   */
-  public String user;
-  /**
-   * 密码
-   */
-  public String password;
-
-  /**
-   * 端口
-   */
-  public String port;
-
-  /**
-   * 主机域名
-   */
-  public String hostName;
-
-  /**
-   * 是否需要登录
-   */
-  public boolean needLogin = false;
-
-  /**
-   * 有效的ip地址
-   */
-  public InetAddress validAddr;
-
-  @Override public FtpUrlEntity clone() {
-    FtpUrlEntity entity = null;
-    try {
-      entity = (FtpUrlEntity) super.clone();
-    } catch (CloneNotSupportedException e) {
-      e.printStackTrace();
-    }
-    return entity;
-  }
-}

+ 7 - 35
Aria/src/main/java/com/arialyy/aria/core/WidgetLiftManager.java

@@ -15,14 +15,11 @@
  */
 package com.arialyy.aria.core;
 
-import android.annotation.TargetApi;
 import android.app.Dialog;
 import android.content.DialogInterface;
-import android.os.Build;
 import android.os.Message;
-import android.support.v4.app.DialogFragment;
+import android.util.Log;
 import android.widget.PopupWindow;
-import com.arialyy.aria.util.ALog;
 import com.arialyy.aria.util.CommonUtil;
 import java.lang.reflect.Field;
 
@@ -34,44 +31,22 @@ final class WidgetLiftManager {
   private final String TAG = "WidgetLiftManager";
 
   /**
-   * 处理DialogFragment事件
-   *
-   * @param dialogFragment {@link android.app.DialogFragment}
-   */
-  @TargetApi(Build.VERSION_CODES.HONEYCOMB) boolean handleDialogFragmentLift(
-      android.app.DialogFragment dialogFragment) {
-    return handleDialogLift(dialogFragment.getDialog());
-  }
-
-  /**
-   * 处理DialogFragment事件
-   *
-   * @param dialogFragment {@link android.support.v4.app.DialogFragment}
-   */
-  @TargetApi(Build.VERSION_CODES.HONEYCOMB) boolean handleDialogFragmentLift(
-      DialogFragment dialogFragment) {
-    return handleDialogLift(dialogFragment.getDialog());
-  }
-
-  /**
    * 处理悬浮框取消或dismiss事件
    */
-  boolean handlePopupWindowLift(PopupWindow popupWindow) {
+  void handlePopupWindowLift(PopupWindow popupWindow) {
     try {
       Field dismissField = CommonUtil.getField(popupWindow.getClass(), "mOnDismissListener");
       PopupWindow.OnDismissListener listener =
           (PopupWindow.OnDismissListener) dismissField.get(popupWindow);
       if (listener != null) {
-        ALog.e(TAG, "你已经对PopupWindow设置了Dismiss事件。为了防止内存泄露,"
-            + "请在dismiss方法中调用Aria.download(this).unRegister();来注销事件");
-        return true;
+        Log.e(TAG, "你已经对PopupWindow设置了Dismiss事件。为了防止内存泄露,"
+            + "请在dismiss方法中调用Aria.download(this).removeSchedulerListener();来注销事件");
       } else {
         popupWindow.setOnDismissListener(createPopupWindowListener(popupWindow));
       }
     } catch (IllegalAccessException e) {
       e.printStackTrace();
     }
-    return false;
   }
 
   /**
@@ -88,7 +63,7 @@ final class WidgetLiftManager {
   /**
    * 处理对话框取消或dismiss
    */
-  boolean handleDialogLift(Dialog dialog) {
+  void handleDialogLift(Dialog dialog) {
     try {
       Field dismissField = CommonUtil.getField(dialog.getClass(), "mDismissMessage");
       Message dismissMsg = (Message) dismissField.get(dialog);
@@ -97,10 +72,8 @@ final class WidgetLiftManager {
         Field cancelField = CommonUtil.getField(dialog.getClass(), "mCancelMessage");
         Message cancelMsg = (Message) cancelField.get(dialog);
         if (cancelMsg != null) {
-          ALog.e(TAG, "你已经对Dialog设置了Dismiss和cancel事件。"
-              + "为了防止内存泄露,请在dismiss方法中调用Aria.download(this).unRegister();来注销事件\n"
-              + "如果你使用的是DialogFragment,那么你需要在onDestroy()中进行销毁Aria事件操作");
-          return true;
+          Log.e(TAG, "你已经对Dialog设置了Dismiss和cancel事件。为了防止内存泄露,"
+              + "请在dismiss方法中调用Aria.download(this).removeSchedulerListener();来注销事件");
         } else {
           dialog.setOnCancelListener(createCancelListener());
         }
@@ -110,7 +83,6 @@ final class WidgetLiftManager {
     } catch (IllegalAccessException e) {
       e.printStackTrace();
     }
-    return false;
   }
 
   /**

+ 1 - 2
Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java

@@ -22,12 +22,11 @@ import com.arialyy.aria.core.queue.ITaskQueue;
 /**
  * Created by AriaL on 2017/6/29.
  */
-public abstract class AbsCmd<T extends AbsTaskEntity> implements ICmd {
+public abstract class AbsCmd<T extends AbsTaskEntity> implements ICmd{
   protected ITaskQueue mQueue;
   protected T mTaskEntity;
   protected String TAG;
   protected String mTargetName;
-
   /**
    * 是否是下载任务的命令
    * {@code true} 下载任务的命令,{@code false} 上传任务的命令

+ 2 - 4
Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java

@@ -21,13 +21,11 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
  * Created by AriaL on 2017/6/29.
  * 抽象命令工厂
  */
-public abstract class AbsCmdFactory<TASK_ENTITY extends AbsTaskEntity, CMD extends AbsCmd> {
+public abstract class AbsCmdFactory<CMD extends AbsCmd> {
 
   /**
    * @param target 创建任务的对象
    * @param entity 下载实体
-   * @param taskType {@link ICmd#TASK_TYPE_DOWNLOAD}、{@link ICmd#TASK_TYPE_DOWNLOAD_GROUP}、{@link
-   * ICmd#TASK_TYPE_UPLOAD}
    */
-  public abstract CMD createCmd(String target, TASK_ENTITY entity, int type, int taskType);
+  public abstract <T extends AbsTaskEntity> CMD createCmd(String target, T entity, int type);
 }

+ 0 - 13
Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java

@@ -21,19 +21,6 @@ package com.arialyy.aria.core.command;
 
 public interface ICmd {
   /**
-   * 单任务下载任务
-   */
-  int TASK_TYPE_DOWNLOAD = 0x01;
-  /**
-   * 任务组下载任务
-   */
-  int TASK_TYPE_DOWNLOAD_GROUP = 0x02;
-  /**
-   * 上传任务
-   */
-  int TASK_TYPE_UPLOAD = 0x10;
-
-  /**
    * 执行命令
    */
   void executeCmd();

+ 6 - 33
Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java

@@ -17,24 +17,19 @@ package com.arialyy.aria.core.command.group;
 
 import com.arialyy.aria.core.command.AbsCmd;
 import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
-import com.arialyy.aria.core.inf.AbsGroupTask;
-import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.download.DownloadTaskEntity;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
-import com.arialyy.aria.util.ALog;
+import com.arialyy.aria.core.queue.DownloadTaskQueue;
+import com.arialyy.aria.core.queue.UploadTaskQueue;
+import com.arialyy.aria.core.upload.UploadTaskEntity;
 import com.arialyy.aria.util.CommonUtil;
 
 /**
  * Created by AriaL on 2017/6/29.
  * 任务组命令
  */
-public abstract class AbsGroupCmd<T extends AbsGroupTaskEntity> extends AbsCmd<T> {
-  /**
-   * 需要控制的子任务url
-   */
-  String childUrl;
-
-  AbsGroupTask tempTask;
+abstract class AbsGroupCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
 
   /**
    * @param targetName 创建任务的对象名
@@ -48,26 +43,4 @@ public abstract class AbsGroupCmd<T extends AbsGroupTaskEntity> extends AbsCmd<T
       isDownloadCmd = true;
     }
   }
-
-  /**
-   * 创建任务
-   *
-   * @return 创建的任务
-   */
-  AbsTask createTask() {
-    tempTask = (AbsGroupTask) mQueue.createTask(mTargetName, mTaskEntity);
-    return tempTask;
-  }
-
-  boolean checkTask() {
-    tempTask = (AbsGroupTask) mQueue.getTask(mTaskEntity.getEntity().getKey());
-    if (tempTask == null) {
-      createTask();
-      if (tempTask.isComplete()) {
-        ALog.i(TAG, "任务已完成");
-        return false;
-      }
-    }
-    return true;
-  }
 }

+ 3 - 5
Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java

@@ -15,13 +15,13 @@
  */
 package com.arialyy.aria.core.command.group;
 
-import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by AriaL on 2017/6/29.
  * 删除任务组
  */
-class GroupCancelCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
+class GroupCancelCmd<T extends AbsTaskEntity> extends AbsGroupCmd<T> {
   /**
    * @param targetName 创建任务的对象名
    */
@@ -30,8 +30,6 @@ class GroupCancelCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
   }
 
   @Override public void executeCmd() {
-    if (checkTask()) {
-      tempTask.cancelSubTask(childUrl);
-    }
+
   }
 }

+ 19 - 26
Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java

@@ -16,25 +16,25 @@
 package com.arialyy.aria.core.command.group;
 
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
+import com.arialyy.aria.core.command.AbsCmdFactory;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by AriaL on 2017/6/29.
- * 任务组子任务控制命令
  */
-public class GroupCmdFactory {
+class GroupCmdFactory extends AbsCmdFactory<AbsGroupCmd> {
   /**
-   * 启动任务
+   * 启动任务
    */
-  public static final int SUB_TASK_START = 0xa1;
+  public static final int TASK_START = 0xa1;
   /**
-   * 停止任务
+   * 停止任务
    */
-  public static final int SUB_TASK_STOP = 0xa2;
+  public static final int TASK_STOP = 0xa2;
   /**
-   * 取消任务
+   * 取消任务
    */
-  public static final int SUB_TASK_CANCEL = 0xa3;
+  public static final int TASK_CANCEL = 0xa3;
 
   private static volatile GroupCmdFactory INSTANCE = null;
 
@@ -54,25 +54,18 @@ public class GroupCmdFactory {
   /**
    * @param target 创建任务的对象
    * @param entity 下载实体
-   * @param type 命令类型{@link #SUB_TASK_START}、{@link #SUB_TASK_STOP}、{@link #SUB_TASK_CANCEL}
-   * @param childUrl 需要控制的子任务url
+   * @param type 命令类型{@link #TASK_START}、{@link #TASK_CANCEL}、{@link #TASK_STOP}
    */
-  public AbsGroupCmd createCmd(String target, AbsGroupTaskEntity entity, int type,
-      String childUrl) {
-    AbsGroupCmd cmd = null;
+  public <T extends AbsTaskEntity> AbsGroupCmd<T> createCmd(String target, T entity, int type) {
     switch (type) {
-      case SUB_TASK_START:
-        cmd = new GroupStartCmd<>(target, entity);
-        break;
-      case SUB_TASK_STOP:
-        cmd = new GroupStopCmd<>(target, entity);
-        break;
-      case SUB_TASK_CANCEL:
-        cmd = new GroupCancelCmd<>(target, entity);
+      case TASK_START:
+        return new GroupStartCmd<>(target, entity);
+      case TASK_STOP:
+        return new GroupStopCmd<>(target, entity);
+      case TASK_CANCEL:
+        return new GroupCancelCmd<>(target, entity);
+      default:
+        return null;
     }
-    if (cmd != null) {
-      cmd.childUrl = childUrl;
-    }
-    return cmd;
   }
 }

+ 40 - 5
Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java

@@ -15,13 +15,18 @@
  */
 package com.arialyy.aria.core.command.group;
 
-import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
+import android.text.TextUtils;
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.common.QueueMod;
+import com.arialyy.aria.core.inf.AbsGroupTask;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.core.inf.IEntity;
 
 /**
  * Created by AriaL on 2017/6/29.
- * 任务组开始命令,该命令负责处理任务组子任务的开始\恢复等工作
+ * 任务组开始命令,该命令负责开始下载或恢复下载的操
  */
-class GroupStartCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
+class GroupStartCmd<T extends AbsTaskEntity> extends AbsGroupCmd<T> {
   /**
    * @param targetName 创建任务的对象名
    */
@@ -30,8 +35,38 @@ class GroupStartCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
   }
 
   @Override public void executeCmd() {
-    if (checkTask()) {
-      tempTask.startSubTask(childUrl);
+    String mod;
+    int maxTaskNum;
+    AriaManager manager = AriaManager.getInstance(AriaManager.APP);
+    if (isDownloadCmd) {
+      mod = manager.getDownloadConfig().getQueueMod();
+      maxTaskNum = manager.getDownloadConfig().getMaxTaskNum();
+    } else {
+      mod = manager.getUploadConfig().getQueueMod();
+      maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
+    }
+
+    AbsGroupTask task = (AbsGroupTask) mQueue.getTask(mTaskEntity.getEntity());
+    if (task == null) {
+      task = (AbsGroupTask) mQueue.createTask(mTargetName, mTaskEntity);
+      if (!TextUtils.isEmpty(mTargetName)) {
+        task.setTargetName(mTargetName);
+      }
+      // 任务不存在时,根据配置不同,对任务执行操作
+      if (mod.equals(QueueMod.NOW.getTag())) {
+        mQueue.startTask(task);
+      } else if (mod.equals(QueueMod.WAIT.getTag())) {
+        if (mQueue.getCurrentExePoolNum() < maxTaskNum) {
+          mQueue.startTask(task);
+        }
+      }
+    } else {
+      // 任务不存在时,根据配置不同,对任务执行操作
+      if (!task.isRunning()
+          && mod.equals(QueueMod.WAIT.getTag())
+          && task.getState() == IEntity.STATE_WAIT) {
+        mQueue.startTask(task);
+      }
     }
   }
 }

+ 3 - 5
Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java

@@ -15,13 +15,13 @@
  */
 package com.arialyy.aria.core.command.group;
 
-import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by AriaL on 2017/6/29.
  * 停止任务组的命令
  */
-class GroupStopCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
+class GroupStopCmd<T extends AbsTaskEntity> extends AbsGroupCmd<T>{
   /**
    * @param targetName 创建任务的对象名
    */
@@ -30,8 +30,6 @@ class GroupStopCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
   }
 
   @Override public void executeCmd() {
-    if (checkTask()) {
-      tempTask.stopSubTask(childUrl);
-    }
+
   }
 }

+ 13 - 49
Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java

@@ -17,19 +17,15 @@
 package com.arialyy.aria.core.command.normal;
 
 import com.arialyy.aria.core.command.AbsCmd;
-import com.arialyy.aria.core.command.ICmd;
 import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.AbsEntity;
 import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.core.manager.TEManager;
 import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
 import com.arialyy.aria.core.queue.DownloadTaskQueue;
 import com.arialyy.aria.core.queue.UploadTaskQueue;
-import com.arialyy.aria.core.scheduler.ISchedulers;
 import com.arialyy.aria.core.upload.UploadTaskEntity;
-import com.arialyy.aria.util.ALog;
 import com.arialyy.aria.util.CommonUtil;
 
 /**
@@ -43,49 +39,25 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
   boolean canExeCmd = true;
 
   private AbsTask tempTask = null;
-  int taskType;
 
   /**
    * @param targetName 产生任务的对象名
-   * @param taskType 下载任务类型{@link ICmd#TASK_TYPE_DOWNLOAD}、{@link ICmd#TASK_TYPE_DOWNLOAD_GROUP}、{@link
-   * ICmd#TASK_TYPE_UPLOAD}
    */
-  AbsNormalCmd(String targetName, T entity, int taskType) {
-    this.taskType = taskType;
+  AbsNormalCmd(String targetName, T entity) {
+    //canExeCmd = CheckUtil.checkCmdEntity(entity,
+    //    !(this instanceof CancelCmd) || !(this instanceof StopCmd));
     mTargetName = targetName;
     mTaskEntity = entity;
     TAG = CommonUtil.getClassName(this);
-    if (taskType == ICmd.TASK_TYPE_DOWNLOAD) {
-      if (!(entity instanceof DownloadTaskEntity)) {
-        ALog.e(TAG, "任务类型错误,任务类型应该为ICM.TASK_TYPE_DOWNLOAD");
-        return;
-      }
+    if (entity instanceof DownloadTaskEntity) {
       mQueue = DownloadTaskQueue.getInstance();
-    } else if (taskType == ICmd.TASK_TYPE_DOWNLOAD_GROUP) {
-      if (!(entity instanceof DownloadGroupTaskEntity)) {
-        ALog.e(TAG, "任务类型错误,任务类型应该为ICM.TASK_TYPE_DOWNLOAD_GROUP");
-        return;
-      }
-      mQueue = DownloadGroupTaskQueue.getInstance();
-    } else if (taskType == ICmd.TASK_TYPE_UPLOAD) {
-      if (!(entity instanceof UploadTaskEntity)) {
-        ALog.e(TAG, "任务类型错误,任务类型应该为ICM.TASK_TYPE_UPLOAD");
-        return;
-      }
+      isDownloadCmd = true;
+    } else if (entity instanceof UploadTaskEntity) {
       mQueue = UploadTaskQueue.getInstance();
-    } else {
-      ALog.e(TAG, "任务类型错误,任务类型应该为ICM.TASK_TYPE_DOWNLOAD、TASK_TYPE_DOWNLOAD_GROUP、TASK_TYPE_UPLOAD");
-      return;
-    }
-    isDownloadCmd = taskType < ICmd.TASK_TYPE_UPLOAD;
-  }
-
-  /**
-   * 发送等待状态
-   */
-  void sendWaitState() {
-    if (tempTask != null) {
-      tempTask.getOutHandler().obtainMessage(ISchedulers.WAIT, tempTask).sendToTarget();
+      isDownloadCmd = false;
+    } else if (entity instanceof DownloadGroupTaskEntity) {
+      mQueue = DownloadGroupTaskQueue.getInstance();
+      isDownloadCmd = true;
     }
   }
 
@@ -116,7 +88,7 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
    */
   void removeTask() {
     if (tempTask == null) createTask();
-    mQueue.cancelTask(tempTask);
+    mQueue.removeTask(tempTask);
   }
 
   /**
@@ -127,13 +99,6 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
   }
 
   /**
-   * 恢复任务
-   */
-  void resumeTask() {
-    mQueue.resumeTask(tempTask);
-  }
-
-  /**
    * 启动指定任务
    *
    * @param task 指定任务
@@ -148,7 +113,7 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
    * @return 执行任务
    */
   AbsTask getTask() {
-    tempTask = mQueue.getTask(mTaskEntity.getEntity().getKey());
+    tempTask = mQueue.getTask(mTaskEntity.getEntity());
     return tempTask;
   }
 
@@ -158,7 +123,7 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
    * @return 执行任务
    */
   AbsTask getTask(AbsEntity entity) {
-    tempTask = mQueue.getTask(entity.getKey());
+    tempTask = mQueue.getTask(entity);
     return tempTask;
   }
 
@@ -179,7 +144,6 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
    * @return 创建的任务
    */
   AbsTask createTask(AbsTaskEntity taskEntity) {
-    TEManager.getInstance().addTEntity(taskEntity);
     return mQueue.createTask(mTargetName, taskEntity);
   }
 }

+ 5 - 6
Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java

@@ -16,10 +16,10 @@
 
 package com.arialyy.aria.core.command.normal;
 
+import android.util.Log;
 import com.arialyy.aria.core.inf.AbsTask;
-import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.util.ALog;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by lyy on 2016/8/22.
@@ -27,8 +27,8 @@ import com.arialyy.aria.util.ALog;
  */
 class AddCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
 
-  AddCmd(String targetName, T entity, int taskType) {
-    super(targetName, entity, taskType);
+  AddCmd(String targetName, T entity) {
+    super(targetName, entity);
   }
 
   @Override public void executeCmd() {
@@ -37,9 +37,8 @@ class AddCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
     if (task == null) {
       mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
       createTask();
-      sendWaitState();
     } else {
-      ALog.w(TAG, "添加命令执行失败,【该任务已经存在】");
+      Log.w(TAG, "添加命令执行失败,【该任务已经存在】");
     }
   }
 }

+ 35 - 9
Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java

@@ -16,27 +16,53 @@
 
 package com.arialyy.aria.core.command.normal;
 
+import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.core.upload.UploadTaskEntity;
+import com.arialyy.aria.orm.DbEntity;
+import com.arialyy.aria.util.CommonUtil;
+import java.util.List;
 
 /**
  * Created by AriaL on 2017/6/27.
  * 删除所有任务,并且删除所有回掉
  */
-public class CancelAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
-  /**
-   * removeFile {@code true} 删除已经下载完成的任务,不仅删除下载记录,还会删除已经下载完成的文件,{@code false}
-   * 如果文件已经下载完成,只删除下载记录
-   */
-  public boolean removeFile = false;
-
+final class CancelAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
   /**
    * @param targetName 产生任务的对象名
    */
-  CancelAllCmd(String targetName, T entity, int taskType) {
-    super(targetName, entity, taskType);
+  CancelAllCmd(String targetName, T entity) {
+    super(targetName, entity);
   }
 
   @Override public void executeCmd() {
     removeAll();
+    if (mTaskEntity instanceof DownloadTaskEntity) {
+      handleDownloadRemove();
+    } else if (mTaskEntity instanceof UploadTaskEntity){
+      handleUploadRemove();
+    }
+  }
+
+  /**
+   * 处理上传的删除
+   */
+  private void handleUploadRemove() {
+    List<UploadTaskEntity> allEntity = DbEntity.findAllData(UploadTaskEntity.class);
+    if (allEntity == null || allEntity.size() == 0) return;
+    for (UploadTaskEntity entity : allEntity) {
+      CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, entity);
+    }
+  }
+
+  /**
+   * 处理下载的删除
+   */
+  private void handleDownloadRemove() {
+    List<DownloadTaskEntity> allEntity = DbEntity.findAllData(DownloadTaskEntity.class);
+    if (allEntity == null || allEntity.size() == 0) return;
+    for (DownloadTaskEntity entity : allEntity) {
+      CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, entity);
+    }
   }
 }

+ 3 - 10
Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java

@@ -24,15 +24,9 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
  * Created by lyy on 2016/9/20.
  * 取消命令
  */
-public class CancelCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
-  /**
-   * removeFile {@code true} 删除已经下载完成的任务,不仅删除下载记录,还会删除已经下载完成的文件,{@code false}
-   * 如果文件已经下载完成,只删除下载记录
-   */
-  public boolean removeFile = false;
-
-  CancelCmd(String targetName, T entity, int taskType) {
-    super(targetName, entity, taskType);
+class CancelCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
+  CancelCmd(String targetName, T entity) {
+    super(targetName, entity);
   }
 
   @Override public void executeCmd() {
@@ -42,7 +36,6 @@ public class CancelCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
       task = createTask();
     }
     if (task != null) {
-      mTaskEntity.setRemoveFile(removeFile);
       if (!TextUtils.isEmpty(mTargetName)) {
         task.setTargetName(mTargetName);
       }

+ 3 - 9
Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java

@@ -16,12 +16,10 @@
 package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
-import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.DownloadTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.queue.DownloadTaskQueue;
-import com.arialyy.aria.util.ALog;
-import com.arialyy.aria.util.NetUtils;
 
 /**
  * Created by lyy on 2017/6/2.
@@ -39,16 +37,12 @@ final class HighestPriorityCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T>
   /**
    * @param targetName 产生任务的对象名
    */
-  HighestPriorityCmd(String targetName, T entity, int taskType) {
-    super(targetName, entity, taskType);
+  HighestPriorityCmd(String targetName, T entity) {
+    super(targetName, entity);
   }
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    if (!NetUtils.isConnected(AriaManager.APP)){
-      ALog.e(TAG, "启动任务失败,网络未连接");
-      return;
-    }
     DownloadTask task = (DownloadTask) getTask();
     if (task == null) {
       task = (DownloadTask) createTask();

+ 19 - 22
Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java

@@ -18,50 +18,49 @@ package com.arialyy.aria.core.command.normal;
 
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.command.AbsCmdFactory;
-import com.arialyy.aria.core.command.ICmd;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by Lyy on 2016/9/23.
  * 命令工厂
  */
-public class NormalCmdFactory extends AbsCmdFactory<AbsTaskEntity, AbsNormalCmd> {
+public class NormalCmdFactory extends AbsCmdFactory<AbsNormalCmd> {
   /**
    * 创建任务
    */
-  public static final int TASK_CREATE = 0xb1;
+  public static final int TASK_CREATE = 0x122;
   /**
    * 启动任务
    */
-  public static final int TASK_START = 0xb2;
+  public static final int TASK_START = 0x123;
   /**
    * 恢复任务
    */
-  public static final int TASK_RESUME = 0xb3;
+  public static final int TASK_RESUME = 0x127;
   /**
    * 取消任务
    */
-  public static final int TASK_CANCEL = 0xb4;
+  public static final int TASK_CANCEL = 0x124;
   /**
    * 停止任务
    */
-  public static final int TASK_STOP = 0xb5;
+  public static final int TASK_STOP = 0x125;
   /**
    * 设置任务为最高优先级
    */
-  public static final int TASK_HIGHEST_PRIORITY = 0xb6;
+  public static final int TASK_HIGHEST_PRIORITY = 0x128;
   /**
    * 停止所有任务
    */
-  public static final int TASK_STOP_ALL = 0xb7;
+  public static final int TASK_STOP_ALL = 0x129;
   /**
    * 恢复所有停止的任务
    */
-  public static final int TASK_RESUME_ALL = 0xb8;
+  public static final int TASK_RESUME_ALL = 0x130;
   /**
    * 删除所有任务,
    */
-  public static final int TASK_CANCEL_ALL = 0xb9;
+  public static final int TASK_CANCEL_ALL = 0x131;
   private static volatile NormalCmdFactory INSTANCE = null;
 
   private NormalCmdFactory() {
@@ -82,28 +81,26 @@ public class NormalCmdFactory extends AbsCmdFactory<AbsTaskEntity, AbsNormalCmd>
    * @param entity 下载实体
    * @param type 命令类型{@link #TASK_CREATE}、{@link #TASK_START}、{@link #TASK_CANCEL}、{@link
    * #TASK_STOP}、{@link #TASK_HIGHEST_PRIORITY}、{@link #TASK_STOP_ALL}、{@link #TASK_RESUME_ALL}
-   * @param taskType {@link ICmd#TASK_TYPE_DOWNLOAD}、{@link ICmd#TASK_TYPE_DOWNLOAD_GROUP}、{@link
-   * ICmd#TASK_TYPE_UPLOAD}
    */
-  public AbsNormalCmd createCmd(String target, AbsTaskEntity entity, int type, int taskType) {
+  public <T extends AbsTaskEntity> AbsNormalCmd<T> createCmd(String target, T entity, int type) {
     switch (type) {
       case TASK_CREATE:
-        return new AddCmd<>(target, entity, taskType);
+        return new AddCmd<>(target, entity);
       case TASK_RESUME:
       case TASK_START:
-        return new StartCmd<>(target, entity, taskType);
+        return new StartCmd<>(target, entity);
       case TASK_CANCEL:
-        return new CancelCmd<>(target, entity, taskType);
+        return new CancelCmd<>(target, entity);
       case TASK_STOP:
-        return new StopCmd<>(target, entity, taskType);
+        return new StopCmd<>(target, entity);
       case TASK_HIGHEST_PRIORITY:
-        return new HighestPriorityCmd<>(target, entity, taskType);
+        return new HighestPriorityCmd<>(target, entity);
       case TASK_STOP_ALL:
-        return new StopAllCmd<>(target, entity, taskType);
+        return new StopAllCmd<>(target, entity);
       case TASK_RESUME_ALL:
-        return new ResumeAllCmd<>(target, entity, taskType);
+        return new ResumeAllCmd<>(target, entity);
       case TASK_CANCEL_ALL:
-        return new CancelAllCmd<>(target, entity, taskType);
+        return new CancelAllCmd<>(target, entity);
       default:
         return null;
     }

+ 25 - 84
Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java

@@ -1,22 +1,14 @@
 package com.arialyy.aria.core.command.normal;
 
-import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.download.wrapper.DGTEWrapper;
-import com.arialyy.aria.core.download.wrapper.DTEWrapper;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
 import com.arialyy.aria.core.queue.DownloadTaskQueue;
 import com.arialyy.aria.core.queue.UploadTaskQueue;
 import com.arialyy.aria.core.upload.UploadTaskEntity;
-import com.arialyy.aria.core.upload.wrapper.UTEWrapper;
 import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.util.ALog;
-import com.arialyy.aria.util.CommonUtil;
-import com.arialyy.aria.util.NetUtils;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -24,101 +16,53 @@ import java.util.List;
  * 恢复所有停止的任务
  * 1.如果执行队列没有满,则开始下载任务,直到执行队列满
  * 2.如果队列执行队列已经满了,则将所有任务添加到等待队列中
- * 3.如果队列中只有等待状态的任务,如果执行队列没有满,则会启动等待状态的任务,如果执行队列已经满了,则会将所有等待状态的任务加载到缓存队列中
  */
 final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
-  private List<AbsTaskEntity> mWaitList = new ArrayList<>();
-
   /**
    * @param targetName 产生任务的对象名
    */
-  ResumeAllCmd(String targetName, T entity, int taskType) {
-    super(targetName, entity, taskType);
+  ResumeAllCmd(String targetName, T entity) {
+    super(targetName, entity);
   }
 
   @Override public void executeCmd() {
-    if (!NetUtils.isConnected(AriaManager.APP)) {
-      ALog.w(TAG, "恢复任务失败,网络未连接");
-      return;
-    }
     if (isDownloadCmd) {
-      resumeTask(findTaskData(1));
-      resumeTask(findTaskData(2));
+      resumeDownload();
     } else {
-      resumeTask(findTaskData(3));
+      resumeUpload();
     }
-    resumeWaitTask();
   }
 
   /**
-   * 查找数据库中的所有任务数据
-   *
-   * @param type {@code 1}单任务下载任务;{@code 2}任务组下载任务;{@code 3} 单任务上传任务
+   * 恢复下载,包括普通任务和任务组
    */
-  private List<AbsTaskEntity> findTaskData(int type) {
-    // TODO: 2018/4/20 需要测试
-    List<AbsTaskEntity> tempList = new ArrayList<>();
-    if (type == 1) {
-      List<DTEWrapper> wrappers = DbEntity.findRelationData(DTEWrapper.class,
-          "DownloadTaskEntity.isGroupTask=? and DownloadTaskEntity.state!=?", "false", "1");
-      if (wrappers != null && !wrappers.isEmpty()) {
-        for (DTEWrapper w : wrappers) {
-          tempList.add(w.taskEntity);
-        }
-      }
-    } else if (type == 2) {
-      List<DGTEWrapper> wrappers =
-          DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.state!=?", "1");
-      if (wrappers != null && !wrappers.isEmpty()) {
-        for (DGTEWrapper w : wrappers) {
-          tempList.add(w.taskEntity);
-        }
-      }
-    } else if (type == 3) {
-      List<UTEWrapper> wrappers =
-          DbEntity.findRelationData(UTEWrapper.class, "UploadTaskEntity.state!=?", "1");
-      if (wrappers != null && !wrappers.isEmpty()) {
-        for (UTEWrapper w : wrappers) {
-          tempList.add(w.taskEntity);
-        }
-      }
+  private void resumeDownload() {
+    List<DownloadTaskEntity> dTaskEntity =
+        DbEntity.findDatas(DownloadTaskEntity.class, "isGroupTask=?", "false");
+    for (DownloadTaskEntity te : dTaskEntity) {
+      int state = te.getState();
+      if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue;
+      resumeEntity(te);
     }
-    return tempList;
-  }
 
-  /**
-   * 恢复任务
-   */
-  private void resumeTask(List<AbsTaskEntity> taskList) {
-    if (taskList != null && !taskList.isEmpty()) {
-      for (AbsTaskEntity te : taskList) {
-        if (te == null || te.getEntity() == null) continue;
-        int state = te.getState();
-        if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
-          resumeEntity(te);
-        } else if (state == IEntity.STATE_WAIT) {
-          mWaitList.add(te);
-        } else if (state == IEntity.STATE_RUNNING) {
-          if (!mQueue.taskIsRunning(te.getEntity().getKey())) {
-            resumeEntity(te);
-          }
-        }
-      }
+    List<DownloadGroupTaskEntity> groupTask = DbEntity.findAllData(DownloadGroupTaskEntity.class);
+    for (DownloadGroupTaskEntity te : groupTask) {
+      int state = te.getState();
+      if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue;
+      resumeEntity(te);
     }
   }
 
   /**
-   * 处理等待状态的任务
+   * 恢复上传,包括普通任务和任务组
    */
-  private void resumeWaitTask() {
-    int maxTaskNum = mQueue.getMaxTaskNum();
-    if (mWaitList == null || mWaitList.isEmpty()) return;
-    for (AbsTaskEntity te : mWaitList) {
-      if (mQueue.getCurrentExePoolNum() < maxTaskNum) {
-        startTask(createTask(te));
-      } else {
-        createTask(te);
-      }
+  private void resumeUpload() {
+    List<UploadTaskEntity> dTaskEntity =
+        DbEntity.findDatas(UploadTaskEntity.class, "isGroupTask=?", "false");
+    for (UploadTaskEntity te : dTaskEntity) {
+      int state = te.getState();
+      if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue;
+      resumeEntity(te);
     }
   }
 
@@ -129,9 +73,6 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
    */
   private void resumeEntity(AbsTaskEntity te) {
     if (te instanceof DownloadTaskEntity) {
-      if (te.getRequestType() == AbsTaskEntity.D_FTP || te.getRequestType() == AbsTaskEntity.U_FTP) {
-        te.setUrlEntity(CommonUtil.getFtpUrlInfo(te.getEntity().getKey()));
-      }
       mQueue = DownloadTaskQueue.getInstance();
     } else if (te instanceof UploadTaskEntity) {
       mQueue = UploadTaskQueue.getInstance();

+ 9 - 103
Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java

@@ -19,24 +19,9 @@ package com.arialyy.aria.core.command.normal;
 import android.text.TextUtils;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.common.QueueMod;
-import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
-import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.download.wrapper.DGTEWrapper;
-import com.arialyy.aria.core.download.wrapper.DTEWrapper;
 import com.arialyy.aria.core.inf.AbsTask;
-import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
-import com.arialyy.aria.core.queue.DownloadTaskQueue;
-import com.arialyy.aria.core.queue.UploadTaskQueue;
-import com.arialyy.aria.core.upload.UploadTaskEntity;
-import com.arialyy.aria.core.upload.wrapper.UTEWrapper;
-import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.util.ALog;
-import com.arialyy.aria.util.CommonUtil;
-import com.arialyy.aria.util.NetUtils;
-import java.util.ArrayList;
-import java.util.List;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by lyy on 2016/8/22.
@@ -45,23 +30,21 @@ import java.util.List;
  */
 class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
 
-  StartCmd(String targetName, T entity, int taskType) {
-    super(targetName, entity, taskType);
+  StartCmd(String targetName, T entity) {
+    super(targetName, entity);
   }
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    if (!NetUtils.isConnected(AriaManager.APP)) {
-      ALog.e(TAG, "启动任务失败,网络未连接");
-      return;
-    }
     String mod;
-    int maxTaskNum = mQueue.getMaxTaskNum();
+    int maxTaskNum;
     AriaManager manager = AriaManager.getInstance(AriaManager.APP);
     if (isDownloadCmd) {
       mod = manager.getDownloadConfig().getQueueMod();
+      maxTaskNum = manager.getDownloadConfig().getMaxTaskNum();
     } else {
       mod = manager.getUploadConfig().getQueueMod();
+      maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
     }
 
     AbsTask task = getTask();
@@ -76,91 +59,14 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
       } else if (mod.equals(QueueMod.WAIT.getTag())) {
         if (mQueue.getCurrentExePoolNum() < maxTaskNum
             || task.getState() == IEntity.STATE_STOP
-            || task.getState() == IEntity.STATE_FAIL
-            || task.getState() == IEntity.STATE_OTHER
-            || task.getState() == IEntity.STATE_POST_PRE
             || task.getState() == IEntity.STATE_COMPLETE) {
-          resumeTask();
-        } else {
-          sendWaitState();
+          startTask();
         }
       }
     } else {
+      // 任务不存在时,根据配置不同,对任务执行操作
       if (!task.isRunning()) {
-        resumeTask();
-      }
-    }
-    if (mQueue.getCurrentCachePoolNum() == 0) {
-      findAllWaitTask();
-    }
-  }
-
-  /**
-   * 当缓冲队列为null时,查找数据库中所有等待中的任务
-   */
-  private void findAllWaitTask() {
-    new Thread(new WaitTaskThread()).start();
-  }
-
-  private class WaitTaskThread implements Runnable {
-
-    @Override public void run() {
-      if (isDownloadCmd) {
-        handleTask(findWaitData(1));
-        handleTask(findWaitData(2));
-      } else {
-        handleTask(findWaitData(3));
-      }
-    }
-
-    private List<AbsTaskEntity> findWaitData(int type) {
-      // TODO: 2018/4/20 需要测试
-      List<AbsTaskEntity> waitList = new ArrayList<>();
-      if (type == 1) {
-        List<DTEWrapper> wrappers = DbEntity.findRelationData(DTEWrapper.class,
-            "DownloadTaskEntity.isGroupTask=? and DownloadTaskEntity.state=?", "false", "3");
-        if (wrappers != null && !wrappers.isEmpty()) {
-          for (DTEWrapper w : wrappers) {
-            waitList.add(w.taskEntity);
-          }
-        }
-      } else if (type == 2) {
-        List<DGTEWrapper> wrappers =
-            DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.state=?", "3");
-        if (wrappers != null && !wrappers.isEmpty()) {
-          for (DGTEWrapper w : wrappers) {
-            waitList.add(w.taskEntity);
-          }
-        }
-      } else if (type == 3) {
-        List<UTEWrapper> wrappers = DbEntity.findRelationData(UTEWrapper.class,
-            "UploadTaskEntity.state=?", "3");
-        if (wrappers != null && !wrappers.isEmpty()) {
-          for (UTEWrapper w : wrappers) {
-            waitList.add(w.taskEntity);
-          }
-        }
-      }
-      return waitList;
-    }
-
-    private void handleTask(List<AbsTaskEntity> waitList) {
-      for (AbsTaskEntity te : waitList) {
-        if (te.getEntity() == null) continue;
-        AbsTask task = getTask(te.getEntity());
-        if (task != null) continue;
-        if (te instanceof DownloadTaskEntity) {
-          if (te.getRequestType() == AbsTaskEntity.D_FTP || te.getRequestType() == AbsTaskEntity.U_FTP) {
-            te.setUrlEntity(CommonUtil.getFtpUrlInfo(te.getEntity().getKey()));
-          }
-          mQueue = DownloadTaskQueue.getInstance();
-        } else if (te instanceof UploadTaskEntity) {
-          mQueue = UploadTaskQueue.getInstance();
-        } else if (te instanceof DownloadGroupTaskEntity) {
-          mQueue = DownloadGroupTaskQueue.getInstance();
-        }
-        createTask(te);
-        sendWaitState();
+        startTask();
       }
     }
   }

+ 2 - 2
Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java

@@ -10,8 +10,8 @@ final class StopAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
   /**
    * @param targetName 产生任务的对象名
    */
-  StopAllCmd(String targetName, T entity, int taskType) {
-    super(targetName, entity, taskType);
+  StopAllCmd(String targetName, T entity) {
+    super(targetName, entity);
   }
 
   @Override public void executeCmd() {

+ 4 - 4
Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java

@@ -17,10 +17,10 @@
 package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
+import android.util.Log;
 import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.util.ALog;
 
 /**
  * Created by lyy on 2016/9/20.
@@ -28,8 +28,8 @@ import com.arialyy.aria.util.ALog;
  */
 class StopCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
 
-  StopCmd(String targetName, T entity, int taskType) {
-    super(targetName, entity, taskType);
+  StopCmd(String targetName, T entity) {
+    super(targetName, entity);
   }
 
   @Override public void executeCmd() {
@@ -39,7 +39,7 @@ class StopCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
       if (mTaskEntity.getEntity().getState() == IEntity.STATE_RUNNING) {
         stopTask();
       } else {
-        ALog.w(TAG, "停止命令执行失败,【调度器中没有该任务】");
+        Log.w(TAG, "停止命令执行失败,【调度器中没有该任务】");
       }
     } else {
       if (!TextUtils.isEmpty(mTargetName)) {

+ 123 - 239
Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java

@@ -16,21 +16,17 @@
 package com.arialyy.aria.core.common;
 
 import android.content.Context;
+import android.util.Log;
 import android.util.SparseArray;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.download.DownloadEntity;
+import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.AbsNormalEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IDownloadListener;
 import com.arialyy.aria.core.inf.IEventListener;
-import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.util.ALog;
+import com.arialyy.aria.core.upload.UploadTaskEntity;
 import com.arialyy.aria.util.CommonUtil;
-import com.arialyy.aria.util.DbHelper;
 import java.io.File;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 import java.util.Timer;
@@ -40,41 +36,28 @@ import java.util.concurrent.Executors;
 
 /**
  * Created by AriaL on 2017/7/1.
- * 任务处理
+ * 文件下载
  */
 public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
     implements Runnable, IUtil {
-  public static final String STATE = "_state_";
-  public static final String RECORD = "_record_";
-  protected static final long SUB_LEN = 1024 * 1024;
-
-  private final String TAG = "AbsFileer";
+  private final String TAG = "Downloader";
   protected IEventListener mListener;
   protected TASK_ENTITY mTaskEntity;
   protected ENTITY mEntity;
+  protected File mConfigFile;//信息配置文件
   protected Context mContext;
-  protected File mTempFile; //文件
+  protected File mTempFile; //下载的文件
+  protected boolean isNewTask = true;
   protected StateConstance mConstance;
   private ExecutorService mFixedThreadPool;
-  //总线程数
-  private int mTotalThreadNum;
-  //启动线程数
-  private int mStartThreadNum;
-  //已完成的线程数
-  private int mCompleteThreadNum;
+  private int mThreadNum, mRealThreadNum;
   private SparseArray<AbsThreadTask> mTask = new SparseArray<>();
 
   /**
    * 小于1m的文件不启用多线程
    */
+  private static final long SUB_LEN = 1024 * 1024;
   private Timer mTimer;
-  @Deprecated
-  private File mConfigFile;
-  /**
-   * 进度刷新间隔
-   */
-  private long mUpdateInterval = 1000;
-  protected TaskRecord mRecord;
 
   protected AbsFileer(IEventListener listener, TASK_ENTITY taskEntity) {
     mListener = listener;
@@ -84,12 +67,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
     mConstance = new StateConstance();
   }
 
-  public void setNewTask(boolean newTask) {
-    mTaskEntity.setNewTask(newTask);
-  }
-
   @Override public void setMaxSpeed(double maxSpeed) {
-    for (int i = 0; i < mTotalThreadNum; i++) {
+    for (int i = 0; i < mThreadNum; i++) {
       AbsThreadTask task = mTask.get(i);
       if (task != null) {
         task.setMaxSpeed(maxSpeed);
@@ -97,40 +76,43 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
     }
   }
 
+  public StateConstance getConstance() {
+    return mConstance;
+  }
+
   @Override public void run() {
-    if (mConstance.isRunning) {
-      return;
-    }
     startFlow();
   }
 
   /**
-   * 开始流程
+   * 开始下载流程
    */
   private void startFlow() {
-    mConstance.resetState();
     checkTask();
-    mConstance.TASK_RECORD = mRecord;
     if (mListener instanceof IDownloadListener) {
       ((IDownloadListener) mListener).onPostPre(mEntity.getFileSize());
     }
-    if (!mTaskEntity.isSupportBP()) {
-      mTotalThreadNum = 1;
-      mStartThreadNum = 1;
+    mConstance.cleanState();
+    mConstance.isRunning = true;
+    if (!mTaskEntity.isSupportBP) {
+      mThreadNum = 1;
+      mConstance.THREAD_NUM = mThreadNum;
       handleNoSupportBP();
     } else {
-      mTotalThreadNum =
-          mTaskEntity.isNewTask() ? (mStartThreadNum = setNewTaskThreadNum()) : mTotalThreadNum;
+      mThreadNum = isNewTask ? (getNewTaskThreadNum()) : mRealThreadNum;
+      mConstance.THREAD_NUM = mThreadNum;
       handleBreakpoint();
     }
-    mConstance.START_THREAD_NUM = mTotalThreadNum;
     startTimer();
   }
 
   /**
    * 设置新任务的最大线程数
    */
-  protected abstract int setNewTaskThreadNum();
+  protected int getNewTaskThreadNum() {
+    return mEntity.getFileSize() <= SUB_LEN || mTaskEntity.requestType == AbsTaskEntity.FTP_DIR ? 1
+        : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
+  }
 
   /**
    * 启动进度获取定时器
@@ -139,39 +121,22 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
     mTimer = new Timer(true);
     mTimer.schedule(new TimerTask() {
       @Override public void run() {
-        if (mConstance.isComplete()
-            || mConstance.isStop()
-            || mConstance.isCancel()
-            || !mConstance.isRunning) {
+        if (mConstance.isComplete() || !mConstance.isRunning) {
           closeTimer();
         } else if (mConstance.CURRENT_LOCATION >= 0) {
           mListener.onProgress(mConstance.CURRENT_LOCATION);
         }
       }
-    }, 0, mUpdateInterval);
+    }, 0, 1000);
   }
 
-  protected void closeTimer() {
+  private void closeTimer() {
     if (mTimer != null) {
       mTimer.purge();
       mTimer.cancel();
-      mTimer = null;
     }
   }
 
-  /**
-   * 设置定时器更新间隔
-   *
-   * @param interval 单位毫秒,不能小于0
-   */
-  protected void setUpdateInterval(long interval) {
-    if (interval < 0) {
-      ALog.w(TAG, "更新间隔不能小于0,默认为1000毫秒");
-      return;
-    }
-    mUpdateInterval = interval;
-  }
-
   @Override public long getFileSize() {
     return mEntity.getFileSize();
   }
@@ -194,23 +159,28 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
     if (mFixedThreadPool != null) {
       mFixedThreadPool.shutdown();
     }
-    for (int i = 0; i < mStartThreadNum; i++) {
+    for (int i = 0; i < mThreadNum; i++) {
       AbsThreadTask task = mTask.get(i);
       if (task != null) {
         task.cancel();
       }
     }
+    if (mTaskEntity instanceof DownloadTaskEntity) {
+      CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, (DownloadTaskEntity) mTaskEntity);
+    } else if (mTaskEntity instanceof UploadTaskEntity) {
+      CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, (UploadTaskEntity) mTaskEntity);
+    }
   }
 
   @Override public void stop() {
     closeTimer();
-    mConstance.isRunning = false;
-    mConstance.isStop = true;
     if (mConstance.isComplete()) return;
+    mConstance.isStop = true;
+    mConstance.isRunning = false;
     if (mFixedThreadPool != null) {
       mFixedThreadPool.shutdown();
     }
-    for (int i = 0; i < mStartThreadNum; i++) {
+    for (int i = 0; i < mThreadNum; i++) {
       AbsThreadTask task = mTask.get(i);
       if (task != null) {
         task.stop();
@@ -230,146 +200,68 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
   }
 
   /**
-   * 检查任务、检查线程数
-   * 新任务条件:
-   * 1、文件不存在
-   * 2、下载记录文件缺失或不匹配
-   * 3、数据库记录不存在
-   * 4、不支持断点,则是新任务
+   * 返回该下载器的
    */
-  protected void checkTask() {
-    mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
-    if (mConfigFile.exists()) {
-      convertDb();
-    } else {
-      mRecord = DbHelper.getTaskRecord(mTaskEntity.getKey());
-      if (mRecord == null) {
-        initRecord();
-        mTaskEntity.setNewTask(true);
-      } else {
-        if (mRecord.threadRecords == null || mRecord.threadRecords.isEmpty()) {
-          initRecord();
-          mTaskEntity.setNewTask(true);
-        } else if (mTempFile.length() == 0) {
-          mRecord.deleteData();
-          initRecord();
-          mTaskEntity.setNewTask(true);
-        } else {
-          for (ThreadRecord tr : mRecord.threadRecords) {
-            if (tr.isComplete) {
-              mCompleteThreadNum++;
-            } else {
-              mStartThreadNum++;
-            }
-          }
-          mTotalThreadNum = mRecord.threadRecords.size();
-          mTaskEntity.setNewTask(false);
-        }
-      }
-    }
+  public IEventListener getListener() {
+    return mListener;
   }
 
   /**
-   * convertDb 为兼容性代码
-   * 从3.4.1开始,线程配置信息将存储在数据库中。
-   * 将配置文件的内容复制到数据库中,并将配置文件删除
+   * 检查任务是否是新任务,新任务条件:
+   * 1、文件不存在
+   * 2、下载记录文件不存在
+   * 3、下载记录文件缺失或不匹配
+   * 4、数据库记录不存在
+   * 5、不支持断点,则是新任务
    */
-  private void convertDb() {
-    List<RecordWrapper> records =
-        DbEntity.findRelationData(RecordWrapper.class, "TaskRecord.filePath=?",
-            mTaskEntity.getKey());
-    if (records == null || records.size() == 0) {
-      Properties pro = CommonUtil.loadConfig(mConfigFile);
-      if (pro.isEmpty()) {
-        mTaskEntity.setNewTask(true);
-        return;
-      }
-      initRecord();
-      Set<Object> keys = pro.keySet();
-      // 老版本记录是5s存一次,但是5s中内,如果线程执行完成,record记录是没有的,只有state记录...
-      // 第一步应该是record 和 state去重取正确的线程数
-      Set<Integer> set = new HashSet<>();
-      for (Object key : keys) {
-        String str = String.valueOf(key);
-        int i = Integer.parseInt(str.substring(str.length() - 1, str.length()));
-        set.add(i);
-      }
-      int threadNum = set.size();
-      if (threadNum == 0) {
-        mTaskEntity.setNewTask(true);
-        return;
-      }
-      mRecord.threadNum = threadNum;
-      mTotalThreadNum = threadNum;
-
-      for (int i = 0; i < threadNum; i++) {
-        ThreadRecord tRecord = new ThreadRecord();
-        tRecord.key = mRecord.filePath;
-        Object state = pro.getProperty(mTempFile.getName() + STATE + i);
-        Object record = pro.getProperty(mTempFile.getName() + RECORD + i);
-        if (state != null && Integer.parseInt(state + "") == 1) {
-          mCompleteThreadNum++;
-          tRecord.isComplete = true;
-          continue;
-        }
-        mStartThreadNum++;
-        if (record != null) {
-          Long temp = Long.parseLong(record + "");
-          tRecord.startLocation = temp > 0 ? temp : 0;
-        } else {
-          tRecord.startLocation = 0;
-        }
-        mRecord.threadRecords.add(tRecord);
-      }
-      mConfigFile.delete();
-    }
-  }
+  protected abstract void checkTask();
 
   /**
-   * 初始化记录
+   * 检查记录文件,如果是新任务返回{@code true},否则返回{@code false}
    */
-  private void initRecord() {
-    mRecord = new TaskRecord();
-    mRecord.fileName = mEntity.getFileName();
-    mRecord.filePath = mTaskEntity.getKey();
-    mRecord.threadRecords = new ArrayList<>();
-    mRecord.isGroupRecord = mTaskEntity.getEntity().isGroupChild();
-    mRecord.isOpenDynamicFile =
-        AriaManager.getInstance(AriaManager.APP).getDownloadConfig().isOpenDynamicFile();
-    if (mRecord.isGroupRecord) {
-      if (mTaskEntity.getEntity() instanceof DownloadEntity) {
-        mRecord.dGroupName = ((DownloadEntity) mTaskEntity.getEntity()).getGroupName();
+  protected boolean checkConfigFile() {
+    Properties pro = CommonUtil.loadConfig(mConfigFile);
+    if (pro.isEmpty()) {
+      return true;
+    }
+    Set<Object> keys = pro.keySet();
+    int num = 0;
+    for (Object key : keys) {
+      if (String.valueOf(key).contains("_record_")) {
+        num++;
       }
     }
-  }
-
-  /**
-   * 保存任务记录
-   */
-  private void saveRecord() {
-    mRecord.save();
-    for (ThreadRecord tr : mRecord.threadRecords) {
-      tr.save();
+    if (num == 0) {
+      return true;
     }
-  }
-
-  public TaskRecord getRecord() {
-    return mRecord;
+    mRealThreadNum = num;
+    for (int i = 0; i < mRealThreadNum; i++) {
+      if (pro.getProperty(mTempFile.getName() + "_record_" + i) == null) {
+        Object state = pro.getProperty(mTempFile.getName() + "_state_" + i);
+        if (state != null && Integer.parseInt(state + "") == 1) {
+          continue;
+        }
+        return true;
+      }
+    }
+    return false;
   }
 
   /**
    * 恢复记录地址
    *
-   * @return {@code true}任务已完成
+   * @return true 表示下载完成
    */
   private boolean resumeRecordLocation(int i, long startL, long endL) {
     mConstance.CURRENT_LOCATION += endL - startL;
-    ALog.d(TAG, "任务【" + mTaskEntity.getEntity().getFileName() + "】线程__" + i + "__已完成");
-    mConstance.COMPLETE_THREAD_NUM = mCompleteThreadNum;
+    Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
+    mConstance.COMPLETE_THREAD_NUM++;
     mConstance.STOP_NUM++;
     mConstance.CANCEL_NUM++;
     if (mConstance.isComplete()) {
-      mRecord.deleteData();
+      if (mConfigFile.exists()) {
+        mConfigFile.delete();
+      }
       mListener.onComplete();
       mConstance.isRunning = false;
       return true;
@@ -385,8 +277,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
    * @param endL 该任务结束位置
    * @param fileLength 该任务需要处理的文件长度
    */
-  private AbsThreadTask createSingThreadTask(int i, long startL, long endL, long fileLength,
-      ThreadRecord record) {
+  private AbsThreadTask createSingThreadTask(int i, long startL, long endL, long fileLength) {
     SubThreadConfig<TASK_ENTITY> config = new SubThreadConfig<>();
     config.FILE_SIZE = fileLength;
     config.URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getUrl();
@@ -394,76 +285,63 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
     config.THREAD_ID = i;
     config.START_LOCATION = startL;
     config.END_LOCATION = endL;
-    config.SUPPORT_BP = mTaskEntity.isSupportBP();
+    config.CONFIG_FILE_PATH = mConfigFile.getPath();
+    config.SUPPORT_BP = mTaskEntity.isSupportBP;
     config.TASK_ENTITY = mTaskEntity;
-    config.THREAD_RECORD = record;
     return selectThreadTask(config);
   }
 
+  /**
+   * 处理断点
+   */
   private void handleBreakpoint() {
     long fileLength = mEntity.getFileSize();
-    long blockSize = fileLength / mTotalThreadNum;
-    int[] threadId = new int[mTotalThreadNum];
-    int rl = 0;
-
-    mRecord.fileLength = fileLength;
-    for (int i = 0; i < mTotalThreadNum; i++) {
-      threadId[i] = -1;
+    Properties pro = CommonUtil.loadConfig(mConfigFile);
+    int blockSize = (int) (fileLength / mThreadNum);
+    int[] recordL = new int[mThreadNum];
+    for (int i = 0; i < mThreadNum; i++) {
+      recordL[i] = -1;
     }
-    if (mTaskEntity.isNewTask() && !handleNewTask()) {
-      return;
+    int rl = 0;
+    if (isNewTask) {
+      handleNewTask();
     }
-    for (int i = 0; i < mTotalThreadNum; i++) {
+    for (int i = 0; i < mThreadNum; i++) {
       long startL = i * blockSize, endL = (i + 1) * blockSize;
-      ThreadRecord tr;
-      boolean isNewTr = false;  // 是否是新的线程记录
-      if (mTaskEntity.isNewTask()) {
-        tr = new ThreadRecord();
-        tr.key = mRecord.filePath;
-        tr.threadId = i;
-        isNewTr = true;
-      } else {
-        tr = mRecord.threadRecords.get(i);
-      }
-      if (tr.isComplete) {//该线程已经完成
+      Object state = pro.getProperty(mTempFile.getName() + "_state_" + i);
+      if (state != null && Integer.parseInt(state + "") == 1) {  //该线程已经完成
         if (resumeRecordLocation(i, startL, endL)) return;
         continue;
       }
-
+      //分配下载位置
+      Object record = pro.getProperty(mTempFile.getName() + "_record_" + i);
       //如果有记录,则恢复下载
-      if (tr.startLocation >= 0) {
-        Long r = tr.startLocation;
-        //记录的位置需要在线程区间中
-        if (startL < r && r < (i == (mTotalThreadNum - 1) ? fileLength : endL)) {
-          mConstance.CURRENT_LOCATION += r - startL;
-          startL = r;
-        }
-        ALog.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载");
+      if (!isNewTask && record != null && Long.parseLong(record + "") >= 0) {
+        Long r = Long.parseLong(record + "");
+        mConstance.CURRENT_LOCATION += r - startL;
+        Log.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载");
+        startL = r;
+        recordL[rl] = i;
+        rl++;
+      } else {
+        recordL[rl] = i;
+        rl++;
       }
-      //最后一个线程的结束位置即为文件的总长度
-      if (i == (mTotalThreadNum - 1)) {
+      if (i == (mThreadNum - 1)) {
+        //最后一个线程的结束位置即为文件的总长度
         endL = fileLength;
       }
-      // 更新记录
-      tr.startLocation = startL;
-      tr.endLocation = endL;
-      if (isNewTr) {
-        mRecord.threadRecords.add(tr);
-      }
-      AbsThreadTask task = createSingThreadTask(i, startL, endL, fileLength, tr);
+      AbsThreadTask task = createSingThreadTask(i, startL, endL, fileLength);
       if (task == null) return;
       mTask.put(i, task);
-      threadId[rl] = i;
-      rl++;
     }
-    saveRecord();
-    startThreadTask(threadId);
+    startSingleTask(recordL);
   }
 
   /**
    * 启动单线程下载任务
    */
-  private void startThreadTask(int[] recordL) {
+  private void startSingleTask(int[] recordL) {
     if (mConstance.CURRENT_LOCATION > 0) {
       mListener.onResume(mConstance.CURRENT_LOCATION);
     } else {
@@ -481,10 +359,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
 
   /**
    * 处理新任务
-   *
-   * @return {@code true}创建新任务失败
    */
-  protected abstract boolean handleNewTask();
+  protected abstract void handleNewTask();
 
   /**
    * 处理不支持断点的下载
@@ -497,7 +373,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
     config.THREAD_ID = 0;
     config.START_LOCATION = 0;
     config.END_LOCATION = config.FILE_SIZE;
-    config.SUPPORT_BP = mTaskEntity.isSupportBP();
+    config.CONFIG_FILE_PATH = mConfigFile.getPath();
+    config.SUPPORT_BP = mTaskEntity.isSupportBP;
     config.TASK_ENTITY = mTaskEntity;
     AbsThreadTask task = selectThreadTask(config);
     if (task == null) return;
@@ -511,4 +388,11 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
    * 选择单任务线程的类型
    */
   protected abstract AbsThreadTask selectThreadTask(SubThreadConfig<TASK_ENTITY> config);
+
+  protected void failDownload(String errorMsg) {
+    closeTimer();
+    Log.e(TAG, errorMsg);
+    mConstance.isRunning = false;
+    mListener.onFail();
+  }
 }

+ 0 - 298
Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpInfoThread.java

@@ -1,298 +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.common;
-
-import android.text.TextUtils;
-import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.FtpUrlEntity;
-import com.arialyy.aria.core.inf.AbsEntity;
-import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.core.upload.UploadEntity;
-import com.arialyy.aria.util.ALog;
-import com.arialyy.aria.util.Regular;
-import java.io.File;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.apache.commons.net.ftp.FTP;
-import org.apache.commons.net.ftp.FTPClient;
-import org.apache.commons.net.ftp.FTPFile;
-import org.apache.commons.net.ftp.FTPReply;
-
-/**
- * Created by Aria.Lao on 2017/7/25.
- * 获取ftp文件夹信息
- */
-public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
-    implements Runnable {
-
-  private final String TAG = "AbsFtpInfoThread";
-  protected ENTITY mEntity;
-  protected TASK_ENTITY mTaskEntity;
-  private int mConnectTimeOut;
-  protected OnFileInfoCallback mCallback;
-  protected long mSize = 0;
-  protected String charSet = "UTF-8";
-  private boolean isUpload = false;
-
-  public AbsFtpInfoThread(TASK_ENTITY taskEntity, OnFileInfoCallback callback) {
-    mTaskEntity = taskEntity;
-    mEntity = taskEntity.getEntity();
-    mConnectTimeOut =
-        AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
-    mCallback = callback;
-    if (mEntity instanceof UploadEntity) {
-      isUpload = true;
-    }
-  }
-
-  /**
-   * 设置请求的远程文件路径
-   *
-   * @return 远程文件路径
-   */
-  protected abstract String setRemotePath();
-
-  @Override public void run() {
-    FTPClient client = null;
-    try {
-      client = createFtpClient();
-      if (client == null) {
-        failDownload("创建FTP客户端失败", true);
-        return;
-      }
-      String remotePath =
-          new String(setRemotePath().getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
-      FTPFile[] files = client.listFiles(remotePath);
-      String s = client.getReplyString();
-      ALog.i(TAG, s);
-      boolean isExist = files.length != 0;
-      if (!isExist && !isUpload) {
-        failDownload("文件不存在,任务链接【" + mTaskEntity.getUrlEntity().url + "】,remotePath:" + remotePath,
-            false);
-        int i = remotePath.lastIndexOf(File.separator);
-        FTPFile[] files1;
-        if (i == -1) {
-          files1 = client.listFiles();
-        } else {
-          files1 = client.listFiles(remotePath.substring(0, i + 1));
-        }
-        if (files1.length > 0) {
-          ALog.i(TAG, "路径【" + setRemotePath() + "】下的文件列表 ===================================");
-          for (FTPFile file : files1) {
-            ALog.d(TAG, file.toString());
-          }
-          ALog.i(TAG,
-              "================================= --end-- ===================================");
-        } else {
-          String msg = client.getReplyString();
-          ALog.w(TAG, msg);
-        }
-        client.disconnect();
-        return;
-      }
-      //为了防止编码错乱,需要使用原始字符串
-      mSize = getFileSize(files, client, setRemotePath());
-      int reply = client.getReplyCode();
-      if (!FTPReply.isPositiveCompletion(reply)) {
-        if (isUpload) {
-          //服务器上没有该文件路径,表示该任务为新的上传任务
-          mTaskEntity.setNewTask(true);
-        } else {
-          client.disconnect();
-          failDownload("获取文件信息错误,错误码为:" + reply + ",msg:" + client.getReplyString(), true);
-          return;
-        }
-      }
-      mTaskEntity.setCode(reply);
-      if (mSize != 0 && !isUpload) {
-        mEntity.setFileSize(mSize);
-      }
-      mTaskEntity.update();
-      onPreComplete(reply);
-    } catch (IOException e) {
-      failDownload(e.getMessage(), true);
-    } finally {
-      if (client != null) {
-        try {
-          client.disconnect();
-        } catch (IOException e) {
-          e.printStackTrace();
-        }
-      }
-    }
-  }
-
-  /**
-   * 检查文件是否存在
-   *
-   * @return {@code true}存在
-   */
-  private boolean checkFileExist(FTPFile[] ftpFiles, String fileName) {
-    for (FTPFile ff : ftpFiles) {
-      if (ff.getName().equals(fileName)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  public void start() {
-    new Thread(this).start();
-  }
-
-  protected void onPreComplete(int code) {
-
-  }
-
-  /**
-   * 创建FTP客户端
-   */
-  private FTPClient createFtpClient() {
-    FTPClient client = null;
-    final FtpUrlEntity urlEntity = mTaskEntity.getUrlEntity();
-    try {
-      Pattern p = Pattern.compile(Regular.REG_IP_V4);
-      Matcher m = p.matcher(urlEntity.hostName);
-      if (m.find() && m.groupCount() > 0) {
-        client = new FTPClient();
-        InetAddress ip = InetAddress.getByName(urlEntity.hostName);
-        client.setConnectTimeout(10000);  // 连接10s超时
-        client.connect(ip, Integer.parseInt(urlEntity.port));
-        mTaskEntity.getUrlEntity().validAddr = ip;
-      } else {
-        InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName);
-        client = connect(new FTPClient(), ips, 0, Integer.parseInt(urlEntity.port));
-      }
-
-      if (client == null) {
-        failDownload("链接失败", false);
-        return null;
-      }
-
-      boolean loginSuccess = true;
-      if (urlEntity.needLogin) {
-        try {
-          if (TextUtils.isEmpty(urlEntity.account)) {
-            loginSuccess = client.login(urlEntity.user, urlEntity.password);
-          } else {
-            loginSuccess = client.login(urlEntity.user, urlEntity.password, urlEntity.account);
-          }
-        } catch (IOException e) {
-          ALog.e(TAG, client.getReplyString());
-          return null;
-        }
-      }
-
-      if (!loginSuccess) {
-        failDownload("登录失败", false);
-        return null;
-      }
-
-      int reply = client.getReplyCode();
-      if (!FTPReply.isPositiveCompletion(reply)) {
-        client.disconnect();
-        failDownload("无法连接到ftp服务器,错误码为:" + reply + ",msg:" + client.getReplyString(), true);
-        return null;
-      }
-      // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
-      charSet = "UTF-8";
-      reply = client.sendCommand("OPTS UTF8", "ON");
-      if (!TextUtils.isEmpty(mTaskEntity.getCharSet()) || (!FTPReply.isPositiveCompletion(reply)
-          && reply != FTPReply.COMMAND_OK)) {
-        ALog.i(TAG, "FTP 服务器不支持开启UTF8编码,尝试使用Aria手动设置的编码");
-        charSet = mTaskEntity.getCharSet();
-      }
-      client.setControlEncoding(charSet);
-      client.setDataTimeout(10 * 1000);
-      client.enterLocalPassiveMode();
-      client.setFileType(FTP.BINARY_FILE_TYPE);
-      client.setConnectTimeout(mConnectTimeOut);
-    } catch (IOException e) {
-      e.printStackTrace();
-    }
-    return client;
-  }
-
-  /**
-   * 连接到ftp服务器
-   */
-  private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) {
-    try {
-      client.connect(ips[index], port);
-      mTaskEntity.getUrlEntity().validAddr = ips[index];
-      return client;
-    } catch (IOException e) {
-      //e.printStackTrace();
-      try {
-        if (client.isConnected()) {
-          client.disconnect();
-        }
-      } catch (IOException e1) {
-        e1.printStackTrace();
-      }
-      if (index + 1 >= ips.length) {
-        ALog.w(TAG, "遇到[ECONNREFUSED-连接被服务器拒绝]错误,已没有其他地址,链接失败");
-        return null;
-      }
-      try {
-        Thread.sleep(1000);
-      } catch (InterruptedException e1) {
-        e1.printStackTrace();
-      }
-      ALog.w(TAG, "遇到[ECONNREFUSED-连接被服务器拒绝]错误,正在尝试下一个地址");
-      return connect(new FTPClient(), ips, index + 1, port);
-    }
-  }
-
-  /**
-   * 遍历FTP服务器上对应文件或文件夹大小
-   *
-   * @throws IOException 字符串编码转换错误
-   */
-  private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
-    long size = 0;
-    String path = dirName + "/";
-    for (FTPFile file : files) {
-      if (file.isFile()) {
-        size += file.getSize();
-        handleFile(path + file.getName(), file);
-      } else {
-        String remotePath =
-            new String((path + file.getName()).getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
-        size += getFileSize(client.listFiles(remotePath), client, path + file.getName());
-      }
-    }
-    return size;
-  }
-
-  /**
-   * 处理FTP文件信息
-   *
-   * @param remotePath ftp服务器文件夹路径
-   * @param ftpFile ftp服务器上对应的文件
-   */
-  protected void handleFile(String remotePath, FTPFile ftpFile) {
-  }
-
-  private void failDownload(String errorMsg, boolean needRetry) {
-    ALog.e(TAG, errorMsg);
-    if (mCallback != null) {
-      mCallback.onFail(mEntity.getKey(), errorMsg, needRetry);
-    }
-  }
-}

+ 0 - 141
Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpThreadTask.java

@@ -1,141 +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.common;
-
-import android.text.TextUtils;
-import com.arialyy.aria.core.FtpUrlEntity;
-import com.arialyy.aria.core.inf.AbsNormalEntity;
-import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.core.inf.IEventListener;
-import com.arialyy.aria.util.ALog;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import org.apache.commons.net.ftp.FTP;
-import org.apache.commons.net.ftp.FTPClient;
-import org.apache.commons.net.ftp.FTPReply;
-
-/**
- * Created by lyy on 2017/9/26.
- * FTP单任务父类
- */
-public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
-    extends AbsThreadTask<ENTITY, TASK_ENTITY> {
-  private final String TAG = "AbsFtpThreadTask";
-  protected String charSet, port;
-  /**
-   * D_FTP 服务器编码
-   */
-  public static String SERVER_CHARSET = "ISO-8859-1";
-
-  protected AbsFtpThreadTask(StateConstance constance, IEventListener listener,
-      SubThreadConfig<TASK_ENTITY> info) {
-    super(constance, listener, info);
-  }
-
-  /**
-   * 构建FTP客户端
-   */
-  protected FTPClient createClient() {
-    FTPClient client = null;
-    final FtpUrlEntity urlEntity = mTaskEntity.getUrlEntity();
-    if (urlEntity.validAddr == null) {
-      try {
-        InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName);
-        client = connect(new FTPClient(), ips, 0, Integer.parseInt(urlEntity.port));
-        if (client == null) {
-          return null;
-        }
-      } catch (UnknownHostException e) {
-        e.printStackTrace();
-      }
-    } else {
-      client = new FTPClient();
-      try {
-        client.connect(urlEntity.validAddr, Integer.parseInt(urlEntity.port));
-      } catch (IOException e) {
-        ALog.e(TAG, ALog.getExceptionString(e));
-        return null;
-      }
-    }
-
-    if (client == null) {
-      return null;
-    }
-
-    try {
-      if (urlEntity.needLogin) {
-        if (TextUtils.isEmpty(urlEntity.account)) {
-          client.login(urlEntity.user, urlEntity.password);
-        } else {
-          client.login(urlEntity.user, urlEntity.password, urlEntity.account);
-        }
-      }
-      int reply = client.getReplyCode();
-      if (!FTPReply.isPositiveCompletion(reply)) {
-        client.disconnect();
-        fail(STATE.CURRENT_LOCATION,
-            "无法连接到ftp服务器,错误码为:" + reply + ",msg:" + client.getReplyString(), null);
-        return null;
-      }
-      // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
-      charSet = "UTF-8";
-      if (!TextUtils.isEmpty(mTaskEntity.getCharSet()) || !FTPReply.isPositiveCompletion(
-          client.sendCommand("OPTS UTF8", "ON"))) {
-        charSet = mTaskEntity.getCharSet();
-      }
-      client.setControlEncoding(charSet);
-      client.setDataTimeout(mReadTimeOut);
-      client.setConnectTimeout(mConnectTimeOut);
-      client.enterLocalPassiveMode();
-      client.setFileType(FTP.BINARY_FILE_TYPE);
-      client.setControlKeepAliveTimeout(5000);
-    } catch (IOException e) {
-      e.printStackTrace();
-    }
-    return client;
-  }
-
-  /**
-   * 连接到ftp服务器
-   */
-  private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) {
-    try {
-      client.connect(ips[index], port);
-      mTaskEntity.getUrlEntity().validAddr = ips[index];
-      return client;
-    } catch (IOException e) {
-      try {
-        if (client.isConnected()) {
-          client.disconnect();
-        }
-      } catch (IOException e1) {
-        e1.printStackTrace();
-      }
-      if (index + 1 >= ips.length) {
-        ALog.w(TAG, "遇到[ECONNREFUSED-连接被服务器拒绝]错误,已没有其他地址,链接失败");
-        return null;
-      }
-      try {
-        Thread.sleep(1000);
-      } catch (InterruptedException e1) {
-        e1.printStackTrace();
-      }
-      ALog.w(TAG, "遇到[ECONNREFUSED-连接被服务器拒绝]错误,正在尝试下一个地址");
-      return connect(new FTPClient(), ips, index + 1, port);
-    }
-  }
-}

+ 65 - 126
Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java

@@ -16,83 +16,62 @@
 package com.arialyy.aria.core.common;
 
 import android.os.Build;
+import android.text.TextUtils;
+import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.inf.AbsNormalEntity;
+import com.arialyy.aria.core.inf.AbsEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEventListener;
 import com.arialyy.aria.core.upload.UploadEntity;
-import com.arialyy.aria.util.ALog;
-import com.arialyy.aria.util.ErrorHelp;
-import com.arialyy.aria.util.NetUtils;
+import com.arialyy.aria.util.CommonUtil;
+import java.io.File;
 import java.io.IOException;
 import java.math.BigDecimal;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import java.util.Properties;
 
 /**
  * Created by lyy on 2017/1/18.
- * 任务线程
+ * 下载线程
  */
-public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
+public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
     implements Runnable {
-  /**
-   * 线程重试次数
-   */
-  private final int RETRY_NUM = 2;
-  /**
-   * 线程重试间隔
-   */
-  private final int RETRY_INTERVAL = 5000;
   private final String TAG = "AbsThreadTask";
   protected long mChildCurrentLocation = 0, mSleepTime = 0;
   protected int mBufSize;
+  protected String mConfigFPath;
   protected IEventListener mListener;
   protected StateConstance STATE;
   protected SubThreadConfig<TASK_ENTITY> mConfig;
   protected ENTITY mEntity;
   protected TASK_ENTITY mTaskEntity;
-  private int mFailNum = 0;
-  private String mTaskType;
-  private Timer mFailTimer;
-  private long mLastSaveTime;
-  private ExecutorService mConfigThreadPool;
-  protected int mConnectTimeOut; //连接超时时间
-  protected int mReadTimeOut; //流读取的超时时间
-  protected boolean isNotNetRetry = false;  //断网情况是否重试
-
-  private Thread mConfigThread = new Thread(new Runnable() {
-    @Override public void run() {
-      final long currentTemp = mChildCurrentLocation;
-      try {
-        writeConfig(false, currentTemp);
-      } catch (IOException e) {
-        e.printStackTrace();
-      }
-    }
-  });
+  /**
+   * FTP 服务器编码
+   */
+  public static String SERVER_CHARSET = "ISO-8859-1";
 
   protected AbsThreadTask(StateConstance constance, IEventListener listener,
       SubThreadConfig<TASK_ENTITY> info) {
+    AriaManager manager = AriaManager.getInstance(AriaManager.APP);
     STATE = constance;
+    STATE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut();
+    STATE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut();
     mListener = listener;
     mConfig = info;
     mTaskEntity = mConfig.TASK_ENTITY;
     mEntity = mTaskEntity.getEntity();
-    mTaskType = getTaskType();
-    mLastSaveTime = System.currentTimeMillis();
-    mConfigThreadPool = Executors.newCachedThreadPool();
+    if (mConfig.SUPPORT_BP) {
+      mConfigFPath = info.CONFIG_FILE_PATH;
+    }
+    mBufSize = manager.getDownloadConfig().getBuffSize();
+    setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed());
   }
 
-  protected abstract String getTaskType();
-
   public void setMaxSpeed(double maxSpeed) {
     if (-0.9999 < maxSpeed && maxSpeed < 0.00001) {
       mSleepTime = 0;
     } else {
       BigDecimal db = new BigDecimal(
-          ((mBufSize / 1024) * (filterVersion() ? 1 : STATE.START_THREAD_NUM) / maxSpeed) * 1000);
+          ((mBufSize / 1024) * (filterVersion() ? 1 : STATE.THREAD_NUM) / maxSpeed) * 1000);
       mSleepTime = db.setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
     }
   }
@@ -101,37 +80,28 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
   }
 
-  @Override protected void finalize() throws Throwable {
-    super.finalize();
-    if (mConfigThreadPool != null) {
-      mConfigThreadPool.shutdown();
-    }
-  }
-
   /**
-   * 停止任务
+   * 停止下载
    */
   public void stop() {
     synchronized (AriaManager.LOCK) {
       try {
         if (mConfig.SUPPORT_BP) {
-          final long currentTemp = mChildCurrentLocation;
           STATE.STOP_NUM++;
-          ALog.d(TAG, "任务【"
+          Log.d(TAG, "任务【"
               + mConfig.TEMP_FILE.getName()
               + "】thread__"
               + mConfig.THREAD_ID
-              + "__停止【停止位置: "
-              + currentTemp
-              + "】");
-          writeConfig(false, currentTemp);
+              + "__停止, stop location ==> "
+              + mChildCurrentLocation);
+          writeConfig(false, mChildCurrentLocation);
           if (STATE.isStop()) {
-            ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
+            Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
             STATE.isRunning = false;
             mListener.onStop(STATE.CURRENT_LOCATION);
           }
         } else {
-          ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
+          Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
           STATE.isRunning = false;
           mListener.onStop(STATE.CURRENT_LOCATION);
         }
@@ -142,40 +112,38 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
   }
 
   /**
-   * 执行
+   * 下载
    */
   protected void progress(long len) {
     synchronized (AriaManager.LOCK) {
       mChildCurrentLocation += len;
       STATE.CURRENT_LOCATION += len;
-      if (System.currentTimeMillis() - mLastSaveTime > 5000
-          && mChildCurrentLocation < mConfig.END_LOCATION) {
-        mLastSaveTime = System.currentTimeMillis();
-        if (!mConfigThreadPool.isShutdown()) {
-          mConfigThreadPool.execute(mConfigThread);
-        }
-      }
     }
   }
 
   /**
-   * 取消任务
+   * 取消下载
    */
   public void cancel() {
     synchronized (AriaManager.LOCK) {
       if (mConfig.SUPPORT_BP) {
         STATE.CANCEL_NUM++;
-        ALog.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消");
+        Log.d(TAG,
+            "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消下载");
         if (STATE.isCancel()) {
+          File configFile = new File(mConfigFPath);
+          if (configFile.exists()) {
+            configFile.delete();
+          }
           if (mConfig.TEMP_FILE.exists() && !(mEntity instanceof UploadEntity)) {
             mConfig.TEMP_FILE.delete();
           }
-          ALog.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消");
+          Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消");
           STATE.isRunning = false;
           mListener.onCancel();
         }
       } else {
-        ALog.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消");
+        Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消");
         STATE.isRunning = false;
         mListener.onCancel();
       }
@@ -185,21 +153,26 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
   /**
    * 任务失败
    */
-  protected void fail(final long currentLocation, String msg, Exception ex) {
+  protected void fail(long currentLocation, String msg, Exception ex) {
     synchronized (AriaManager.LOCK) {
       try {
+        STATE.FAIL_NUM++;
+        STATE.isRunning = false;
+        STATE.isStop = true;
         if (ex != null) {
-          ALog.e(TAG, msg + "\n" + ALog.getExceptionString(ex));
+          Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
         } else {
-          ALog.e(TAG, msg);
+          Log.e(TAG, msg);
         }
         if (mConfig.SUPPORT_BP) {
           writeConfig(false, currentLocation);
-          retryThis(STATE.START_THREAD_NUM != 1);
+          if (STATE.isFail()) {
+            Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
+            mListener.onFail();
+          }
         } else {
-          ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
-          mListener.onFail(true);
-          ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
+          Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
+          mListener.onFail();
         }
       } catch (IOException e) {
         e.printStackTrace();
@@ -208,58 +181,24 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
   }
 
   /**
-   * 重试当前线程,如果其中一条线程已经下载失败,则任务该任务下载失败,并且停止该任务的所有线程
-   *
-   * @param needRetry 是否可以重试
-   */
-  private void retryThis(boolean needRetry) {
-    if (mFailTimer != null) {
-      mFailTimer.purge();
-      mFailTimer.cancel();
-    }
-    if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) {
-      ALog.w(TAG,
-          "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__重试失败,网络未连接");
-    }
-    if (mFailNum < RETRY_NUM
-        && needRetry
-        && NetUtils.isConnected(AriaManager.APP)
-        && !isNotNetRetry
-        && !STATE.isCancel
-        && !STATE.isStop) {
-      mFailTimer = new Timer(true);
-      mFailTimer.schedule(new TimerTask() {
-        @Override public void run() {
-          mFailNum++;
-          ALog.w(TAG,
-              "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__正在重试");
-          final long retryLocation =
-              mChildCurrentLocation == 0 ? mConfig.START_LOCATION : mChildCurrentLocation;
-          mConfig.START_LOCATION = retryLocation;
-          AbsThreadTask.this.run();
-        }
-      }, RETRY_INTERVAL);
-    } else {
-      STATE.FAIL_NUM++;
-      if (STATE.isFail()) {
-        STATE.isRunning = false;
-        STATE.isStop = true;
-        ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
-        mListener.onFail(true);
-      }
-    }
-  }
-
-  /**
    * 将记录写入到配置文件
    */
-  protected void writeConfig(boolean isComplete, final long record) throws IOException {
-    if (mConfig.THREAD_RECORD != null) {
-      mConfig.THREAD_RECORD.isComplete = isComplete;
+  protected void writeConfig(boolean isComplete, long record) throws IOException {
+    synchronized (AriaManager.LOCK) {
+      String key = null, value = null;
       if (0 < record && record < mConfig.END_LOCATION) {
-        mConfig.THREAD_RECORD.startLocation = record;
+        key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID;
+        value = String.valueOf(record);
+      } else if (record >= mConfig.END_LOCATION || isComplete) {
+        key = mConfig.TEMP_FILE.getName() + "_state_" + mConfig.THREAD_ID;
+        value = "1";
+      }
+      if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
+        File configFile = new File(mConfigFPath);
+        Properties pro = CommonUtil.loadConfig(configFile);
+        pro.setProperty(key, value);
+        CommonUtil.saveConfig(configFile, pro);
       }
-      mConfig.THREAD_RECORD.update();
     }
   }
 }

+ 0 - 31
Aria/src/main/java/com/arialyy/aria/core/common/CompleteInfo.java

@@ -1,31 +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.common;
-
-/**
- * Created by AriaL on 2018/3/3.
- * 获取文件信息完成后 回调给下载线程的信息
- */
-public class CompleteInfo {
-  /**
-   * 自定义的状态码
-   */
-  public int code;
-
-  public CompleteInfo(int code) {
-    this.code = code;
-  }
-}

+ 9 - 9
Aria/src/main/java/com/arialyy/aria/core/common/IUtil.java

@@ -18,7 +18,7 @@ package com.arialyy.aria.core.common;
 
 /**
  * Created by lyy on 2016/10/31.
- * 任务功能接口
+ * 抽象的下载接口
  */
 public interface IUtil {
 
@@ -28,39 +28,39 @@ public interface IUtil {
   long getFileSize();
 
   /**
-   * 获取当前位置
+   * 获取当前下载位置
    */
   long getCurrentLocation();
 
   /**
-   * 任务是否正在执行
+   * 是否正在下载
    *
-   * @return {@code true} 任务正在执行
+   * @return true, 正在下载
    */
   boolean isRunning();
 
   /**
-   * 取消
+   * 取消下载
    */
   void cancel();
 
   /**
-   * 停止
+   * 停止下载
    */
   void stop();
 
   /**
-   * 开始
+   * 开始下载
    */
   void start();
 
   /**
-   * 从上次断点恢复
+   * 从上次断点恢复下载
    */
   void resume();
 
   /**
-   * 设置最大速度
+   * 设置最大下载速度
    */
   void setMaxSpeed(double maxSpeed);
 }

+ 0 - 32
Aria/src/main/java/com/arialyy/aria/core/common/OnFileInfoCallback.java

@@ -1,32 +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.common;
-
-public interface OnFileInfoCallback {
-  /**
-   * 处理完成
-   *
-   * @param info 一些回调的信息
-   */
-  void onComplete(String url, CompleteInfo info);
-
-  /**
-   * 请求失败
-   *
-   * @param errorMsg 错误信息
-   */
-  void onFail(String url, String errorMsg, boolean needRetry);
-}

+ 7 - 36
Aria/src/main/java/com/arialyy/aria/core/common/ProxyHelper.java

@@ -16,20 +16,18 @@
 package com.arialyy.aria.core.common;
 
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.util.ALog;
-import com.arialyy.aria.util.CommonUtil;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
+import static java.util.Collections.unmodifiableSet;
+
 /**
  * Created by Aria.Lao on 2017/7/10.
  * 代理参数获取
  */
 public class ProxyHelper {
-  public Set<String> downloadCounter, uploadCounter, downloadGroupCounter, downloadGroupSubCounter;
+  public Set<String> downloadCounter, uploadCounter, downloadGroupCounter;
 
   public static volatile ProxyHelper INSTANCE = null;
 
@@ -47,50 +45,23 @@ public class ProxyHelper {
   }
 
   private void init() {
-    List<String> classes = CommonUtil.getClassName(AriaManager.APP, "com.arialyy.aria");
-    for (String className : classes) {
-      if (!className.startsWith("com.arialyy.aria.ProxyClassCounter")){
-        continue;
-      }
-      count(className);
-    }
-  }
-
-  private void count(String className) {
     try {
-      Class clazz = Class.forName(className);
+      Class clazz = Class.forName("com.arialyy.aria.ProxyClassCounter");
       Method download = clazz.getMethod("getDownloadCounter");
       Method downloadGroup = clazz.getMethod("getDownloadGroupCounter");
-      Method downloadGroupSub = clazz.getMethod("getDownloadGroupSubCounter");
       Method upload = clazz.getMethod("getUploadCounter");
       Object object = clazz.newInstance();
       Object dc = download.invoke(object);
       if (dc != null) {
-        if (downloadCounter == null) {
-          downloadCounter = new HashSet<>();
-        }
-        downloadCounter.addAll((Set<String>) dc);
+        downloadCounter = unmodifiableSet((Set<String>) dc);
       }
       Object dgc = downloadGroup.invoke(object);
       if (dgc != null) {
-        if (downloadGroupCounter == null) {
-          downloadGroupCounter = new HashSet<>();
-        }
-        downloadGroupCounter.addAll((Set<String>) dgc);
-      }
-      Object dgsc = downloadGroupSub.invoke(object);
-      if (dgsc != null) {
-        if (downloadGroupSubCounter == null) {
-          downloadGroupSubCounter = new HashSet<>();
-        }
-        downloadGroupSubCounter.addAll((Set<String>) dgsc);
+        downloadGroupCounter = unmodifiableSet((Set<String>) dgc);
       }
       Object uc = upload.invoke(object);
       if (uc != null) {
-        if (uploadCounter == null) {
-          uploadCounter = new HashSet<>();
-        }
-        uploadCounter.addAll((Set<String>) uc);
+        uploadCounter = unmodifiableSet((Set<String>) uc);
       }
     } catch (ClassNotFoundException e) {
       e.printStackTrace();

+ 0 - 45
Aria/src/main/java/com/arialyy/aria/core/common/RecordWrapper.java

@@ -1,45 +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.common;
-
-import com.arialyy.aria.orm.AbsWrapper;
-import com.arialyy.aria.orm.annotation.Many;
-import com.arialyy.aria.orm.annotation.One;
-import com.arialyy.aria.orm.annotation.Wrapper;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Created by laoyuyu on 2018/3/30.
- * 任务记录和线程记录的关系
- */
-@Wrapper
-public class RecordWrapper extends AbsWrapper {
-
-  @One
-  public TaskRecord taskRecord;
-
-  @Many(parentColumn = "filePath", entityColumn = "key")
-  public List<ThreadRecord> threadRecords;
-
-  @Override protected void handleConvert() {
-    if (threadRecords != null && !threadRecords.isEmpty()) {
-      taskRecord.threadRecords = threadRecords;
-    } else {
-      taskRecord.threadRecords = new ArrayList<>();
-    }
-  }
-}

+ 8 - 8
Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java

@@ -23,18 +23,19 @@ public class StateConstance {
   public int CANCEL_NUM = 0;
   public int STOP_NUM = 0;
   public int FAIL_NUM = 0;
+  public int CONNECT_TIME_OUT; //连接超时时间
+  public int READ_TIME_OUT; //流读取的超时时间
   public int COMPLETE_THREAD_NUM = 0;
-  public int START_THREAD_NUM;  //启动的线程数
+  public int THREAD_NUM;
   public long CURRENT_LOCATION = 0;
   public boolean isRunning = false;
   public boolean isCancel = false;
   public boolean isStop = false;
-  public TaskRecord TASK_RECORD;
 
   public StateConstance() {
   }
 
-  public void resetState() {
+  public void cleanState() {
     isCancel = false;
     isStop = false;
     isRunning = true;
@@ -48,28 +49,27 @@ public class StateConstance {
    * 所有子线程是否都已经停止下载
    */
   public boolean isStop() {
-    return STOP_NUM == START_THREAD_NUM;
+    return STOP_NUM == THREAD_NUM;
   }
 
   /**
    * 所有子线程是否都已经下载失败
    */
   public boolean isFail() {
-    return COMPLETE_THREAD_NUM != START_THREAD_NUM
-        && FAIL_NUM + COMPLETE_THREAD_NUM >= START_THREAD_NUM;
+    return FAIL_NUM == THREAD_NUM;
   }
 
   /**
    * 所有子线程是否都已经完成下载
    */
   public boolean isComplete() {
-    return COMPLETE_THREAD_NUM >= START_THREAD_NUM;
+    return COMPLETE_THREAD_NUM == THREAD_NUM;
   }
 
   /**
    * 所有子线程是否都已经取消下载
    */
   public boolean isCancel() {
-    return CANCEL_NUM == START_THREAD_NUM;
+    return CANCEL_NUM == THREAD_NUM;
   }
 }

+ 1 - 1
Aria/src/main/java/com/arialyy/aria/core/common/SubThreadConfig.java

@@ -19,7 +19,7 @@ public class SubThreadConfig<TASK_ENTITY extends AbsTaskEntity> {
   public File TEMP_FILE;
   //服务器地址
   public String URL;
+  public String CONFIG_FILE_PATH;
   public TASK_ENTITY TASK_ENTITY;
   public boolean SUPPORT_BP = true;
-  public ThreadRecord THREAD_RECORD;
 }

+ 0 - 82
Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java

@@ -1,82 +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.common;
-
-import com.arialyy.aria.core.download.DownloadGroupEntity;
-import com.arialyy.aria.orm.ActionPolicy;
-import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.orm.annotation.Foreign;
-import com.arialyy.aria.orm.annotation.Ignore;
-import com.arialyy.aria.orm.annotation.NoNull;
-import com.arialyy.aria.orm.annotation.Primary;
-import java.util.List;
-
-/**
- * Created by laoyuyu on 2018/3/21.
- * 任务上传或下载的任务记录
- */
-public class TaskRecord extends DbEntity {
-
-  @Ignore
-  public List<ThreadRecord> threadRecords;
-
-  /**
-   * 任务线程数
-   */
-  public int threadNum;
-
-  /**
-   * 任务文件路径
-   */
-  @Primary
-  public String filePath;
-
-  /**
-   * 文件长度
-   */
-  public long fileLength;
-
-  /**
-   * 任务文件名
-   */
-  @NoNull
-  public String fileName;
-
-  /**
-   * 是否是任务组的子任务记录
-   * {@code true}是
-   */
-  public boolean isGroupRecord = false;
-
-  /**
-   * 下载任务组名
-   */
-  @Foreign(parent = DownloadGroupEntity.class, column = "groupName", onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
-  public String dGroupName;
-
-  /**
-   * 上传组任务名,暂时没有用
-   */
-  @Ignore
-  @Deprecated
-  public String uGroupName;
-
-  /**
-   * 是否是使用虚拟文件下载的
-   * {@code true}是,{@code false}不是
-   */
-  public boolean isOpenDynamicFile = false;
-}

+ 0 - 50
Aria/src/main/java/com/arialyy/aria/core/common/ThreadRecord.java

@@ -1,50 +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.common;
-
-import com.arialyy.aria.orm.ActionPolicy;
-import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.orm.annotation.Foreign;
-
-/**
- * Created by laoyuyu on 2018/5/8.
- * 任务的线程记录
- */
-public class ThreadRecord extends DbEntity {
-  @Foreign(parent = TaskRecord.class, column = "filePath", onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
-  public String key;
-
-  /**
-   * 开始位置
-   */
-  public long startLocation;
-
-  /**
-   * 结束位置
-   */
-  public long endLocation;
-
-  /**
-   * 线程是否完成
-   * {@code true}完成,{@code false}未完成
-   */
-  public boolean isComplete = false;
-
-  /**
-   * 线程id
-   */
-  public int threadId = -1;
-}

+ 0 - 66
Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java

@@ -1,66 +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.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;
-  private TARGET mTarget;
-
-  public FtpDelegate(TARGET target, TASK_ENTITY taskEntity) {
-    mTarget = target;
-    mTaskEntity = taskEntity;
-    mEntity = mTaskEntity.getEntity();
-  }
-
-  @Override public TARGET charSet(String charSet) {
-    if (TextUtils.isEmpty(charSet)) return mTarget;
-    mTaskEntity.setCharSet(charSet);
-    return mTarget;
-  }
-
-  @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 mTarget;
-    } else if (TextUtils.isEmpty(password)) {
-      ALog.e(TAG, "密码不能为null");
-      return mTarget;
-    }
-    mTaskEntity.getUrlEntity().needLogin = true;
-    mTaskEntity.getUrlEntity().user = userName;
-    mTaskEntity.getUrlEntity().password = password;
-    mTaskEntity.getUrlEntity().account = account;
-    return mTarget;
-  }
-}

+ 0 - 139
Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java

@@ -1,139 +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.delegate;
-
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import com.arialyy.aria.core.common.RequestEnum;
-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;
-  private TARGET mTarget;
-
-  public HttpHeaderDelegate(TARGET target, TASK_ENTITY taskEntity) {
-    mTarget = target;
-    mTaskEntity = taskEntity;
-
-    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 mTarget;
-    } else if (TextUtils.isEmpty(value)) {
-      ALog.w(TAG, "设置header失败,header对应的value不能为null");
-      return mTarget;
-    }
-    if (mTaskEntity.getHeaders().get(key) == null) {
-      mTaskEntity.getHeaders().put(key, value);
-    } else if (!mTaskEntity.getHeaders().get(key).equals(value)) {
-      mTaskEntity.getHeaders().put(key, value);
-    }
-    return mTarget;
-  }
-
-  /**
-   * 给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 mTarget;
-    }
-    /*
-      两个map比较逻辑
-      1、比对key是否相同
-      2、如果key相同,比对value是否相同
-      3、只有当上面两个步骤中key 和 value都相同时才能任务两个map数据一致
-     */
-    boolean mapEquals = false;
-    if (mTaskEntity.getHeaders().size() == headers.size()) {
-      int i = 0;
-      Set<String> keys = mTaskEntity.getHeaders().keySet();
-      for (String key : keys) {
-        if (headers.containsKey(key)) {
-          i++;
-        } else {
-          break;
-        }
-      }
-      if (i == mTaskEntity.getHeaders().size()) {
-        int j = 0;
-        Collection<String> values = mTaskEntity.getHeaders().values();
-        for (String value : values) {
-          if (headers.containsValue(value)) {
-            j++;
-          } else {
-            break;
-          }
-        }
-        if (j == mTaskEntity.getHeaders().size()) {
-          mapEquals = true;
-        }
-      }
-    }
-
-    if (!mapEquals) {
-      mTaskEntity.getHeaders().clear();
-      Set<String> keys = headers.keySet();
-      for (String key : keys) {
-        mTaskEntity.getHeaders().put(key, headers.get(key));
-      }
-    }
-
-    return mTarget;
-  }
-
-  /**
-   * 设置请求类型,POST或GET,默认为在GET
-   * 只试用于HTTP请求
-   *
-   * @param requestEnum {@link RequestEnum}
-   */
-  @Override
-  public TARGET setRequestMode(RequestEnum requestEnum) {
-    mTaskEntity.setRequestEnum(requestEnum);
-    return mTarget;
-  }
-}

+ 0 - 97
Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java

@@ -1,97 +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.download;
-
-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.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();
-    }
-  }
-
-  /**
-   * 获取任务文件大小
-   *
-   * @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();
-}

+ 19 - 47
Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java

@@ -16,48 +16,37 @@
 package com.arialyy.aria.core.download;
 
 import android.os.Handler;
+import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.common.TaskRecord;
 import com.arialyy.aria.core.inf.AbsEntity;
-import com.arialyy.aria.core.inf.AbsGroupEntity;
-import com.arialyy.aria.core.inf.AbsNormalEntity;
 import com.arialyy.aria.core.inf.AbsTask;
-import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IDownloadListener;
 import com.arialyy.aria.core.inf.IEntity;
+import com.arialyy.aria.core.inf.IEventListener;
 import com.arialyy.aria.core.scheduler.ISchedulers;
-import com.arialyy.aria.orm.DbEntity;
 import com.arialyy.aria.util.CommonUtil;
 import java.lang.ref.WeakReference;
 
 /**
  * 下载监听类
  */
-class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>, TASK extends AbsTask<TASK_ENTITY>>
+class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
     implements IDownloadListener {
-  private static final String TAG = "BaseDListener";
-  protected WeakReference<Handler> outHandler;
-  private int RUN_SAVE_INTERVAL = 5 * 1000;  //5s保存一次下载中的进度
+  private WeakReference<Handler> outHandler;
   private long mLastLen = 0;   //上一次发送长度
   private boolean isFirst = true;
   protected ENTITY mEntity;
-  protected TASK_ENTITY mTaskEntity;
   protected TASK mTask;
   private boolean isConvertSpeed = false;
   boolean isWait = false;
-  private long mLastSaveTime;
-  private long mUpdateInterval;
 
   BaseDListener(TASK task, Handler outHandler) {
     this.outHandler = new WeakReference<>(outHandler);
     this.mTask = new WeakReference<>(task).get();
-    this.mEntity = mTask.getTaskEntity().getEntity();
-    this.mTaskEntity = mTask.getTaskEntity();
+    this.mEntity = this.mTask.getEntity();
     final AriaManager manager = AriaManager.getInstance(AriaManager.APP);
     isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
     mLastLen = mEntity.getCurrentProgress();
-    mLastSaveTime = System.currentTimeMillis();
-    mUpdateInterval = manager.getDownloadConfig().getUpdateInterval();
   }
 
   @Override public void onPre() {
@@ -95,11 +84,6 @@ class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
     }
     handleSpeed(speed);
     sendInState2Target(ISchedulers.RUNNING);
-    if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL) {
-      saveData(IEntity.STATE_RUNNING, currentLocation);
-      mLastSaveTime = System.currentTimeMillis();
-    }
-
     mLastLen = currentLocation;
   }
 
@@ -121,25 +105,19 @@ class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
     sendInState2Target(ISchedulers.COMPLETE);
   }
 
-  @Override public void onFail(boolean needRetry) {
+  @Override public void onFail() {
     mEntity.setFailNum(mEntity.getFailNum() + 1);
     saveData(IEntity.STATE_FAIL, mEntity.getCurrentProgress());
     handleSpeed(0);
-    mTask.needRetry = needRetry;
     sendInState2Target(ISchedulers.FAIL);
   }
 
   private void handleSpeed(long speed) {
-    if (mUpdateInterval != 1000) {
-      speed = speed * 1000 / mUpdateInterval;
-    }
     if (isConvertSpeed) {
       mEntity.setConvertSpeed(CommonUtil.formatFileSize(speed < 0 ? 0 : speed) + "/s");
+    } else {
+      mEntity.setSpeed(speed < 0 ? 0 : speed);
     }
-    mEntity.setSpeed(speed < 0 ? 0 : speed);
-
-    mEntity.setPercent((int) (mEntity.getFileSize() <= 0 ? 0
-        : mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()));
   }
 
   /**
@@ -154,27 +132,21 @@ class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
   }
 
   private void saveData(int state, long location) {
-    mTaskEntity.setState(state);
-    mEntity.setState(state);
     mEntity.setComplete(state == IEntity.STATE_COMPLETE);
     if (state == IEntity.STATE_CANCEL) {
-      if (mEntity instanceof AbsNormalEntity) {
-        TaskRecord record =
-            DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey());
-        if (record != null) {
-          CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (AbsNormalEntity) mEntity);
-        }
-      } else if (mEntity instanceof AbsGroupEntity) {
-        CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), ((AbsGroupEntity) mEntity));
-      }
-      //mEntity.deleteData();
-      return;
-    } else if (mEntity.isComplete()) {
+      mEntity.setState(state);
+      mEntity.deleteData();
+    } else if (state == IEntity.STATE_COMPLETE) {
+      mEntity.setState(state);
       mEntity.setCompleteTime(System.currentTimeMillis());
       mEntity.setCurrentProgress(mEntity.getFileSize());
-    } else if (location > 0) {
-      mEntity.setCurrentProgress(location);
+      mEntity.update();
+    } else {
+      mEntity.setState(state);
+      if (location != -1) {
+        mEntity.setCurrentProgress(location);
+      }
+      mEntity.update();
     }
-    mTaskEntity.update();
   }
 }

+ 116 - 79
Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java

@@ -16,44 +16,45 @@
 package com.arialyy.aria.core.download;
 
 import android.text.TextUtils;
-import android.util.Log;
-import com.arialyy.aria.core.manager.SubTaskManager;
-import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
-import com.arialyy.aria.util.ALog;
+import com.arialyy.aria.core.inf.AbsDownloadTarget;
+import com.arialyy.aria.core.inf.AbsTarget;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.orm.DbEntity;
+import com.arialyy.aria.util.CommonUtil;
 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 BaseGroupTarget>
-    extends AbsDownloadTarget<TARGET, DownloadGroupEntity, DownloadGroupTaskEntity> {
+abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends AbsTaskEntity>
+    extends AbsDownloadTarget<TARGET, DownloadGroupEntity, TASK_ENTITY> {
 
-  /**
-   * 组任务名
-   */
+  List<String> mUrls = new ArrayList<>();
   String mGroupName;
   /**
-   * 文件夹临时路径
+   * 子任务文件名
    */
-  String mDirPathTemp;
+  private List<String> mSubTaskFileName = new ArrayList<>();
   /**
-   * 是否需要修改路径
+   * 是否已经设置了文件路径
    */
-  boolean needModifyPath = false;
-
-  private SubTaskManager mSubTaskManager;
+  private boolean isSetDirPathed = false;
 
   /**
-   * 获取子任务管理器
-   *
-   * @return 子任务管理器
+   * 查询任务组实体,如果数据库不存在该实体,则新创建一个新的任务组实体
    */
-  public SubTaskManager getSubTaskManager() {
-    if (mSubTaskManager == null) {
-      mSubTaskManager = new SubTaskManager(mTargetName, mTaskEntity);
+  DownloadGroupEntity getDownloadGroupEntity() {
+    DownloadGroupEntity entity =
+        DbEntity.findFirst(DownloadGroupEntity.class, "groupName=?", mGroupName);
+    if (entity == null) {
+      entity = new DownloadGroupEntity();
+      entity.setGroupName(mGroupName);
+      entity.setUrls(mUrls);
+      entity.insert();
     }
-    return mSubTaskManager;
+    return entity;
   }
 
   /**
@@ -62,24 +63,10 @@ abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
   public TARGET setGroupAlias(String alias) {
     if (TextUtils.isEmpty(alias)) return (TARGET) this;
     mEntity.setAlias(alias);
+    mEntity.update();
     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"
@@ -97,16 +84,32 @@ abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
    *   }
    * </pre>
    *
-   * @param dirPath 任务组保存文件夹路径
+   * @param groupDirPath 任务组保存文件夹路径
    */
-  public TARGET setDirPath(String dirPath) {
-    mDirPathTemp = dirPath;
-    return (TARGET) this;
-  }
+  public TARGET setDownloadDirPath(String groupDirPath) {
+    if (TextUtils.isEmpty(groupDirPath)) {
+      throw new NullPointerException("任务组文件夹保存路径不能为null");
+    }
 
-  @Override public boolean isRunning() {
-    DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey());
-    return task != null && task.isRunning();
+    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();
+    }
+
+    mEntity.setDirPath(groupDirPath);
+    if (!TextUtils.isEmpty(mEntity.getDirPath())) {
+      reChangeDirPath(groupDirPath);
+    } else {
+      mEntity.setSubTasks(createSubTask());
+    }
+    mEntity.update();
+    return (TARGET) this;
   }
 
   /**
@@ -114,52 +117,86 @@ abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
    *
    * @param newDirPath 新的文件夹路径
    */
-  void reChangeDirPath(String newDirPath) {
-    List<DownloadTaskEntity> subTasks = mTaskEntity.getSubTaskEntities();
-    if (subTasks != null && !subTasks.isEmpty()) {
-      for (DownloadTaskEntity dte : subTasks) {
-        DownloadEntity de = dte.getEntity();
-        String oldPath = de.getDownloadPath();
-        String newPath = newDirPath + "/" + de.getFileName();
+  private void reChangeDirPath(String newDirPath) {
+    List<DownloadEntity> subTask = mEntity.getSubTask();
+    if (subTask != null && !subTask.isEmpty()) {
+      for (DownloadEntity entity : subTask) {
+        String oldPath = entity.getDownloadPath();
+        String newPath = newDirPath + "/" + entity.getFileName();
         File file = new File(oldPath);
-        if (file.exists()) {
-          file.renameTo(new File(newPath));
-        }
-        de.setDownloadPath(newPath);
-        dte.setKey(newPath);
-        de.save();
-        dte.save();
+        file.renameTo(new File(newPath));
+        DbEntity.exeSql("UPDATE DownloadEntity SET downloadPath='"
+            + newPath
+            + "' WHERE downloadPath='"
+            + oldPath
+            + "'");
+        DbEntity.exeSql(
+            "UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
       }
+    } else {
+      mEntity.setSubTasks(createSubTask());
     }
   }
 
   /**
-   * 检查并设置文件夹路径
-   *
-   * @return {@code true} 合法
+   * 设置子任务文件名,该方法必须在{@link #setDownloadDirPath(String)}之后调用,否则不生效
    */
-  boolean checkDirPath() {
-    if (TextUtils.isEmpty(mDirPathTemp)) {
-      ALog.e(TAG, "文件夹路径不能为null");
-      return false;
-    } else if (!mDirPathTemp.startsWith("/")) {
-      ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误");
-      return false;
+  public TARGET setSubTaskFileName(List<String> subTaskFileName) {
+    if (subTaskFileName == null || subTaskFileName.isEmpty()) return (TARGET) this;
+    mSubTaskFileName.addAll(subTaskFileName);
+    if (mUrls.size() != subTaskFileName.size()) {
+      throw new IllegalArgumentException("下载链接数必须要和保存路径的数量一致");
     }
-    File file = new File(mDirPathTemp);
-    if (file.isFile()) {
-      ALog.e(TAG, "路径【" + mDirPathTemp + "】是文件,请设置文件夹路径");
-      return false;
+    if (isSetDirPathed) {
+      List<DownloadEntity> entities = mEntity.getSubTask();
+      int i = 0;
+      for (DownloadEntity entity : entities) {
+        String newName = mSubTaskFileName.get(i);
+        updateSubFileName(entity, newName);
+        i++;
+      }
     }
+    return (TARGET) this;
+  }
 
-    if (TextUtils.isEmpty(mEntity.getDirPath()) || !mEntity.getDirPath().equals(mDirPathTemp)) {
-      if (!file.exists()) {
-        file.mkdirs();
+  /**
+   * 更新子任务文件名
+   */
+  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));
       }
-      needModifyPath = true;
-      mEntity.setDirPath(mDirPathTemp);
+      CommonUtil.renameDownloadConfig(oldFile.getName(), newName);
+      DbEntity.exeSql(
+          "UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
+      entity.setDownloadPath(newPath);
+      entity.setFileName(newName);
+      entity.update();
     }
+  }
 
-    return true;
+  /**
+   * 创建子任务
+   */
+  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;
   }
+
 }

+ 0 - 182
Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java

@@ -1,182 +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.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> {
-
-  /**
-   * 资源地址
-   */
-  protected String url;
-
-  /**
-   * 通过地址初始化target
-   */
-  void initTarget(String url, String targetName, boolean refreshInfo) {
-    this.url = url;
-    mTargetName = targetName;
-    mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
-    mEntity = mTaskEntity.getEntity();
-    mTaskEntity.setRefreshInfo(refreshInfo);
-    if (mEntity != null) {
-      mTempFilePath = mEntity.getDownloadPath();
-    }
-  }
-
-  /**
-   * 将任务设置为最高优先级任务,最高优先级任务有以下特点:
-   * 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() {
-    boolean b = getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath();
-    if (b) {
-      mEntity.save();
-      mTaskEntity.save();
-    }
-    return b;
-  }
-
-  /**
-   * 检查并设置普通任务的文件保存路径
-   *
-   * @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();
-      }
-    }
-    mEntity.setFileName(file.getName());
-
-    //设置文件保存路径,如果新文件路径和就文件路径不同,则修改路径
-    if (!filePath.equals(mEntity.getDownloadPath())) {
-      if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", filePath)) {
-        ALog.e(TAG, "下载失败,保存路径【" + filePath + "】已经被其它任务占用,请设置其它保存路径");
-        return false;
-      }
-      File oldFile = new File(mEntity.getDownloadPath());
-      File newFile = new File(filePath);
-      mEntity.setDownloadPath(filePath);
-      mEntity.setFileName(newFile.getName());
-      mTaskEntity.setKey(filePath);
-      if (oldFile.exists()) {
-        oldFile.renameTo(newFile);
-        CommonUtil.modifyTaskRecord(oldFile.getPath(), newFile.getPath());
-      }
-    }
-    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;
-    }
-    return true;
-  }
-}

+ 15 - 16
Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java

@@ -21,9 +21,7 @@ import android.os.Parcelable;
 import android.text.TextUtils;
 import com.arialyy.aria.core.inf.AbsNormalEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.orm.ActionPolicy;
-import com.arialyy.aria.orm.annotation.Foreign;
-import com.arialyy.aria.orm.annotation.Primary;
+import com.arialyy.aria.orm.Primary;
 import com.arialyy.aria.util.CommonUtil;
 
 /**
@@ -31,39 +29,33 @@ import com.arialyy.aria.util.CommonUtil;
  * 下载实体
  */
 public class DownloadEntity extends AbsNormalEntity implements Parcelable {
-  @Primary private String downloadPath; //保存路径
+  @Primary private String downloadPath = ""; //保存路径
 
   /**
    * 所属任务组
    */
-  @Foreign(parent = DownloadGroupEntity.class, column = "groupName",
-      onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
-  private String groupName;
+  private String groupName = "";
 
   /**
-   * 从服务器的返回信息中获取的文件md5信息,如果服务器没有返回,则不会设置该信息
+   * 通过{@link AbsTaskEntity#md5Key}从服务器的返回信息中获取的文件md5信息,如果服务器没有返回,则不会设置该信息
    * 如果你已经设置了该任务的MD5信息,Aria也不会从服务器返回的信息中获取该信息
    */
-  private String md5Code;
+  private String md5Code = "";
 
   /**
-   * 从服务器的返回信息中获取的文件描述信息
+   * 通过{@link AbsTaskEntity#dispositionKey}从服务器的返回信息中获取的文件描述信息
    */
-  private String disposition;
+  private String disposition = "";
 
   /**
    * 从disposition获取到的文件名,如果可以获取到,则会赋值到这个字段
    */
-  private String serverFileName;
+  private String serverFileName = "";
 
   @Override public String getKey() {
     return getUrl();
   }
 
-  @Override public int getTaskType() {
-    return getUrl().startsWith("ftp") ? AbsTaskEntity.D_FTP : AbsTaskEntity.D_HTTP;
-  }
-
   public DownloadEntity() {
   }
 
@@ -99,6 +91,13 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable {
     this.groupName = groupName;
   }
 
+  /**
+   * {@link #getUrl()}
+   */
+  @Deprecated public String getDownloadUrl() {
+    return getUrl();
+  }
+
   public String getDownloadPath() {
     return downloadPath;
   }

+ 38 - 15
Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java

@@ -17,8 +17,9 @@ package com.arialyy.aria.core.download;
 
 import android.os.Parcel;
 import com.arialyy.aria.core.inf.AbsGroupEntity;
-import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.orm.annotation.Ignore;
+import com.arialyy.aria.orm.NormalList;
+import com.arialyy.aria.orm.OneToMany;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -27,27 +28,47 @@ import java.util.List;
  */
 public class DownloadGroupEntity extends AbsGroupEntity {
 
-  @Ignore private List<DownloadEntity> subEntities;
-
+  @OneToMany(table = DownloadEntity.class, key = "groupName") private List<DownloadEntity> subtask =
+      new ArrayList<>();
 
+  /**
+   * 子任务链接组
+   */
+  @NormalList(clazz = String.class) private List<String> urls = new ArrayList<>();
 
   /**
-   * 子任务实体列表
+   * 任务组下载文件的文件夹地址
+   *
+   * @see DownloadGroupTarget#setDownloadDirPath(String)
    */
-  public List<DownloadEntity> getSubEntities() {
-    return subEntities;
+  private String dirPath = "";
+
+  public List<DownloadEntity> getSubTask() {
+    return subtask;
   }
 
-  public void setSubEntities(List<DownloadEntity> subTasks) {
-    this.subEntities = subTasks;
+  public void setSubTasks(List<DownloadEntity> subTasks) {
+    this.subtask = subTasks;
   }
 
-  public void setGroupName(String key) {
-    this.groupName = key;
+  public String getDirPath() {
+    return dirPath;
+  }
+
+  public void setDirPath(String dirPath) {
+    this.dirPath = dirPath;
+  }
+
+  public List<String> getUrls() {
+    return urls;
   }
 
-  @Override public int getTaskType() {
-    return getKey().startsWith("ftp") ? AbsTaskEntity.D_FTP_DIR : AbsTaskEntity.DG_HTTP;
+  public void setUrls(List<String> urls) {
+    this.urls = urls;
+  }
+
+  void setGroupName(String key) {
+    this.groupName = key;
   }
 
   public DownloadGroupEntity() {
@@ -59,12 +80,14 @@ public class DownloadGroupEntity extends AbsGroupEntity {
 
   @Override public void writeToParcel(Parcel dest, int flags) {
     super.writeToParcel(dest, flags);
-    dest.writeTypedList(this.subEntities);
+    dest.writeTypedList(this.subtask);
+    dest.writeString(this.dirPath);
   }
 
   protected DownloadGroupEntity(Parcel in) {
     super(in);
-    this.subEntities = in.createTypedArrayList(DownloadEntity.CREATOR);
+    this.subtask = in.createTypedArrayList(DownloadEntity.CREATOR);
+    this.dirPath = in.readString();
   }
 
   public static final Creator<DownloadGroupEntity> CREATOR = new Creator<DownloadGroupEntity>() {

+ 4 - 34
Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java

@@ -17,27 +17,17 @@ package com.arialyy.aria.core.download;
 
 import android.os.Handler;
 import com.arialyy.aria.core.download.downloader.IDownloadGroupListener;
-import com.arialyy.aria.core.inf.GroupSendParams;
-import com.arialyy.aria.core.scheduler.ISchedulers;
 
 /**
  * Created by Aria.Lao on 2017/7/20.
  * 任务组下载事件
  */
-class DownloadGroupListener
-    extends BaseDListener<DownloadGroupEntity, DownloadGroupTaskEntity, DownloadGroupTask>
+class DownloadGroupListener extends BaseDListener<DownloadGroupEntity, DownloadGroupTask>
     implements IDownloadGroupListener {
   private final String TAG = "DownloadGroupListener";
-  private GroupSendParams<DownloadGroupTask, DownloadEntity> mSeedEntity;
 
   DownloadGroupListener(DownloadGroupTask task, Handler outHandler) {
     super(task, outHandler);
-    mSeedEntity = new GroupSendParams<>();
-    mSeedEntity.groupTask = task;
-  }
-
-  @Override public void onSubPre(DownloadEntity subEntity) {
-    sendInState2Target(ISchedulers.SUB_PRE, subEntity);
   }
 
   @Override public void supportBreakpoint(boolean support, DownloadEntity subEntity) {
@@ -45,48 +35,28 @@ class DownloadGroupListener
   }
 
   @Override public void onSubStart(DownloadEntity subEntity) {
-    sendInState2Target(ISchedulers.SUB_START, subEntity);
+
   }
 
   @Override public void onSubStop(DownloadEntity subEntity) {
     saveCurrentLocation();
-    sendInState2Target(ISchedulers.SUB_STOP, subEntity);
   }
 
   @Override public void onSubComplete(DownloadEntity subEntity) {
     saveCurrentLocation();
-    sendInState2Target(ISchedulers.SUB_COMPLETE, subEntity);
   }
 
   @Override public void onSubFail(DownloadEntity subEntity) {
     saveCurrentLocation();
-    sendInState2Target(ISchedulers.SUB_FAIL, subEntity);
   }
 
-  @Override public void onSubCancel(DownloadEntity subEntity) {
+  @Override public void onSubCancel(DownloadEntity entity) {
     saveCurrentLocation();
-    sendInState2Target(ISchedulers.SUB_CANCEL, subEntity);
-  }
-
-  @Override public void onSubRunning(DownloadEntity subEntity) {
-    sendInState2Target(ISchedulers.SUB_RUNNING, subEntity);
-  }
-
-  /**
-   * 将任务状态发送给下载器
-   *
-   * @param state {@link ISchedulers#START}
-   */
-  private void sendInState2Target(int state, DownloadEntity subEntity) {
-    if (outHandler.get() != null) {
-      mSeedEntity.entity = subEntity;
-      outHandler.get().obtainMessage(state, ISchedulers.IS_SUB_TASK, 0, mSeedEntity).sendToTarget();
-    }
   }
 
   private void saveCurrentLocation() {
     long location = 0;
-    for (DownloadEntity e : mEntity.getSubEntities()) {
+    for (DownloadEntity e : mEntity.getSubTask()) {
       location += e.getCurrentProgress();
     }
     mEntity.setCurrentProgress(location);

+ 21 - 201
Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java

@@ -15,237 +15,57 @@
  */
 package com.arialyy.aria.core.download;
 
-import android.text.TextUtils;
-import com.arialyy.aria.core.manager.TEManager;
-import com.arialyy.aria.util.ALog;
+import com.arialyy.aria.orm.DbEntity;
+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.Set;
 
 /**
  * Created by AriaL on 2017/6/29.
  * 下载任务组
  */
-public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
-  /**
-   * 子任务下载地址,
-   */
-  private List<String> mUrls = new ArrayList<>();
-
-  /**
-   * 子任务文件名
-   */
-  private List<String> mSubNameTemp = new ArrayList<>();
+public class DownloadGroupTarget
+    extends BaseGroupTarget<DownloadGroupTarget, DownloadGroupTaskEntity> {
+  private final String TAG = "DownloadGroupTarget";
 
   DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
     this.mTargetName = targetName;
     if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) {
       this.mUrls.addAll(groupEntity.getUrls());
     }
-    init();
+    init(groupEntity.getGroupName());
   }
 
   DownloadGroupTarget(List<String> urls, String targetName) {
     this.mTargetName = targetName;
     this.mUrls = urls;
-    init();
-  }
-
-  private void init() {
-    mGroupName = CommonUtil.getMd5Code(mUrls);
-    mTaskEntity = TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, mUrls);
-    mEntity = mTaskEntity.getEntity();
-
-    if (mEntity != null) {
-      mDirPathTemp = mEntity.getDirPath();
-    }
+    init(CommonUtil.getMd5Code(urls));
   }
 
-  /**
-   * 任务组总任务大小,任务组是一个抽象的概念,没有真实的数据实体,任务组的大小是Aria动态获取子任务大小相加而得到的,
-   * 如果你知道当前任务组总大小,你也可以调用该方法给任务组设置大小
-   *
-   * 为了更好的用户体验,建议直接设置任务组文件大小
-   *
-   * @param fileSize 任务组总大小
-   */
-  public DownloadGroupTarget setFileSize(long fileSize) {
-    if (fileSize <= 0) {
-      ALog.e(TAG, "文件大小不能小于 0");
-      return this;
+  private void init(String key) {
+    mGroupName = key;
+    mTaskEntity = DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key);
+    if (mTaskEntity == null) {
+      mTaskEntity = new DownloadGroupTaskEntity();
+      mTaskEntity.key = key;
+      mTaskEntity.entity = getDownloadGroupEntity();
+      mTaskEntity.insert();
     }
-    if (mEntity.getFileSize() <= 1 || mEntity.getFileSize() != fileSize) {
-      mEntity.setFileSize(fileSize);
+    if (mTaskEntity.entity == null) {
+      mTaskEntity.entity = getDownloadGroupEntity();
     }
-    return this;
+    mEntity = mTaskEntity.entity;
   }
 
   /**
    * 如果你是使用{@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;
   }
-
-  /**
-   * 设置子任务文件名,该方法必须在{@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()) {
-      ALog.e(TAG, "修改子任务的文件名失败:列表为null");
-      return this;
-    }
-    if (subTaskFileName.size() != mTaskEntity.getSubTaskEntities().size()) {
-      ALog.e(TAG, "修改子任务的文件名失败:子任务文件名列表数量和子任务的数量不匹配");
-      return this;
-    }
-    mSubNameTemp.clear();
-    mSubNameTemp.addAll(subTaskFileName);
-    return this;
-  }
-
-  @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;
-      }
-
-      mEntity.save();
-      mTaskEntity.save();
-
-      if (needModifyPath) {
-        reChangeDirPath(mDirPathTemp);
-      }
-
-      if (!mSubNameTemp.isEmpty()) {
-        updateSingleSubFileName();
-      }
-      return true;
-    }
-    return false;
-  }
-
-  /**
-   * 更新所有改动的子任务文件名
-   */
-  private void updateSingleSubFileName() {
-    List<DownloadTaskEntity> entities = mTaskEntity.getSubTaskEntities();
-    int i = 0;
-    for (DownloadTaskEntity 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<>();
-
-    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);
-      }
-    }
-
-    mEntity.setGroupName(CommonUtil.getMd5Code(mUrls));
-
-    return true;
-  }
-
-  /**
-   * 更新单个子任务文件名
-   */
-  private void updateSingleSubFileName(DownloadTaskEntity taskEntity, String newName) {
-    DownloadEntity entity = taskEntity.getEntity();
-    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.modifyTaskRecord(oldFile.getPath(), newPath);
-      entity.setDownloadPath(newPath);
-      taskEntity.setKey(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;
-  }
 }

+ 18 - 35
Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java

@@ -16,77 +16,64 @@
 package com.arialyy.aria.core.download;
 
 import android.os.Handler;
-import android.os.Looper;
-import android.text.TextUtils;
-import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.downloader.DownloadGroupUtil;
 import com.arialyy.aria.core.download.downloader.FtpDirDownloadUtil;
+import com.arialyy.aria.core.common.IUtil;
 import com.arialyy.aria.core.inf.AbsGroupTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.scheduler.ISchedulers;
-import com.arialyy.aria.util.ALog;
 import com.arialyy.aria.util.CheckUtil;
 
 /**
  * Created by AriaL on 2017/6/27.
  * 任务组任务
  */
-public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
+public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity, DownloadGroupEntity> {
   private final String TAG = "DownloadGroupTask";
   private DownloadGroupListener mListener;
+  private IUtil mUtil;
 
   private DownloadGroupTask(DownloadGroupTaskEntity taskEntity, Handler outHandler) {
     mTaskEntity = taskEntity;
+    mEntity = taskEntity.getEntity();
     mOutHandler = outHandler;
     mContext = AriaManager.APP;
     mListener = new DownloadGroupListener(this, mOutHandler);
-    switch (taskEntity.getRequestType()) {
-      case AbsTaskEntity.D_HTTP:
+    switch (taskEntity.requestType) {
+      case AbsTaskEntity.HTTP:
         mUtil = new DownloadGroupUtil(mListener, mTaskEntity);
         break;
-      case AbsTaskEntity.D_FTP_DIR:
+      case  AbsTaskEntity.FTP_DIR:
         mUtil = new FtpDirDownloadUtil(mListener, mTaskEntity);
         break;
     }
-    Log.d(TAG, "FTP_TASK_MD5:" + mTaskEntity.hashCode());
   }
 
   @Override public boolean isRunning() {
     return mUtil.isRunning();
   }
 
-  public DownloadGroupEntity getEntity() {
-    return mTaskEntity.getEntity();
-  }
-
   @Override public void start() {
-    if (mUtil.isRunning()) {
-      ALog.d(TAG, "任务正在下载");
-    } else {
-      mUtil.start();
-    }
+    mUtil.start();
   }
 
   @Override public void stop() {
     if (!mUtil.isRunning()) {
-      mListener.onStop(getCurrentProgress());
-    } else {
-      mUtil.stop();
+      if (mOutHandler != null) {
+        mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget();
+      }
     }
+    mUtil.stop();
   }
 
   @Override public void cancel() {
     if (!mUtil.isRunning()) {
-      mListener.onCancel();
-    } else {
-      mUtil.cancel();
+      if (mOutHandler != null) {
+        mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget();
+      }
     }
-  }
-
-  @Override public String getTaskName() {
-    return "任务组->" + (TextUtils.isEmpty(mTaskEntity.getEntity().getAlias())
-        ? mTaskEntity.getEntity().getGroupName() : mTaskEntity.getEntity().getAlias());
+    mUtil.cancel();
   }
 
   public static class Builder {
@@ -106,18 +93,14 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
      * @param schedulers {@link ISchedulers}
      */
     public DownloadGroupTask.Builder setOutHandler(ISchedulers schedulers) {
-      try {
-        outHandler = new Handler(schedulers);
-      } catch (Exception e) {
-        e.printStackTrace();
-        outHandler = new Handler(Looper.getMainLooper(), schedulers);
-      }
+      this.outHandler = new Handler(schedulers);
       return this;
     }
 
     public DownloadGroupTask build() {
       DownloadGroupTask task = new DownloadGroupTask(taskEntity, outHandler);
       task.setTargetName(targetName);
+      taskEntity.save();
       return task;
     }
   }

+ 4 - 36
Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java

@@ -15,49 +15,17 @@
  */
 package com.arialyy.aria.core.download;
 
-import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
-import com.arialyy.aria.orm.ActionPolicy;
-import com.arialyy.aria.orm.annotation.Foreign;
-import com.arialyy.aria.orm.annotation.Ignore;
-import com.arialyy.aria.orm.annotation.Primary;
-import java.util.List;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.orm.OneToOne;
 
 /**
  * Created by AriaL on 2017/7/1.
- * 任务组的任务实体
  */
-public class DownloadGroupTaskEntity extends AbsGroupTaskEntity<DownloadGroupEntity> {
+public class DownloadGroupTaskEntity extends AbsTaskEntity<DownloadGroupEntity> {
 
-  @Ignore private DownloadGroupEntity entity;
-
-  @Ignore private List<DownloadTaskEntity> subTaskEntities;
-
-  @Primary
-  @Foreign(parent = DownloadGroupEntity.class, column = "groupName",
-      onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
-  private String key;
+  @OneToOne(table = DownloadGroupEntity.class, key = "groupName") public DownloadGroupEntity entity;
 
   @Override public DownloadGroupEntity getEntity() {
     return entity;
   }
-
-  public void setEntity(DownloadGroupEntity entity) {
-    this.entity = entity;
-  }
-
-  public List<DownloadTaskEntity> getSubTaskEntities() {
-    return subTaskEntities;
-  }
-
-  public void setSubTaskEntities(List<DownloadTaskEntity> subTaskEntities) {
-    this.subTaskEntities = subTaskEntities;
-  }
-
-  @Override public String getKey() {
-    return key;
-  }
-
-  public void setKey(String key) {
-    this.key = key;
-  }
 }

+ 1 - 1
Aria/src/main/java/com/arialyy/aria/core/download/DownloadListener.java

@@ -22,7 +22,7 @@ import com.arialyy.aria.core.inf.IDownloadListener;
  * Created by Aria.Lao on 2017/7/20.
  * 普通任务下载的事件监听器
  */
-class DownloadListener extends BaseDListener<DownloadEntity, DownloadTaskEntity, DownloadTask>
+class DownloadListener extends BaseDListener<DownloadEntity, DownloadTask>
     implements IDownloadListener {
   DownloadListener(DownloadTask task, Handler outHandler) {
     super(task, outHandler);

+ 67 - 217
Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java

@@ -16,21 +16,16 @@
 package com.arialyy.aria.core.download;
 
 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.download.wrapper.DGEWrapper;
 import com.arialyy.aria.core.inf.AbsEntity;
 import com.arialyy.aria.core.inf.AbsReceiver;
-import com.arialyy.aria.core.inf.AbsTarget;
-import com.arialyy.aria.core.manager.TEManager;
+import com.arialyy.aria.core.inf.IReceiver;
+import com.arialyy.aria.core.command.normal.NormalCmdFactory;
 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.core.common.ProxyHelper;
 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;
@@ -43,6 +38,7 @@ import java.util.Set;
  */
 public class DownloadReceiver extends AbsReceiver {
   private final String TAG = "DownloadReceiver";
+  public ISchedulerListener<DownloadTask> listener;
 
   /**
    * 设置最大下载速度,单位:kb
@@ -50,147 +46,39 @@ public class DownloadReceiver extends AbsReceiver {
    *
    * @param maxSpeed 为0表示不限速
    */
-  @Deprecated public void setMaxSpeed(int maxSpeed) {
-    AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMaxSpeed(maxSpeed);
+  @Deprecated public void setMaxSpeed(double maxSpeed) {
+    AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMsxSpeed(maxSpeed);
   }
 
   /**
    * 使用下载实体执行下载操作
-   *
-   * @param entity 下载实体
    */
   public DownloadTarget load(DownloadEntity entity) {
-    return load(entity, false);
-  }
-
-  /**
-   * 使用下载实体执行下载操作
-   *
-   * @param refreshInfo 是否刷新下载信息
-   * @deprecated 请使用 {@link AbsTarget#resetState()}
-   * <pre>
-   *   <code>
-   *   Aria.download(this)
-   *       .load(URL)
-   *       .setDownloadPath(PATH)
-   *       .resetState()
-   *       .start();
-   *   </code>
-   * </pre>
-   */
-  @Deprecated public DownloadTarget load(DownloadEntity entity, boolean refreshInfo) {
-    CheckUtil.checkDownloadEntity(entity);
-    return new DownloadTarget(entity, targetName, refreshInfo);
+    return new DownloadTarget(entity, targetName);
   }
 
   /**
    * 加载Http、https单任务下载地址
-   *
-   * @param url 下载地址
    */
   public DownloadTarget load(@NonNull String url) {
-    return load(url, false);
-  }
-
-  /**
-   * 加载Http、https单任务下载地址
-   *
-   * @param url 下载地址
-   * @param refreshInfo 是否刷新下载信息,当下载地址改变而保存路径不变,则需要设置该参数为{@code true}
-   * @deprecated 请使用 {@link AbsTarget#resetState()}
-   * <pre>
-   *   <code>
-   *   Aria.download(this)
-   *       .load(URL)
-   *       .setDownloadPath(PATH)
-   *       .resetState()
-   *       .start();
-   *   </code>
-   * </pre>
-   */
-  @Deprecated public DownloadTarget load(@NonNull String url, boolean refreshInfo) {
-    CheckUtil.checkUrlInvalidThrow(url);
-    return new DownloadTarget(url, targetName, refreshInfo);
+    CheckUtil.checkDownloadUrl(url);
+    return new DownloadTarget(url, targetName);
   }
 
   /**
    * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组
-   *
-   * @param urls 任务组子任务下载地址列表
-   * @deprecated {@link #loadGroup(DownloadGroupEntity)}
    */
-  @Deprecated
   public DownloadGroupTarget load(List<String> urls) {
-    return loadGroup(urls);
-  }
-
-  /**
-   * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组
-   */
-  public DownloadGroupTarget loadGroup(List<String> urls) {
     CheckUtil.checkDownloadUrls(urls);
     return new DownloadGroupTarget(urls, targetName);
   }
 
   /**
-   * 使用下载实体执行FTP下载操作
-   *
-   * @param entity 下载实体
-   */
-  public FtpDownloadTarget loadFtp(DownloadEntity entity) {
-    return loadFtp(entity, false);
-  }
-
-  /**
-   * 使用下载实体执行下载操作
-   *
-   * @param refreshInfo 是否刷新下载信息,当下载地址改变而保存路径不变,则需要设置该参数为{@code true}
-   * @deprecated 请使用 {@link AbsTarget#resetState()}
-   * <pre>
-   *   <code>
-   *   Aria.download(this)
-   *       .load(URL)
-   *       .setDownloadPath(PATH)
-   *       .resetState()
-   *       .start();
-   *   </code>
-   * </pre>
-   */
-  @Deprecated public FtpDownloadTarget loadFtp(DownloadEntity entity, boolean refreshInfo) {
-    CheckUtil.checkDownloadEntity(entity);
-    if (!entity.getUrl().startsWith("ftp")) {
-      throw new IllegalArgumentException("非FTP请求不能使用该方法");
-    }
-    return new FtpDownloadTarget(entity, targetName, refreshInfo);
-  }
-
-  /**
    * 加载ftp单任务下载地址
    */
   public FtpDownloadTarget loadFtp(@NonNull String url) {
-    return loadFtp(url, false);
-  }
-
-  /**
-   * 加载ftp单任务下载地址
-   *
-   * @param refreshInfo 是否刷新下载信息
-   */
-  public FtpDownloadTarget loadFtp(@NonNull String url, boolean refreshInfo) {
-    CheckUtil.checkUrlInvalidThrow(url);
-    return new FtpDownloadTarget(url, targetName, refreshInfo);
-  }
-
-  /**
-   * 使用任务组实体执行任务组的实体执行任务组的下载操作,后续版本会删除该api
-   *
-   * @param groupEntity 如果加载的任务实体没有子项的下载地址,
-   * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
-   * @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)}
-   */
-  @Deprecated
-  public DownloadGroupTarget load(DownloadGroupEntity groupEntity) {
-    return loadGroup(groupEntity);
+    CheckUtil.checkDownloadUrl(url);
+    return new FtpDownloadTarget(url, targetName);
   }
 
   /**
@@ -199,7 +87,7 @@ public class DownloadReceiver extends AbsReceiver {
    * @param groupEntity 如果加载的任务实体没有子项的下载地址,
    * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
    */
-  public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) {
+  public DownloadGroupTarget load(DownloadGroupEntity groupEntity) {
     return new DownloadGroupTarget(groupEntity, targetName);
   }
 
@@ -207,7 +95,7 @@ public class DownloadReceiver extends AbsReceiver {
    * 加载ftp文件夹下载地址
    */
   public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) {
-    CheckUtil.checkUrlInvalidThrow(dirUrl);
+    CheckUtil.checkDownloadUrl(dirUrl);
     return new FtpDirDownloadTarget(dirUrl, targetName);
   }
 
@@ -218,98 +106,92 @@ public class DownloadReceiver extends AbsReceiver {
     String className = obj.getClass().getName();
     Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
     Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
-    Set<String> dgsCounter = ProxyHelper.getInstance().downloadGroupSubCounter;
     if (dCounter != null && dCounter.contains(className)) {
       DownloadSchedulers.getInstance().register(obj);
     }
-    if ((dgCounter != null && dgCounter.contains(className)) || (dgsCounter != null
-        && dgsCounter.contains(className))) {
+    if (dgCounter != null && dgCounter.contains(className)) {
       DownloadGroupSchedulers.getInstance().register(obj);
     }
     return this;
   }
 
   /**
-   * 取消注册,如果是Activity或fragment,Aria会界面销毁时自动调用该方法。
-   * 如果在activity中一定要调用该方法,那么请在onDestroy()中调用
-   * 如果是Dialog或popupwindow,需要你在撤销界面时调用该方法
+   * 取消注册
    */
   @Override public void unRegister() {
-    if (needRmListener) {
-      unRegisterListener();
-    }
-    AriaManager.getInstance(AriaManager.APP).removeReceiver(obj);
-  }
-
-  @Override public void unRegisterListener() {
     String className = obj.getClass().getName();
     Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
     Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
-    Set<String> dgsCounter = ProxyHelper.getInstance().downloadGroupSubCounter;
     if (dCounter != null && dCounter.contains(className)) {
       DownloadSchedulers.getInstance().unRegister(obj);
     }
-    if (dgCounter != null && dgCounter.contains(className) || (dgsCounter != null
-        && dgsCounter.contains(className))) {
+    if (dgCounter != null && dgCounter.contains(className)) {
       DownloadGroupSchedulers.getInstance().unRegister(obj);
     }
   }
 
+  /**
+   * 添加调度器回调
+   *
+   * @see #register()
+   */
+  @Deprecated public DownloadReceiver addSchedulerListener(
+      ISchedulerListener<DownloadTask> listener) {
+    this.listener = listener;
+    DownloadSchedulers.getInstance().addSchedulerListener(targetName, listener);
+    return this;
+  }
+
+  /**
+   * 移除回调
+   *
+   * @see #unRegister()
+   */
+  @Deprecated @Override public void removeSchedulerListener() {
+    if (listener != null) {
+      DownloadSchedulers.getInstance().removeSchedulerListener(targetName, listener);
+    }
+  }
+
   @Override public void destroy() {
     targetName = null;
+    listener = null;
   }
 
   /**
    * 通过下载链接获取下载实体
-   *
-   * @return 如果url错误或查找不到数据,则返回null
    */
   public DownloadEntity getDownloadEntity(String downloadUrl) {
-    if (CheckUtil.checkUrl(downloadUrl)) {
-      return null;
-    }
-    return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
+    CheckUtil.checkDownloadUrl(downloadUrl);
+    return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'",
+        downloadUrl);
   }
 
   /**
-   * 通过下载地址和文件保存路径获取下载任务实体
-   *
-   * @param downloadUrl 下载地址
-   * @return 如果url错误或查找不到数据,则返回null
+   * 通过下载链接获取保存在数据库的下载任务实体
    */
   public DownloadTaskEntity getDownloadTask(String downloadUrl) {
-    if (CheckUtil.checkUrl(downloadUrl)) {
-      return null;
-    }
-    return TEManager.getInstance().getTEntity(DownloadTaskEntity.class, downloadUrl);
+    CheckUtil.checkDownloadUrl(downloadUrl);
+    return DbEntity.findFirst(DownloadTaskEntity.class, "groupName=? and isGroupTask='false'",
+        downloadUrl);
   }
 
   /**
    * 通过下载链接获取保存在数据库的下载任务组实体
-   *
-   * @param urls 任务组子任务下载地址列表
-   * @return 返回对应的任务组实体;如果查找不到对应的数据或子任务列表为null,返回null
    */
-  public DownloadGroupTaskEntity getGroupTask(List<String> urls) {
-    if (urls == null || urls.isEmpty()) {
-      ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null");
-      return null;
-    }
-    return TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, urls);
+  public DownloadGroupTaskEntity getDownloadGroupTask(List<String> urls) {
+    CheckUtil.checkDownloadUrls(urls);
+    String hashCode = CommonUtil.getMd5Code(urls);
+    return DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", hashCode);
   }
 
   /**
-   * 获取FTP文件夹下载任务实体
-   *
-   * @param dirUrl FTP文件夹本地下载路径
-   * @return 返回对应的任务组实体;如果查找不到对应的数据或路径为null,返回null
+   * 通过任务组key,获取任务组实体
+   * 如果是http,key为所有子任务下载地址拼接后取md5
+   * 如果是ftp,key为ftp服务器的文件夹路径
    */
-  public DownloadGroupTaskEntity getFtpDirTask(String dirUrl) {
-    if (TextUtils.isEmpty(dirUrl)) {
-      ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null");
-      return null;
-    }
-    return TEManager.getInstance().getFDTEntity(DownloadGroupTaskEntity.class, dirUrl);
+  public DownloadGroupTaskEntity getDownloadGroupTask(String key) {
+    return DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key);
   }
 
   /**
@@ -320,54 +202,26 @@ public class DownloadReceiver extends AbsReceiver {
   }
 
   /**
-   * 获取所有普通下载任务
-   * 获取未完成的普通任务列表{@link #getAllNotCompletTask()}
-   * 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
+   * 获取普通下载任务列表
    */
-  @Override public List<DownloadEntity> getTaskList() {
+  @Override public List<DownloadEntity> getSimpleTaskList() {
     return DownloadEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''",
         "false");
   }
 
   /**
-   * 获取所有未完成的普通下载任务
-   */
-  public List<DownloadEntity> getAllNotCompletTask() {
-    return DownloadEntity.findDatas(DownloadEntity.class,
-        "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
-  }
-
-  /**
-   * 获取所有已经完成的普通任务
-   */
-  public List<DownloadEntity> getAllCompleteTask() {
-    return DownloadEntity.findDatas(DownloadEntity.class,
-        "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
-  }
-
-  /**
    * 获取任务组列表
-   *
-   * @return 如果没有任务组列表,则返回null
    */
   public List<DownloadGroupEntity> getGroupTaskList() {
-    List<DGEWrapper> wrappers = DbEntity.findRelationData(DGEWrapper.class);
-    if (wrappers == null || wrappers.isEmpty()) {
-      return null;
-    }
-    List<DownloadGroupEntity> entities = new ArrayList<>();
-    for (DGEWrapper wrapper : wrappers) {
-      entities.add(wrapper.groupEntity);
-    }
-    return entities;
+    return DownloadEntity.findAllData(DownloadGroupEntity.class);
   }
 
   /**
    * 获取普通任务和任务组的任务列表
    */
-  public List<AbsEntity> getTotalTaskList() {
+  public List<AbsEntity> getTotleTaskList() {
     List<AbsEntity> list = new ArrayList<>();
-    List<DownloadEntity> simpleTask = getTaskList();
+    List<DownloadEntity> simpleTask = getSimpleTaskList();
     List<DownloadGroupEntity> groupTask = getGroupTaskList();
     if (simpleTask != null && !simpleTask.isEmpty()) {
       list.addAll(simpleTask);
@@ -384,8 +238,7 @@ public class DownloadReceiver extends AbsReceiver {
   @Override public void stopAllTask() {
     AriaManager.getInstance(AriaManager.APP)
         .setCmd(NormalCmdFactory.getInstance()
-            .createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL,
-                ICmd.TASK_TYPE_DOWNLOAD))
+            .createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL))
         .exe();
   }
 
@@ -397,8 +250,7 @@ public class DownloadReceiver extends AbsReceiver {
   public void resumeAllTask() {
     AriaManager.getInstance(AriaManager.APP)
         .setCmd(NormalCmdFactory.getInstance()
-            .createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_RESUME_ALL,
-                ICmd.TASK_TYPE_DOWNLOAD))
+            .createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_RESUME_ALL))
         .exe();
   }
 
@@ -410,11 +262,9 @@ public class DownloadReceiver extends AbsReceiver {
    */
   @Override public void removeAllTask(boolean removeFile) {
     final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
-    CancelAllCmd cancelCmd =
-        (CancelAllCmd) CommonUtil.createNormalCmd(targetName, new DownloadTaskEntity(),
-            NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_DOWNLOAD);
-    cancelCmd.removeFile = removeFile;
-    ariaManager.setCmd(cancelCmd).exe();
+    ariaManager.setCmd(CommonUtil.createCmd(targetName, new DownloadTaskEntity(),
+        NormalCmdFactory.TASK_CANCEL_ALL)).exe();
+
     Set<String> keys = ariaManager.getReceiver().keySet();
     for (String key : keys) {
       ariaManager.getReceiver().remove(key);

+ 94 - 46
Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java

@@ -16,56 +16,90 @@
 package com.arialyy.aria.core.download;
 
 import android.support.annotation.NonNull;
-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;
+import android.text.TextUtils;
+import com.arialyy.aria.core.inf.AbsDownloadTarget;
+import com.arialyy.aria.core.inf.IEntity;
+import com.arialyy.aria.core.queue.DownloadTaskQueue;
+import com.arialyy.aria.orm.DbEntity;
+import com.arialyy.aria.util.CommonUtil;
+import java.io.File;
 
 /**
  * Created by lyy on 2016/12/5.
  * https://github.com/AriaLyy/Aria
  */
-public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
-    implements IHttpHeaderTarget<DownloadTarget> {
-  private HttpHeaderDelegate<DownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
+public class DownloadTarget
+    extends AbsDownloadTarget<DownloadTarget, DownloadEntity, DownloadTaskEntity> {
+  protected String url;
 
   DownloadTarget(DownloadEntity entity, String targetName) {
-    this(entity, targetName, false);
-  }
-
-  DownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
-    this(entity.getUrl(), targetName, refreshInfo);
+    this.url = entity.getUrl();
+    mTargetName = targetName;
+    initTask(entity);
   }
 
   DownloadTarget(String url, String targetName) {
-    this(url, targetName, false);
+    this.url = url;
+    mTargetName = targetName;
+    DownloadEntity entity = getEntity(url);
+    initTask(entity);
   }
 
-  DownloadTarget(String url, String targetName, boolean refreshInfo) {
-    initTarget(url, targetName, refreshInfo);
-    mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity);
+  private void initTask(DownloadEntity entity) {
+    mTaskEntity = DbEntity.findFirst(DownloadTaskEntity.class, "key=? and isGroupTask='false'",
+        entity.getDownloadPath());
+    if (mTaskEntity == null) {
+      mTaskEntity = new DownloadTaskEntity();
+      mTaskEntity.key = entity.getDownloadPath();
+      mTaskEntity.entity = entity;
+      mTaskEntity.save();
+    }
+    if (mTaskEntity.entity == null) {
+      mTaskEntity.entity = entity;
+    }
+    mEntity = mTaskEntity.entity;
   }
 
   /**
-   * 是否使用服务器通过content-disposition传递的文件名,内容格式{@code attachment;filename=***}
-   * 如果获取不到服务器文件名,则使用用户设置的文件名
+   * 如果任务存在,但是下载实体不存在,则通过下载地址获取下载实体
    *
-   * @param use {@code true} 使用
+   * @param downloadUrl 下载地址
    */
-  public DownloadTarget useServerFileName(boolean use) {
-    mTaskEntity.setUseServerFileName(use);
-    return this;
+  private DownloadEntity getEntity(String downloadUrl) {
+    DownloadEntity entity =
+        DownloadEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'",
+            downloadUrl);
+    if (entity == null) {
+      entity = new DownloadEntity();
+      entity.setUrl(downloadUrl);
+      entity.setGroupChild(false);
+      entity.save();
+    }
+    File file = new File(entity.getDownloadPath());
+    if (!file.exists()) {
+      entity.setState(IEntity.STATE_WAIT);
+    }
+    return entity;
   }
 
   /**
-   * 设置文件存储路径
-   * 该api后续版本会删除
-   *
-   * @param downloadPath 文件保存路径
-   * @deprecated {@link #setFilePath(String)} 请使用这个api
+   * 将任务设置为最高优先级任务,最高优先级任务有以下特点:
+   * 1、在下载队列中,有且只有一个最高优先级任务
+   * 2、最高优先级任务会一直存在,直到用户手动暂停或任务完成
+   * 3、任务调度器不会暂停最高优先级任务
+   * 4、用户手动暂停或任务完成后,第二次重新执行该任务,该命令将失效
+   * 5、如果下载队列中已经满了,则会停止队尾的任务,当高优先级任务完成后,该队尾任务将自动执行
+   * 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务
    */
-  @Deprecated public DownloadTarget setDownloadPath(@NonNull String downloadPath) {
-    return setFilePath(downloadPath);
+  @Override public void setHighestPriority() {
+    super.setHighestPriority();
+  }
+
+  /**
+   * 下载任务是否存在
+   */
+  @Override public boolean taskExists() {
+    return DownloadTaskQueue.getInstance().getTask(mEntity.getUrl()) != null;
   }
 
   /**
@@ -73,13 +107,35 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
    * 如:原文件路径 /mnt/sdcard/test.zip
    * 如果需要将test.zip改为game.zip,只需要重新设置文件路径为:/mnt/sdcard/game.zip
    *
-   * @param filePath 路径必须为文件路径,不能为文件夹路径
+   * @param downloadPath 路径必须为文件路径,不能为文件夹路径
    */
-  public DownloadTarget setFilePath(@NonNull String filePath) {
-    mTempFilePath = filePath;
+  public DownloadTarget setDownloadPath(@NonNull String downloadPath) {
+    if (TextUtils.isEmpty(downloadPath)) {
+      throw new IllegalArgumentException("文件保持路径不能为null");
+    }
+    File file = new File(downloadPath);
+    if (file.isDirectory()) {
+      throw new IllegalArgumentException("文件不能为文件夹");
+    }
+    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());
+      }
+    }
     return this;
   }
 
+  public DownloadEntity getDownloadEntity() {
+    return mEntity;
+  }
+
   /**
    * 从header中获取文件描述信息
    */
@@ -87,19 +143,11 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
     return mEntity.getDisposition();
   }
 
-  @Override protected int getTargetType() {
-    return HTTP;
-  }
-
-  @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);
-  }
-
-  @Override public DownloadTarget setRequestMode(RequestEnum requestEnum) {
-    return mDelegate.setRequestMode(requestEnum);
+  /**
+   * 是否在下载
+   */
+  public boolean isDownloading() {
+    DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity);
+    return task != null && task.isRunning();
   }
 }

+ 24 - 29
Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java

@@ -17,33 +17,31 @@
 package com.arialyy.aria.core.download;
 
 import android.os.Handler;
-import android.os.Looper;
+import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.common.IUtil;
 import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil;
 import com.arialyy.aria.core.inf.AbsNormalTask;
+import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.scheduler.ISchedulers;
-import com.arialyy.aria.util.ALog;
 import java.io.File;
 
 /**
  * Created by lyy on 2016/8/11.
  * 下载任务类
  */
-public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
+public class DownloadTask extends AbsNormalTask<DownloadEntity> {
   public static final String TAG = "DownloadTask";
 
   private DownloadListener mListener;
-  private DownloadEntity mEntity;
   private IUtil mUtil;
 
   private DownloadTask(DownloadTaskEntity taskEntity, Handler outHandler) {
-    mTaskEntity = taskEntity;
+    mEntity = taskEntity.getEntity();
     mOutHandler = outHandler;
     mContext = AriaManager.APP;
     mListener = new DownloadListener(this, mOutHandler);
     mUtil = new SimpleDownloadUtil(taskEntity, mListener);
-    mEntity = taskEntity.getEntity();
   }
 
   /**
@@ -59,10 +57,6 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
     return mEntity.getDownloadPath();
   }
 
-  public DownloadEntity getEntity() {
-    return mTaskEntity.getEntity();
-  }
-
   /**
    * 获取当前下载任务的下载地址
    *
@@ -77,14 +71,18 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
   }
 
   /**
-   * 是否真正下载
+   * 任务下载状态
    *
-   * @return {@code true} 真正下载
+   * @see DownloadTask#isRunning()
    */
-  @Override public boolean isRunning() {
+  @Deprecated public boolean isDownloading() {
     return mUtil.isRunning();
   }
 
+  @Override public boolean isRunning() {
+    return isDownloading();
+  }
+
   public DownloadEntity getDownloadEntity() {
     return mEntity;
   }
@@ -111,7 +109,7 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
   @Override public void start() {
     mListener.isWait = false;
     if (mUtil.isRunning()) {
-      ALog.d(TAG, "任务正在下载");
+      Log.d(TAG, "任务正在下载");
     } else {
       mUtil.start();
     }
@@ -129,7 +127,11 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
     if (mUtil.isRunning()) {
       mUtil.stop();
     } else {
-      mListener.onStop(mEntity.getCurrentProgress());
+      mEntity.setState(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
+      mEntity.update();
+      if (mOutHandler != null) {
+        mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget();
+      }
     }
   }
 
@@ -137,15 +139,12 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
    * 取消下载
    */
   @Override public void cancel() {
-    if (mUtil.isRunning()) {
-      mUtil.cancel();
-    } else {
-      mListener.onCancel();
+    if (!mUtil.isRunning()) {
+      if (mOutHandler != null) {
+        mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget();
+      }
     }
-  }
-
-  @Override public String getTaskName() {
-    return mEntity.getFileName();
+    mUtil.cancel();
   }
 
   public static class Builder {
@@ -164,18 +163,14 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
      * @param schedulers {@link ISchedulers}
      */
     public Builder setOutHandler(ISchedulers schedulers) {
-      try {
-        outHandler = new Handler(schedulers);
-      } catch (Exception e) {
-        ALog.w(TAG, ALog.getExceptionString(e));
-        outHandler = new Handler(Looper.getMainLooper(), schedulers);
-      }
+      this.outHandler = new Handler(schedulers);
       return this;
     }
 
     public DownloadTask build() {
       DownloadTask task = new DownloadTask(taskEntity, outHandler);
       task.setTargetName(targetName);
+      taskEntity.getEntity().save();
       taskEntity.save();
       return task;
     }

+ 8 - 79
Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java

@@ -15,52 +15,27 @@
  */
 package com.arialyy.aria.core.download;
 
-import com.arialyy.aria.core.inf.AbsNormalTaskEntity;
-import com.arialyy.aria.orm.ActionPolicy;
-import com.arialyy.aria.orm.annotation.Foreign;
-import com.arialyy.aria.orm.annotation.Ignore;
-import com.arialyy.aria.orm.annotation.NoNull;
-import com.arialyy.aria.orm.annotation.Primary;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.orm.Ignore;
+import com.arialyy.aria.orm.OneToOne;
 
 /**
  * Created by lyy on 2017/1/23.
- * 下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除
+ * 下载任务实体
  */
-public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
+public class DownloadTaskEntity extends AbsTaskEntity<DownloadEntity> {
 
-  @Ignore private DownloadEntity entity;
-
-  /**
-   * 任务的url
-   */
-  @NoNull private String url;
+  @OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity;
 
   /**
    * 所属的任务组组名,如果不属于任务组,则为null
    */
-  @Foreign(parent = DownloadGroupTaskEntity.class, column = "key",
-      onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
-  private String groupName;
-
-  /**
-   * 是否是chunk模式
-   */
-  private boolean isChunked = false;
+  public String groupName = "";
 
   /**
    * 该任务是否属于任务组
    */
-  private boolean isGroupTask = false;
-
-  /**
-   * Task实体对应的key
-   */
-  @Primary
-  @Foreign(parent = DownloadEntity.class, column = "downloadPath",
-      onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
-  private String key;
-
-
+  public boolean isGroupTask = false;
 
   public DownloadTaskEntity() {
   }
@@ -68,50 +43,4 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
   @Override public DownloadEntity getEntity() {
     return entity;
   }
-
-  @Override public String getKey() {
-    return key;
-  }
-
-  @Override public void setKey(String key) {
-    this.key = key;
-  }
-
-  public String getUrl() {
-    return url;
-  }
-
-  public String getGroupName() {
-    return groupName;
-  }
-
-  public boolean isChunked() {
-    return isChunked;
-  }
-
-  public boolean isGroupTask() {
-    return isGroupTask;
-  }
-
-  public void setEntity(DownloadEntity entity) {
-    this.entity = entity;
-  }
-
-  public void setUrl(String url) {
-    this.url = url;
-  }
-
-  public void setGroupName(String groupName) {
-    this.groupName = groupName;
-  }
-
-  public void setChunked(boolean chunked) {
-    isChunked = chunked;
-  }
-
-  public void setGroupTask(boolean groupTask) {
-    isGroupTask = groupTask;
-  }
-
-
 }

+ 58 - 60
Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java

@@ -16,89 +16,87 @@
 package com.arialyy.aria.core.download;
 
 import android.text.TextUtils;
-import com.arialyy.aria.core.delegate.FtpDelegate;
+import android.util.Log;
 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.util.ALog;
+import com.arialyy.aria.orm.DbEntity;
 
 /**
  * Created by Aria.Lao on 2017/7/26.
  * ftp文件夹下载
  */
-public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
-    implements IFtpTarget<FtpDirDownloadTarget> {
-  private FtpDelegate<FtpDirDownloadTarget, DownloadGroupEntity, DownloadGroupTaskEntity> mDelegate;
+public class FtpDirDownloadTarget
+    extends BaseGroupTarget<FtpDirDownloadTarget, DownloadGroupTaskEntity> {
+  private final String TAG = "FtpDirDownloadTarget";
+  private String serverIp, remotePath;
+  private int port;
 
   FtpDirDownloadTarget(String url, String targetName) {
-    mTargetName = targetName;
     init(url);
+    String[] pp = url.split("/")[2].split(":");
+    mTargetName = targetName;
+    serverIp = pp[0];
+    port = Integer.parseInt(pp[1]);
+    mTaskEntity.requestType = AbsTaskEntity.FTP_DIR;
+    mTaskEntity.serverIp = serverIp;
+    mTaskEntity.port = port;
+    remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
+    if (TextUtils.isEmpty(remotePath)) {
+      throw new NullPointerException("ftp服务器地址不能为null");
+    }
   }
 
   private void init(String key) {
     mGroupName = key;
-    mTaskEntity = TEManager.getInstance().getFDTEntity(DownloadGroupTaskEntity.class, key);
-    mTaskEntity.setRequestType(AbsTaskEntity.D_FTP_DIR);
-    mEntity = mTaskEntity.getEntity();
-    if (mEntity != null) {
-      mDirPathTemp = mEntity.getDirPath();
+    mTaskEntity = DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key);
+    if (mTaskEntity == null) {
+      mTaskEntity = new DownloadGroupTaskEntity();
+      mTaskEntity.key = key;
+      mTaskEntity.entity = getDownloadGroupEntity();
+      mTaskEntity.insert();
     }
-    mDelegate = new FtpDelegate<>(this, mTaskEntity);
+    if (mTaskEntity.entity == null) {
+      mTaskEntity.entity = getDownloadGroupEntity();
+    }
+    mEntity = mTaskEntity.entity;
   }
 
-  @Override protected int getTargetType() {
-    return GROUP_FTP_DIR;
+  /**
+   * 设置字符编码
+   */
+  public FtpDirDownloadTarget charSet(String charSet) {
+    if (TextUtils.isEmpty(charSet)) return this;
+    mTaskEntity.charSet = charSet;
+    return this;
   }
 
-  @Override protected boolean checkEntity() {
-    boolean b = getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl();
-    if (b) {
-      mEntity.save();
-      mTaskEntity.save();
-      if (mTaskEntity.getSubTaskEntities() != null) {
-        //初始化子项的登录信息
-        for (DownloadTaskEntity entity : mTaskEntity.getSubTaskEntities()) {
-          entity.getUrlEntity().needLogin = mTaskEntity.getUrlEntity().needLogin;
-          entity.getUrlEntity().account = mTaskEntity.getUrlEntity().account;
-          entity.getUrlEntity().user = mTaskEntity.getUrlEntity().user;
-          entity.getUrlEntity().password = mTaskEntity.getUrlEntity().password;
-        }
-      }
-    }
-    return b;
+  /**
+   * ftp 用户登录信息
+   *
+   * @param userName ftp用户名
+   * @param password ftp用户密码
+   */
+  public FtpDirDownloadTarget login(String userName, String password) {
+    return login(userName, password, null);
   }
 
   /**
-   * 检查普通任务的下载地址
+   * ftp 用户登录信息
    *
-   * @return {@code true}地址合法
+   * @param userName ftp用户名
+   * @param password ftp用户密码
+   * @param account ftp账号
    */
-  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;
-    }
-    int index = url.indexOf("://");
-    if (index == -1) {
-      ALog.e(TAG, "下载失败,url【" + url + "】不合法");
-      return false;
+  public FtpDirDownloadTarget login(String userName, String password, String account) {
+    if (TextUtils.isEmpty(userName)) {
+      Log.e(TAG, "用户名不能为null");
+      return this;
+    } else if (TextUtils.isEmpty(password)) {
+      Log.e(TAG, "密码不能为null");
+      return this;
     }
-    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 FtpDirDownloadTarget login(String userName, String password, String account) {
-    return mDelegate.login(userName, password, account);
+    mTaskEntity.userName = userName;
+    mTaskEntity.userPw = password;
+    mTaskEntity.account = account;
+    return this;
   }
 }

+ 74 - 46
Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java

@@ -16,51 +16,35 @@
 package com.arialyy.aria.core.download;
 
 import android.support.annotation.NonNull;
-import com.arialyy.aria.core.delegate.FtpDelegate;
+import android.text.TextUtils;
+import android.util.Log;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
-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 BaseNormalTarget<FtpDownloadTarget>
-    implements IFtpTarget<FtpDownloadTarget> {
-  private FtpDelegate<FtpDownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
-
-  FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
-    this(entity.getUrl(), targetName, refreshInfo);
-  }
+public class FtpDownloadTarget extends DownloadTarget {
+  private final String TAG = "FtpDownloadTarget";
+  private String serverIp, remotePath;
+  private int port;
 
   FtpDownloadTarget(String url, String targetName) {
-    this(url, targetName, false);
-  }
-
-  FtpDownloadTarget(String url, String targetName, boolean refreshInfo) {
-    initTarget(url, targetName, refreshInfo);
-    init(refreshInfo);
-  }
-
-  private void init(boolean refreshInfo) {
+    super(url, targetName);
+    String[] pp = url.split("/")[2].split(":");
+    this.serverIp = pp[0];
+    this.port = Integer.parseInt(pp[1]);
+    mTaskEntity.requestType = AbsTaskEntity.FTP;
+    remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
+    if (TextUtils.isEmpty(remotePath)) {
+      throw new NullPointerException("ftp服务器地址不能为null");
+    }
     int lastIndex = url.lastIndexOf("/");
+    mTaskEntity.serverIp = serverIp;
+    mTaskEntity.port = port;
     mEntity.setFileName(url.substring(lastIndex + 1, url.length()));
-    mTaskEntity.setUrlEntity(CommonUtil.getFtpUrlInfo(url));
-    mTaskEntity.setRefreshInfo(refreshInfo);
-    mTaskEntity.setRequestType(AbsTaskEntity.D_FTP);
-
-    mDelegate = new FtpDelegate<>(this, mTaskEntity);
-  }
-
-  /**
-   * 设置文件保存文件夹路径
-   *
-   * @param filePath 文件保存路径
-   * @deprecated {@link #setFilePath(String)} 请使用这个api
-   */
-  @Deprecated
-  public FtpDownloadTarget setDownloadPath(@NonNull String filePath) {
-    return setFilePath(filePath);
   }
 
   /**
@@ -68,25 +52,69 @@ public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
    * 关于文件名:
    * 1、如果保存路径是该文件的保存路径,如:/mnt/sdcard/file.zip,则使用路径中的文件名file.zip
    * 2、如果保存路径是文件夹路径,如:/mnt/sdcard/,则使用FTP服务器该文件的文件名
+   *
+   * @param downloadPath 路径必须为文件路径,不能为文件夹路径
    */
-  public FtpDownloadTarget setFilePath(@NonNull String filePath) {
-    mTempFilePath = 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());
+      }
+    }
     return this;
   }
 
-  @Override protected int getTargetType() {
-    return FTP;
-  }
-
-  @Override public FtpDownloadTarget charSet(String charSet) {
-    return mDelegate.charSet(charSet);
+  /**
+   * 设置字符编码
+   */
+  public FtpDownloadTarget charSet(String charSet) {
+    if (TextUtils.isEmpty(charSet)) return this;
+    mTaskEntity.charSet = charSet;
+    return this;
   }
 
-  @Override public FtpDownloadTarget login(String userName, String password) {
-    return mDelegate.login(userName, password);
+  /**
+   * ftp 用户登录信息
+   *
+   * @param userName ftp用户名
+   * @param password ftp用户密码
+   */
+  public FtpDownloadTarget login(String userName, String password) {
+    return login(userName, password, null);
   }
 
-  @Override public FtpDownloadTarget login(String userName, String password, String account) {
-    return mDelegate.login(userName, password, account);
+  /**
+   * ftp 用户登录信息
+   *
+   * @param userName ftp用户名
+   * @param password ftp用户密码
+   * @param account ftp账号
+   */
+  public FtpDownloadTarget login(String userName, String password, String account) {
+    if (TextUtils.isEmpty(userName)) {
+      Log.e(TAG, "用户名不能为null");
+      return this;
+    } else if (TextUtils.isEmpty(password)) {
+      Log.e(TAG, "密码不能为null");
+      return this;
+    }
+    mTaskEntity.userName = userName;
+    mTaskEntity.userPw = password;
+    mTaskEntity.account = account;
+    return this;
   }
 }

+ 155 - 0
Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsFtpInfoThread.java

@@ -0,0 +1,155 @@
+/*
+ * 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.downloader;
+
+import android.text.TextUtils;
+import android.util.Log;
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.common.AbsThreadTask;
+import com.arialyy.aria.core.inf.AbsEntity;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.util.CommonUtil;
+import java.io.IOException;
+import org.apache.commons.net.ftp.FTP;
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+
+/**
+ * Created by Aria.Lao on 2017/7/25.
+ * 获取ftp文件夹信息
+ */
+abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
+    implements Runnable {
+
+  private final String TAG = "HttpFileInfoThread";
+  protected ENTITY mEntity;
+  protected TASK_ENTITY mTaskEntity;
+  private int mConnectTimeOut;
+  private OnFileInfoCallback mCallback;
+
+  AbsFtpInfoThread(TASK_ENTITY taskEntity, OnFileInfoCallback callback) {
+    mTaskEntity = taskEntity;
+    mEntity = taskEntity.getEntity();
+    mConnectTimeOut =
+        AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
+    mCallback = callback;
+  }
+
+  @Override public void run() {
+    FTPClient client = null;
+    try {
+      String url = mTaskEntity.getEntity().getKey();
+      String[] pp = url.split("/")[2].split(":");
+      String serverIp = pp[0];
+      int port = Integer.parseInt(pp[1]);
+      String remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
+      client = new FTPClient();
+      client.connect(serverIp, port);
+      if (!TextUtils.isEmpty(mTaskEntity.account)) {
+        client.login(mTaskEntity.userName, mTaskEntity.userPw);
+      } else {
+        client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
+      }
+      int reply = client.getReplyCode();
+      if (!FTPReply.isPositiveCompletion(reply)) {
+        client.disconnect();
+        failDownload("无法连接到ftp服务器,错误码为:" + reply);
+        return;
+      }
+      client.setDataTimeout(mConnectTimeOut);
+      String charSet = "UTF-8";
+      // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
+      if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
+          client.sendCommand("OPTS UTF8", "ON"))) {
+        charSet = mTaskEntity.charSet;
+      }
+      client.setControlEncoding(charSet);
+      client.enterLocalPassiveMode();
+      client.setFileType(FTP.BINARY_FILE_TYPE);
+      FTPFile[] files =
+          client.listFiles(new String(remotePath.getBytes(charSet), AbsThreadTask.SERVER_CHARSET));
+      long size = getFileSize(files, client, remotePath);
+      mEntity.setFileSize(size);
+      reply = client.getReplyCode();
+      if (!FTPReply.isPositiveCompletion(reply)) {
+        client.disconnect();
+        failDownload("获取文件信息错误,错误码为:" + reply);
+        return;
+      }
+      mTaskEntity.code = reply;
+      onPreComplete();
+      mEntity.update();
+      mTaskEntity.update();
+      mCallback.onComplete(mEntity.getKey(), reply);
+    } catch (IOException e) {
+      failDownload(e.getMessage());
+    } finally {
+      if (client != null) {
+        try {
+          client.disconnect();
+        } catch (IOException e) {
+          e.printStackTrace();
+        }
+      }
+    }
+  }
+
+  void start() {
+    new Thread(this).start();
+  }
+
+  protected void onPreComplete() {
+
+  }
+
+  /**
+   * 遍历FTP服务器上对应文件或文件夹大小
+   *
+   * @throws IOException
+   */
+  private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
+    long size = 0;
+    String path = dirName + "/";
+    for (FTPFile file : files) {
+      if (file.isFile()) {
+        size += file.getSize();
+        handleFile(path + file.getName(), file);
+      } else {
+        size += getFileSize(client.listFiles(
+            CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client,
+            path + file.getName());
+      }
+    }
+    return size;
+  }
+
+  /**
+   * 处理FTP文件信息
+   *
+   * @param remotePath ftp服务器文件夹路径
+   * @param ftpFile ftp服务器上对应的文件
+   */
+  void handleFile(String remotePath, FTPFile ftpFile) {
+  }
+
+  private void failDownload(String errorMsg) {
+    Log.e(TAG, errorMsg);
+    if (mCallback != null) {
+      mCallback.onFail(mEntity.getKey(), errorMsg);
+    }
+  }
+}

+ 142 - 270
Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java

@@ -22,11 +22,11 @@ import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.IDownloadListener;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.util.ALog;
+import com.arialyy.aria.orm.DbEntity;
 import com.arialyy.aria.util.CommonUtil;
-import com.arialyy.aria.util.NetUtils;
 import java.io.File;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.Timer;
@@ -38,27 +38,26 @@ import java.util.concurrent.Executors;
  * Created by AriaL on 2017/6/30.
  * 任务组核心逻辑
  */
-public abstract class AbsGroupUtil implements IUtil {
-  private final String TAG = "AbsGroupUtil";
+abstract class AbsGroupUtil implements IUtil {
+  private final String TAG = "DownloadGroupUtil";
   /**
-   * FTP文件夹
+   * 任务组所有任务总大小
    */
-  protected int FTP_DIR = 0xa1;
+  long mTotalSize = 0;
+  protected long mCurrentLocation = 0;
+  private ExecutorService mExePool;
+  protected IDownloadGroupListener mListener;
+  protected DownloadGroupTaskEntity mTaskEntity;
+  private boolean isRunning = true;
+  private Timer mTimer;
   /**
-   * HTTP 任务组
+   * 初始化完成的任务书数
    */
-  protected int HTTP_GROUP = 0xa2;
-
+  int mInitNum = 0;
   /**
-   * 任务组所有任务总长度
+   * 初始化失败的任务数
    */
-  long mTotalLen = 0;
-  long mCurrentLocation = 0;
-  private ExecutorService mExePool;
-  protected IDownloadGroupListener mListener;
-  protected DownloadGroupTaskEntity mGTEntity;
-  private boolean isRunning = false;
-  private Timer mTimer;
+  int mInitFailNum = 0;
   /**
    * 保存所有没有下载完成的任务,key为下载地址
    */
@@ -70,145 +69,49 @@ public abstract class AbsGroupUtil implements IUtil {
   Map<String, DownloadTaskEntity> mFailMap = new HashMap<>();
 
   /**
-   * 该任务组对应的所有任务
-   */
-  private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>();
-
-  /**
    * 下载器映射表,key为下载地址
    */
   private Map<String, Downloader> mDownloaderMap = new HashMap<>();
 
   /**
-   * 是否需要读取文件长度,{@code true}需要
+   * 该任务组对应的所有任务
    */
-  boolean isNeedLoadFileSize = true;
+  private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>();
   //已经完成的任务数
-  int mCompleteNum = 0;
-  //停止的任务数
-  private int mStopNum = 0;
-  //任务组大小
-  int mGroupSize = 0;
-  private long mUpdateInterval = 1000;
-
-  AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity groupEntity) {
+  private int mCompleteNum = 0;
+  //失败的任务数
+  private int mFailNum = 0;
+  //实际的下载任务数
+  int mActualTaskNum = 0;
+
+  AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
     mListener = listener;
-    mGTEntity = groupEntity;
+    mTaskEntity = taskEntity;
     mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
-    mUpdateInterval =
-        AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getUpdateInterval();
-  }
-
-  /**
-   * 获取任务类型
-   *
-   * @return {@link #FTP_DIR}、{@link #HTTP_GROUP}
-   */
-  abstract int getTaskType();
-
-  /**
-   * 更新任务组文件大小
-   */
-  void updateFileSize() {
-    if (isNeedLoadFileSize) {
-      mGTEntity.getEntity().setFileSize(mTotalLen);
-      mGTEntity.getEntity().update();
-    }
-  }
-
-  /**
-   * 启动子任务下载
-   *
-   * @param url 子任务下载地址
-   */
-  public void startSubTask(String url) {
-    if (!checkSubTask(url, "开始")) return;
-    if (!isRunning) {
-      isRunning = true;
-      startTimer();
-    }
-    Downloader d = getDownloader(url, false);
-    if (d != null && !d.isRunning()) {
-      d.setNewTask(false);
-      d.start();
-    }
-  }
-
-  /**
-   * 停止子任务下载
-   *
-   * @param url 子任务下载地址
-   */
-  public void stopSubTask(String url) {
-    if (!checkSubTask(url, "停止")) return;
-    Downloader d = getDownloader(url, false);
-    if (d != null && d.isRunning()) {
-      d.stop();
-    }
-  }
-
-  /**
-   * 删除子任务
-   *
-   * @param url 子任务下载地址
-   */
-  public void cancelSubTask(String url) {
-    Set<String> urls = mTasksMap.keySet();
-    if (!urls.isEmpty() && urls.contains(url)) {
-      DownloadTaskEntity det = mTasksMap.get(url);
-      if (det != null) {
-        mTotalLen -= det.getEntity().getFileSize();
-        mGroupSize--;
-        if (mGroupSize == 0) {
-          closeTimer(false);
-          mListener.onCancel();
-        }
+    List<DownloadTaskEntity> tasks =
+        DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mTaskEntity.key);
+    if (tasks != null && !tasks.isEmpty()) {
+      for (DownloadTaskEntity te : tasks) {
+        mTasksMap.put(te.getEntity().getUrl(), te);
       }
-      mGTEntity.update();
-    }
-    Downloader d = getDownloader(url, false);
-    if (d != null) {
-      d.cancel();
     }
-  }
-
-  /**
-   * 检查子任务
-   *
-   * @param url 子任务url
-   * @param type 任务类型
-   * @return {@code true} 任务可以下载
-   */
-  private boolean checkSubTask(String url, String type) {
-    DownloadTaskEntity entity = mTasksMap.get(url);
-    if (entity != null) {
-      if (entity.getState() == IEntity.STATE_COMPLETE) {
-        ALog.w(TAG, "任务【" + url + "】已完成," + type + "失败");
-        return false;
+    for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) {
+      File file = new File(entity.getDownloadPath());
+      if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) {
+        mCompleteNum++;
+        mInitNum++;
+        mCurrentLocation += entity.getFileSize();
+      } else {
+        mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
+        mCurrentLocation += entity.getCurrentProgress();
+        mActualTaskNum++;
       }
-    } else {
-      ALog.w(TAG, "任务组中没有该任务【" + url + "】," + type + "失败");
-      return false;
-    }
-    return true;
-  }
-
-  /**
-   * 通过地址获取下载器
-   *
-   * @param url 子任务下载地址
-   * @param start 是否启动任务
-   */
-  private Downloader getDownloader(String url, boolean start) {
-    Downloader d = mDownloaderMap.get(url);
-    if (d == null) {
-      return createChildDownload(mTasksMap.get(url), start);
+      mTotalSize += entity.getFileSize();
     }
-    return d;
   }
 
   @Override public long getFileSize() {
-    return mTotalLen;
+    return mTotalSize;
   }
 
   @Override public long getCurrentLocation() {
@@ -221,6 +124,7 @@ public abstract class AbsGroupUtil implements IUtil {
 
   @Override public void cancel() {
     closeTimer(false);
+    mListener.onCancel();
     onCancel();
     if (!mExePool.isShutdown()) {
       mExePool.shutdown();
@@ -233,16 +137,29 @@ public abstract class AbsGroupUtil implements IUtil {
         dt.cancel();
       }
     }
-    clearState();
-    mListener.onCancel();
+    delDownloadInfo();
+    mTaskEntity.deleteData();
   }
 
   public void onCancel() {
 
   }
 
+  /**
+   * 删除所有子任务的下载信息
+   */
+  private void delDownloadInfo() {
+    List<DownloadTaskEntity> tasks =
+        DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mTaskEntity.key);
+    if (tasks == null || tasks.isEmpty()) return;
+    for (DownloadTaskEntity taskEntity : tasks) {
+      CommonUtil.delDownloadTaskConfig(taskEntity.removeFile, taskEntity);
+    }
+  }
+
   @Override public void stop() {
     closeTimer(false);
+    mListener.onStop(mCurrentLocation);
     onStop();
     if (!mExePool.isShutdown()) {
       mExePool.shutdown();
@@ -261,35 +178,10 @@ public abstract class AbsGroupUtil implements IUtil {
 
   }
 
-  /**
-   * 预处理操作,由于属性的不同,http任务组在构造函数中就可以完成了
-   * 而FTP文件夹的,需要获取完成所有子任务信息才算预处理完成
-   */
-  protected void onPre() {
-    mListener.onPre();
-    mGroupSize = mGTEntity.getSubTaskEntities().size();
-    mTotalLen = mGTEntity.getEntity().getFileSize();
-    isNeedLoadFileSize = mTotalLen <= 1;
-    for (DownloadTaskEntity te : mGTEntity.getSubTaskEntities()) {
-      File file = new File(te.getKey());
-      if (te.getState() == IEntity.STATE_COMPLETE && file.exists()) {
-        mCompleteNum++;
-        mCurrentLocation += te.getEntity().getFileSize();
-      } else {
-        mExeMap.put(te.getUrl(), te);
-        mCurrentLocation += file.exists() ? te.getEntity().getCurrentProgress() : 0;
-      }
-      if (isNeedLoadFileSize) {
-        mTotalLen += te.getEntity().getFileSize();
-      }
-      mTasksMap.put(te.getUrl(), te);
-    }
-    updateFileSize();
-  }
-
   @Override public void start() {
     isRunning = true;
-    clearState();
+    mFailNum = 0;
+    mListener.onPre();
     onStart();
   }
 
@@ -306,17 +198,11 @@ public abstract class AbsGroupUtil implements IUtil {
 
   }
 
-  private void clearState(){
-    mDownloaderMap.clear();
-    mFailMap.clear();
-  }
-
   private void closeTimer(boolean isRunning) {
     this.isRunning = isRunning;
     if (mTimer != null) {
       mTimer.purge();
       mTimer.cancel();
-      mTimer = null;
     }
   }
 
@@ -325,12 +211,8 @@ public abstract class AbsGroupUtil implements IUtil {
    */
   void startRunningFlow() {
     closeTimer(true);
-    mListener.onPostPre(mTotalLen);
+    mListener.onPostPre(mTotalSize);
     mListener.onStart(mCurrentLocation);
-    startTimer();
-  }
-
-  private void startTimer() {
     mTimer = new Timer(true);
     mTimer.schedule(new TimerTask() {
       @Override public void run() {
@@ -340,48 +222,66 @@ public abstract class AbsGroupUtil implements IUtil {
           mListener.onProgress(mCurrentLocation);
         }
       }
-    }, 0, mUpdateInterval);
+    }, 0, 1000);
   }
 
   /**
-   * 创建子任务下载器,默认创建完成自动启动
+   * 启动子任务下载器
    */
-  Downloader createChildDownload(DownloadTaskEntity taskEntity) {
-    return createChildDownload(taskEntity, true);
+  void startChildDownload(DownloadTaskEntity taskEntity) {
+    ChildDownloadListener listener = new ChildDownloadListener(taskEntity);
+    Downloader dt = new Downloader(listener, taskEntity);
+    mDownloaderMap.put(taskEntity.getEntity().getUrl(), dt);
+    if (mExePool.isShutdown()) return;
+    mExePool.execute(dt);
   }
 
   /**
-   * 创建子任务下载器,启动子任务下载器
-   *
-   * @param start 是否启动下载
+   * 创建子任务下载信息
    */
-  private Downloader createChildDownload(DownloadTaskEntity taskEntity, boolean start) {
-    ChildDownloadListener listener = new ChildDownloadListener(taskEntity);
-    Downloader dt = new Downloader(listener, taskEntity);
-    mDownloaderMap.put(taskEntity.getEntity().getUrl(), dt);
-    if (mExePool.isShutdown()) return dt;
-    if (start) {
-      mExePool.execute(dt);
+  DownloadTaskEntity createChildDownloadTask(DownloadEntity entity) {
+    DownloadTaskEntity taskEntity = mTasksMap.get(entity.getUrl());
+    if (taskEntity != null) {
+      taskEntity.entity = entity;
+      //ftp登录的
+      taskEntity.userName = mTaskEntity.userName;
+      taskEntity.userPw = mTaskEntity.userPw;
+      taskEntity.account = mTaskEntity.account;
+      return taskEntity;
     }
-    return dt;
+    taskEntity = new DownloadTaskEntity();
+    taskEntity.entity = entity;
+    taskEntity.headers = mTaskEntity.headers;
+    taskEntity.requestEnum = mTaskEntity.requestEnum;
+    taskEntity.redirectUrlKey = mTaskEntity.redirectUrlKey;
+    taskEntity.removeFile = mTaskEntity.removeFile;
+    taskEntity.groupName = mTaskEntity.key;
+    taskEntity.isGroupTask = true;
+    taskEntity.requestType = mTaskEntity.requestType;
+    //ftp登录的
+    taskEntity.userName = mTaskEntity.userName;
+    taskEntity.userPw = mTaskEntity.userPw;
+    taskEntity.account = mTaskEntity.account;
+    taskEntity.key = entity.getDownloadPath();
+    taskEntity.save();
+    return taskEntity;
   }
 
   /**
    * 子任务事件监听
    */
   private class ChildDownloadListener implements IDownloadListener {
-    private DownloadTaskEntity subTaskEntity;
-    private DownloadEntity subEntity;
-    private int RUN_SAVE_INTERVAL = 5 * 1000;  //5s保存一次下载中的进度
-    private long lastSaveTime;
-    private long lastLen = 0;
+
+    DownloadTaskEntity taskEntity;
+    DownloadEntity entity;
+
+    long lastLen = 0;
 
     ChildDownloadListener(DownloadTaskEntity entity) {
-      subTaskEntity = entity;
-      subEntity = subTaskEntity.getEntity();
-      subEntity.setFailNum(0);
-      lastLen = subEntity.getCurrentProgress();
-      lastSaveTime = System.currentTimeMillis();
+      this.taskEntity = entity;
+      this.entity = taskEntity.getEntity();
+      lastLen = this.entity.getCurrentProgress();
+      this.entity.setFailNum(0);
     }
 
     @Override public void onPre() {
@@ -389,99 +289,77 @@ public abstract class AbsGroupUtil implements IUtil {
     }
 
     @Override public void onPostPre(long fileSize) {
-      subEntity.setFileSize(fileSize);
-      subEntity.setConvertFileSize(CommonUtil.formatFileSize(fileSize));
+      entity.setFileSize(fileSize);
+      entity.setConvertFileSize(CommonUtil.formatFileSize(fileSize));
       saveData(IEntity.STATE_POST_PRE, -1);
-      mListener.onSubPre(subEntity);
     }
 
     @Override public void onResume(long resumeLocation) {
       saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
       lastLen = resumeLocation;
-      mListener.onSubStart(subEntity);
     }
 
     @Override public void onStart(long startLocation) {
       saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
       lastLen = startLocation;
-      mListener.onSubStart(subEntity);
     }
 
     @Override public void onProgress(long currentLocation) {
       long speed = currentLocation - lastLen;
       mCurrentLocation += speed;
-      subEntity.setCurrentProgress(currentLocation);
-      handleSpeed(speed);
-      mListener.onSubRunning(subEntity);
-      if (System.currentTimeMillis() - lastSaveTime >= RUN_SAVE_INTERVAL) {
-        saveData(IEntity.STATE_RUNNING, currentLocation);
-        lastSaveTime = System.currentTimeMillis();
-      }
       lastLen = currentLocation;
+      entity.setCurrentProgress(currentLocation);
+      handleSpeed(speed);
     }
 
     @Override public void onStop(long stopLocation) {
       saveData(IEntity.STATE_STOP, stopLocation);
       handleSpeed(0);
-      mListener.onSubStop(subEntity);
-      synchronized (AbsGroupUtil.class) {
-        mStopNum++;
-        if (mStopNum + mCompleteNum + mFailMap.size() == mGroupSize) {
-          closeTimer(false);
-          mListener.onStop(mCurrentLocation);
-        }
-      }
+      mListener.onSubStop(entity);
     }
 
     @Override public void onCancel() {
       saveData(IEntity.STATE_CANCEL, -1);
       handleSpeed(0);
-      mListener.onSubCancel(subEntity);
+      mListener.onSubCancel(entity);
     }
 
     @Override public void onComplete() {
-      saveData(IEntity.STATE_COMPLETE, subEntity.getFileSize());
+      saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
+      mCompleteNum++;
       handleSpeed(0);
-      mListener.onSubComplete(subEntity);
-      synchronized (ChildDownloadListener.class) {
-        mCompleteNum++;
-        //如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
-        if (mCompleteNum >= mGroupSize) {
-          closeTimer(false);
-          mListener.onComplete();
-        } else if (mFailMap.size() > 0 && mStopNum + mCompleteNum + mFailMap.size() >= mGroupSize) {
-          //如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
-          closeTimer(false);
-          mListener.onStop(mCurrentLocation);
-        }
+      mListener.onSubComplete(entity);
+      //如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
+      if (mCompleteNum >= mTaskEntity.getEntity().getSubTask().size()) {
+        closeTimer(false);
+        mListener.onComplete();
+      } else if (mCompleteNum + mFailNum >= mActualTaskNum) {
+        //如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
+        closeTimer(false);
       }
     }
 
-    @Override public void onFail(boolean needRetry) {
-      subEntity.setFailNum(subEntity.getFailNum() + 1);
+    @Override public void onFail() {
+      entity.setFailNum(entity.getFailNum() + 1);
       saveData(IEntity.STATE_FAIL, lastLen);
       handleSpeed(0);
-      reTry(needRetry);
+      reTry();
     }
 
     /**
-     * 重试下载
+     * 失败后重试下载,如果失败次数超过5次,不再重试
      */
-    private void reTry(boolean needRetry) {
-      synchronized (ChildDownloadListener.class) {
-        if (subEntity.getFailNum() < 5 && needRetry && NetUtils.isConnected(AriaManager.APP)) {
+    private void reTry() {
+      synchronized (AriaManager.LOCK) {
+        if (entity.getFailNum() < 5 && isRunning) {
           reStartTask();
         } else {
-          mFailMap.put(subTaskEntity.getUrl(), subTaskEntity);
-          mListener.onSubFail(subEntity);
+          mFailNum++;
+          mListener.onSubFail(entity);
           //如果失败的任务数大于实际的下载任务数,任务组停止下载
-          if (mFailMap.size() >= mExeMap.size()) {
+          if (mFailNum >= mActualTaskNum) {
             closeTimer(false);
-            if (mFailMap.size() == mGroupSize) {  //所有任务都失败了,则认为该任务组已经失败
-              mListener.onFail(true);
-            } else {
-              mListener.onStop(mCurrentLocation);
-            }
+            mListener.onStop(mCurrentLocation);
           }
         }
       }
@@ -491,33 +369,27 @@ public abstract class AbsGroupUtil implements IUtil {
       Timer timer = new Timer();
       timer.schedule(new TimerTask() {
         @Override public void run() {
-          Downloader dt = mDownloaderMap.get(subEntity.getUrl());
+          Downloader dt = mDownloaderMap.get(entity.getUrl());
           dt.start();
         }
       }, 3000);
     }
 
     private void handleSpeed(long speed) {
-      subEntity.setSpeed(speed);
-      subEntity.setConvertSpeed(speed <= 0 ? "" : CommonUtil.formatFileSize(speed) + "/s");
-      subEntity.setPercent((int) (subEntity.getFileSize() <= 0 ? 0
-          : subEntity.getCurrentProgress() * 100 / subEntity.getFileSize()));
+      entity.setSpeed(speed);
+      entity.setConvertSpeed(speed <= 0 ? "" : CommonUtil.formatFileSize(speed) + "/s");
     }
 
     private void saveData(int state, long location) {
-      subTaskEntity.setState(state);
-      subEntity.setState(state);
-      subEntity.setComplete(state == IEntity.STATE_COMPLETE);
-      if (state == IEntity.STATE_CANCEL) {
-        subEntity.deleteData();
-        return;
-      } else if (subEntity.isComplete()) {
-        subEntity.setCompleteTime(System.currentTimeMillis());
-        subEntity.setCurrentProgress(subEntity.getFileSize());
+      entity.setState(state);
+      entity.setComplete(state == IEntity.STATE_COMPLETE);
+      if (entity.isComplete()) {
+        entity.setCompleteTime(System.currentTimeMillis());
+        entity.setCurrentProgress(entity.getFileSize());
       } else if (location > 0) {
-        subEntity.setCurrentProgress(location);
+        entity.setCurrentProgress(location);
       }
-      subTaskEntity.update();
+      entity.update();
     }
 
     @Override public void supportBreakpoint(boolean support) {

+ 8 - 30
Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java

@@ -16,21 +16,19 @@
 package com.arialyy.aria.core.download.downloader;
 
 import android.text.TextUtils;
+
 import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.util.ALog;
 import com.arialyy.aria.util.SSLContextUtil;
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.net.ProtocolException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.util.Set;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.InflaterInputStream;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
+import org.apache.commons.net.ftp.FTPClient;
 
 /**
  * Created by lyy on 2017/1/18.
@@ -39,26 +37,6 @@ import javax.net.ssl.SSLSocketFactory;
 class ConnectionHelp {
 
   /**
-   * 转换HttpUrlConnect的inputStream流
-   *
-   * @return {@link GZIPInputStream}、{@link InflaterInputStream}
-   * @throws IOException
-   */
-  static InputStream convertInputStream(HttpURLConnection connection) throws IOException {
-    String encoding = connection.getContentEncoding();
-    if (TextUtils.isEmpty(encoding)) {
-      return connection.getInputStream();
-    }
-    if (encoding.contains("gzip")) {
-      return new GZIPInputStream(connection.getInputStream());
-    } else if (encoding.contains("deflate")) {
-      return new InflaterInputStream(connection.getInputStream());
-    } else {
-      return connection.getInputStream();
-    }
-  }
-
-  /**
    * 处理链接
    *
    * @throws IOException
@@ -89,12 +67,12 @@ class ConnectionHelp {
    */
   static HttpURLConnection setConnectParam(DownloadTaskEntity entity, HttpURLConnection conn)
       throws ProtocolException {
-    conn.setRequestMethod(entity.getRequestEnum().name);
+    conn.setRequestMethod(entity.requestEnum.name);
     Set<String> keys = null;
-    if (entity.getHeaders() != null && entity.getHeaders().size() > 0) {
-      keys = entity.getHeaders().keySet();
+    if (entity.headers != null && entity.headers.size() > 0) {
+      keys = entity.headers.keySet();
       for (String key : keys) {
-        conn.setRequestProperty(key, entity.getHeaders().get(key));
+        conn.setRequestProperty(key, entity.headers.get(key));
       }
     }
     if (keys == null || !keys.contains("Charset")) {
@@ -109,7 +87,6 @@ class ConnectionHelp {
           .append("image/jpeg, ")
           .append("image/pjpeg, ")
           .append("image/webp, ")
-          .append("image/apng, ")
           .append("application/xml, ")
           .append("application/xaml+xml, ")
           .append("application/xhtml+xml, ")
@@ -138,6 +115,7 @@ class ConnectionHelp {
     conn.setInstanceFollowRedirects(false);
     return conn;
   }
+
   /**
    * 返回正确的UserAgent
    * @return
@@ -158,10 +136,10 @@ class ConnectionHelp {
         }
       }
 
-      ALog.d("Aria_ConnectionHelp", "User-Agent: "+ sb.toString());
     } catch (Exception e) {
       e.printStackTrace();
     }
     return TextUtils.isEmpty(sb) ? "Dalvik/2.1.0 (Linux; U; Android 5.1.1; letv x501 Build/LMY48Z)" : sb.toString();
   }
+
 }

+ 21 - 43
Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java

@@ -16,13 +16,10 @@
 package com.arialyy.aria.core.download.downloader;
 
 import android.util.SparseArray;
-import com.arialyy.aria.core.common.CompleteInfo;
 import com.arialyy.aria.core.common.IUtil;
-import com.arialyy.aria.core.common.OnFileInfoCallback;
 import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.util.ALog;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -34,7 +31,6 @@ import java.util.concurrent.Executors;
 public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
   private final String TAG = "DownloadGroupUtil";
   private ExecutorService mInfoPool;
-  private int mInitCompleteNum, mInitFailNum;
 
   /**
    * 文件信息回调组
@@ -44,11 +40,6 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
   public DownloadGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
     super(listener, taskEntity);
     mInfoPool = Executors.newCachedThreadPool();
-    onPre();
-  }
-
-  @Override int getTaskType() {
-    return HTTP_GROUP;
   }
 
   @Override public void onCancel() {
@@ -67,29 +58,22 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
 
   @Override protected void onStart() {
     super.onStart();
-    if (mCompleteNum == mGroupSize) {
-      mListener.onComplete();
-      return;
-    }
-
-    if (mExeMap.size() == 0) {
-      ALog.e(TAG, "任务组无可执行任务");
-      mListener.onFail(false);
-      return;
-    }
     Set<String> keys = mExeMap.keySet();
+    int i = 0;
     for (String key : keys) {
       DownloadTaskEntity taskEntity = mExeMap.get(key);
       if (taskEntity != null) {
         if (taskEntity.getState() != IEntity.STATE_FAIL
             && taskEntity.getState() != IEntity.STATE_WAIT) {
-          createChildDownload(taskEntity);
+          startChildDownload(taskEntity);
+          i++;
         } else {
           mInfoPool.execute(createFileInfoThread(taskEntity));
         }
       }
     }
-    if (mCurrentLocation == mTotalLen) {
+    if (i != 0 && i == mExeMap.size()) startRunningFlow();
+    if (mCurrentLocation == mTotalSize) {
       mListener.onComplete();
     }
   }
@@ -104,42 +88,36 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
       callback = new OnFileInfoCallback() {
         int failNum = 0;
 
-        @Override public void onComplete(String url, CompleteInfo info) {
+        @Override public void onComplete(String url, int code) {
           DownloadTaskEntity te = mExeMap.get(url);
           if (te != null) {
-            if (isNeedLoadFileSize) {
-              mTotalLen += te.getEntity().getFileSize();
-            }
-            createChildDownload(te);
+            mTotalSize += te.getEntity().getFileSize();
+            startChildDownload(te);
           }
-          mInitCompleteNum ++;
-
-          if (mInitCompleteNum + mInitFailNum >= mGroupSize || !isNeedLoadFileSize) {
+          mInitNum++;
+          if (mInitNum + mInitFailNum >= mTaskEntity.getEntity().getSubTask().size()) {
             startRunningFlow();
-            updateFileSize();
           }
         }
 
-        @Override public void onFail(String url, String errorMsg, boolean needRetry) {
-          ALog.e(TAG, "任务【" + url + "】初始化失败。");
+        @Override public void onFail(String url, String errorMsg) {
           DownloadTaskEntity te = mExeMap.get(url);
           if (te != null) {
             mFailMap.put(url, te);
             mFileInfoCallbacks.put(te.hashCode(), this);
-            mExeMap.remove(url);
           }
           //404链接不重试下载
-          //if (failNum < 3 && !errorMsg.contains("错误码:404") && !errorMsg.contains(
-          //    "UnknownHostException")) {
-          //  mInfoPool.execute(createFileInfoThread(te));
-          //} else {
-          //  mInitFailNum++;
-          //}
-          //failNum++;
-          mInitFailNum ++;
-          if (mInitCompleteNum + mInitFailNum >= mGroupSize || !isNeedLoadFileSize) {
+          if (failNum < 10 && !errorMsg.contains("错误码:404") && !errorMsg.contains(
+              "UnknownHostException")) {
+            mInfoPool.execute(createFileInfoThread(te));
+          } else {
+            mInitFailNum++;
+            mActualTaskNum--;
+            if (mActualTaskNum < 0) mActualTaskNum = 0;
+          }
+          failNum++;
+          if (mInitNum + mInitFailNum >= mTaskEntity.getEntity().getSubTask().size()) {
             startRunningFlow();
-            updateFileSize();
           }
         }
       };

+ 29 - 32
Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java

@@ -23,10 +23,9 @@ import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IDownloadListener;
-import com.arialyy.aria.util.ALog;
+import com.arialyy.aria.orm.DbEntity;
 import com.arialyy.aria.util.BufferedRandomAccessFile;
 import com.arialyy.aria.util.CommonUtil;
-import com.arialyy.aria.util.ErrorHelp;
 import java.io.File;
 import java.io.IOException;
 
@@ -35,41 +34,48 @@ import java.io.IOException;
  * 文件下载器
  */
 class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
-  private String TAG = "Downloader";
 
   Downloader(IDownloadListener listener, DownloadTaskEntity taskEntity) {
     super(listener, taskEntity);
-    mTempFile = new File(mEntity.getDownloadPath());
-    AriaManager manager = AriaManager.getInstance(AriaManager.APP);
-    setUpdateInterval(manager.getDownloadConfig().getUpdateInterval());
   }
 
-  @Override protected int setNewTaskThreadNum() {
-    return
-        // 小于1m的文件或是任务组的子任务、使用虚拟文件,线程数都是1
-        mEntity.getFileSize() <= SUB_LEN
-            || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR
-            || mTaskEntity.getRequestType() == AbsTaskEntity.DG_HTTP
-            || mRecord.isOpenDynamicFile
-            ? 1
-            : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
+  @Override protected void checkTask() {
+    if (!mTaskEntity.isSupportBP) {
+      isNewTask = true;
+      return;
+    }
+    mConfigFile = new File(mContext.getFilesDir().getPath()
+        + AriaManager.DOWNLOAD_TEMP_DIR
+        + mEntity.getFileName()
+        + ".properties");
+    mTempFile = new File(mEntity.getDownloadPath());
+    if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
+      isNewTask = true;
+      CommonUtil.createFile(mConfigFile.getPath());
+    } else if (!mTempFile.exists()) {
+      isNewTask = true;
+    } else if (DbEntity.findFirst(DownloadEntity.class, "url=?", mEntity.getDownloadUrl())
+        == null) {
+      isNewTask = true;
+    } else {
+      isNewTask = checkConfigFile();
+    }
   }
 
-  @Override protected boolean handleNewTask() {
+  @Override protected void handleNewTask() {
     CommonUtil.createFile(mTempFile.getPath());
     BufferedRandomAccessFile file = null;
     try {
       file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192);
       //设置文件长度
-      file.setLength(mRecord.isOpenDynamicFile ? 1 : mEntity.getFileSize());
-      return true;
+      file.setLength(mEntity.getFileSize());
     } catch (IOException e) {
       failDownload("下载失败【downloadUrl:"
           + mEntity.getUrl()
           + "】\n【filePath:"
           + mEntity.getDownloadPath()
           + "】\n"
-          + ALog.getExceptionString(e));
+          + CommonUtil.getPrintException(e));
     } finally {
       if (file != null) {
         try {
@@ -79,25 +85,16 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
         }
       }
     }
-    return false;
   }
 
   @Override protected AbsThreadTask selectThreadTask(SubThreadConfig<DownloadTaskEntity> config) {
-    switch (mTaskEntity.getRequestType()) {
-      case AbsTaskEntity.D_FTP:
-      case AbsTaskEntity.D_FTP_DIR:
+    switch (mTaskEntity.requestType) {
+      case AbsTaskEntity.FTP:
+      case AbsTaskEntity.FTP_DIR:
         return new FtpThreadTask(mConstance, (IDownloadListener) mListener, config);
-      case AbsTaskEntity.D_HTTP:
+      case AbsTaskEntity.HTTP:
         return new HttpThreadTask(mConstance, (IDownloadListener) mListener, config);
     }
     return null;
   }
-
-  private void failDownload(String errorMsg) {
-    closeTimer();
-    ALog.e(TAG, errorMsg);
-    mConstance.isRunning = false;
-    mListener.onFail(false);
-    ErrorHelp.saveError(TAG, "", errorMsg);
-  }
 }

+ 118 - 0
Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpClientHelp.java

@@ -0,0 +1,118 @@
+/*
+ * 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.downloader;
+
+import android.text.TextUtils;
+import android.util.Log;
+import com.arialyy.aria.core.AriaManager;
+import java.io.IOException;
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPReply;
+
+/**
+ * Created by Aria.Lao on 2017/7/26.
+ */
+public class FtpClientHelp {
+  private final String TAG = "FtpClientHelp";
+  private static volatile FtpClientHelp INSTANCE = null;
+
+  private FTPClient client;
+  private String serverIp, user, pw, account;
+  private int port;
+
+  private FtpClientHelp() {
+  }
+
+  public static FtpClientHelp getInstnce() {
+    if (INSTANCE == null) {
+      synchronized (AriaManager.LOCK) {
+        INSTANCE = new FtpClientHelp();
+      }
+    }
+    return INSTANCE;
+  }
+
+  public FTPClient getClient() {
+    if (client == null || !client.isConnected()) {
+      createClient();
+    }
+    return client;
+  }
+
+  /**
+   * 登录到FTP服务器,当客户端为null或客户端没有连接到FTP服务器时才会执行登录操作
+   */
+  public FTPClient login(String serverIp, int port, String user, String pw, String account) {
+    this.serverIp = serverIp;
+    this.port = port;
+    this.user = user;
+    this.pw = pw;
+    this.account = account;
+    if (client == null || !client.isConnected()) {
+      createClient();
+    }
+    return client;
+  }
+
+  /**
+   * 登出
+   */
+  public void logout() {
+    try {
+      if (client != null && client.isConnected()) {
+        client.logout();
+      }
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  FTPClient createClient() {
+    new Thread(new Runnable() {
+      @Override public void run() {
+        client = new FTPClient();
+        try {
+          client.connect(serverIp, port);
+          if (!TextUtils.isEmpty(account)) {
+            client.login(user, pw);
+          } else {
+            client.login(user, pw, account);
+          }
+          int reply = client.getReplyCode();
+          if (!FTPReply.isPositiveCompletion(reply)) {
+            client.disconnect();
+            Log.e(TAG, "无法连接到ftp服务器,错误码为:" + reply);
+          }
+        } catch (IOException e) {
+          Log.d(TAG, e.getMessage());
+        } finally {
+          synchronized (FtpClientHelp.this) {
+            FtpClientHelp.this.notify();
+          }
+        }
+      }
+    }).start();
+    synchronized (FtpClientHelp.this) {
+      try {
+        wait();
+      } catch (InterruptedException e) {
+        e.printStackTrace();
+      }
+    }
+
+    return client;
+  }
+}

+ 14 - 33
Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java

@@ -15,11 +15,9 @@
  */
 package com.arialyy.aria.core.download.downloader;
 
-import com.arialyy.aria.core.common.CompleteInfo;
-import com.arialyy.aria.core.common.OnFileInfoCallback;
+import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.util.ErrorHelp;
 import java.util.Set;
 
 /**
@@ -27,61 +25,44 @@ import java.util.Set;
  * ftp文件夹下载工具
  */
 public class FtpDirDownloadUtil extends AbsGroupUtil {
-  private String TAG = "FtpDirDownloadUtil";
-
   public FtpDirDownloadUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
     super(listener, taskEntity);
   }
 
-  @Override int getTaskType() {
-    return FTP_DIR;
-  }
-
   @Override protected void onStart() {
     super.onStart();
-    if (mGTEntity.getEntity().getFileSize() > 1) {
-      onPre();
+    if (mTaskEntity.getEntity().getFileSize() > 1) {
       startDownload();
     } else {
-      new FtpDirInfoThread(mGTEntity, new OnFileInfoCallback() {
-        @Override public void onComplete(String url, CompleteInfo info) {
-          if (info.code >= 200 && info.code < 300) {
-            onPre();
+      new FtpDirInfoThread(mTaskEntity, new OnFileInfoCallback() {
+        @Override public void onComplete(String url, int code) {
+          if (code >= 200 && code < 300) {
+            mTotalSize = mTaskEntity.getEntity().getFileSize();
+            for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) {
+              mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
+            }
+            mActualTaskNum = mTaskEntity.entity.getSubTask().size();
             startDownload();
           }
         }
 
-        @Override public void onFail(String url, String errorMsg, boolean needRetry) {
-          DownloadTaskEntity te = mExeMap.get(url);
-          if (te != null) {
-            mFailMap.put(url, te);
-            mExeMap.remove(url);
-          }
-          mListener.onFail(needRetry);
-          ErrorHelp.saveError(TAG, "", errorMsg);
+        @Override public void onFail(String url, String errorMsg) {
+          mListener.onFail();
         }
       }).start();
     }
   }
 
   private void startDownload() {
-    if (mCompleteNum == mGroupSize) {
-      mListener.onComplete();
-      return;
-    }
     int i = 0;
     Set<String> keys = mExeMap.keySet();
     for (String key : keys) {
       DownloadTaskEntity taskEntity = mExeMap.get(key);
       if (taskEntity != null) {
-        createChildDownload(taskEntity);
+        startChildDownload(taskEntity);
         i++;
       }
     }
-    if (mExeMap.size() == 0) {
-      mListener.onComplete();
-    } else if (i == mExeMap.size()) {
-      startRunningFlow();
-    }
+    if (i == mExeMap.size()) startRunningFlow();
   }
 }

+ 11 - 36
Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java

@@ -15,15 +15,9 @@
  */
 package com.arialyy.aria.core.download.downloader;
 
-import com.arialyy.aria.core.FtpUrlEntity;
-import com.arialyy.aria.core.common.AbsFtpInfoThread;
-import com.arialyy.aria.core.common.CompleteInfo;
-import com.arialyy.aria.core.common.OnFileInfoCallback;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadGroupEntity;
 import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
-import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.util.CommonUtil;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
@@ -34,60 +28,41 @@ import org.apache.commons.net.ftp.FTPFile;
  * 获取ftp文件夹信息
  */
 class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGroupTaskEntity> {
+  private long mSize = 0;
 
   FtpDirInfoThread(DownloadGroupTaskEntity taskEntity, OnFileInfoCallback callback) {
     super(taskEntity, callback);
   }
 
-  @Override protected String setRemotePath() {
-    return mTaskEntity.getUrlEntity().remotePath;
-  }
-
-  @Override protected void handleFile(String remotePath, FTPFile ftpFile) {
+  @Override void handleFile(String remotePath, FTPFile ftpFile) {
     super.handleFile(remotePath, ftpFile);
+    mSize += ftpFile.getSize();
     addEntity(remotePath, ftpFile);
   }
 
-  @Override protected void onPreComplete(int code) {
-    super.onPreComplete(code);
+  @Override protected void onPreComplete() {
+    super.onPreComplete();
     mEntity.setFileSize(mSize);
-    mCallback.onComplete(mEntity.getKey(), new CompleteInfo(code));
   }
 
-  /**
-   * FTP文件夹的子任务实体 在这生成
-   */
   private void addEntity(String remotePath, FTPFile ftpFile) {
-    final FtpUrlEntity urlEntity = mTaskEntity.getUrlEntity().clone();
     DownloadEntity entity = new DownloadEntity();
-    entity.setUrl(
-        urlEntity.protocol + "://" + urlEntity.hostName + ":" + urlEntity.port + "/" + remotePath);
+    entity.setUrl("ftp://" + mTaskEntity.serverIp + ":" + mTaskEntity.port + remotePath);
     entity.setDownloadPath(mEntity.getDirPath() + "/" + remotePath);
     int lastIndex = remotePath.lastIndexOf("/");
     String fileName = lastIndex < 0 ? CommonUtil.keyToHashKey(remotePath)
         : remotePath.substring(lastIndex + 1, remotePath.length());
-    entity.setFileName(new String(fileName.getBytes(), Charset.forName(mTaskEntity.getCharSet())));
+    entity.setFileName(new String(fileName.getBytes(), Charset.forName(mTaskEntity.charSet)));
     entity.setGroupName(mEntity.getGroupName());
     entity.setGroupChild(true);
     entity.setFileSize(ftpFile.getSize());
     entity.insert();
-
-    DownloadTaskEntity taskEntity = new DownloadTaskEntity();
-    taskEntity.setKey(entity.getDownloadPath());
-    taskEntity.setUrl(entity.getUrl());
-    taskEntity.setEntity(entity);
-    taskEntity.setGroupTask(true);
-    taskEntity.setGroupName(mEntity.getGroupName());
-    taskEntity.setRequestType(AbsTaskEntity.D_FTP);
-    urlEntity.url = entity.getUrl();
-    urlEntity.remotePath = remotePath;
-    taskEntity.setUrlEntity(urlEntity);
-    taskEntity.insert();
-
     if (mEntity.getUrls() == null) {
       mEntity.setUrls(new ArrayList<String>());
     }
-    mEntity.getSubEntities().add(entity);
-    mTaskEntity.getSubTaskEntities().add(taskEntity);
+    if (mEntity.getSubTask() == null) {
+      mEntity.setSubTasks(new ArrayList<DownloadEntity>());
+    }
+    mEntity.getSubTask().add(entity);
   }
 }

+ 0 - 16
Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java

@@ -15,9 +15,6 @@
  */
 package com.arialyy.aria.core.download.downloader;
 
-import com.arialyy.aria.core.common.AbsFtpInfoThread;
-import com.arialyy.aria.core.common.CompleteInfo;
-import com.arialyy.aria.core.common.OnFileInfoCallback;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 
@@ -30,17 +27,4 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEnt
   FtpFileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) {
     super(taskEntity, callback);
   }
-
-  @Override protected String setRemotePath() {
-    return mTaskEntity.getUrlEntity().remotePath;
-  }
-
-  @Override protected void onPreComplete(int code) {
-    super.onPreComplete(code);
-    if (mSize != mTaskEntity.getEntity().getFileSize()) {
-      mTaskEntity.setNewTask(true);
-    }
-    mEntity.setFileSize(mSize);
-    mCallback.onComplete(mEntity.getUrl(), new CompleteInfo(code));
-  }
 }

+ 45 - 53
Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java

@@ -15,17 +15,19 @@
  */
 package com.arialyy.aria.core.download.downloader;
 
-import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.common.AbsFtpThreadTask;
+import android.text.TextUtils;
+import android.util.Log;
+import com.arialyy.aria.core.common.AbsThreadTask;
 import com.arialyy.aria.core.common.StateConstance;
 import com.arialyy.aria.core.common.SubThreadConfig;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.IDownloadListener;
-import com.arialyy.aria.util.ALog;
 import com.arialyy.aria.util.BufferedRandomAccessFile;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import org.apache.commons.net.ftp.FTP;
 import org.apache.commons.net.ftp.FTPClient;
 import org.apache.commons.net.ftp.FTPReply;
 
@@ -33,34 +35,20 @@ import org.apache.commons.net.ftp.FTPReply;
  * Created by Aria.Lao on 2017/7/24.
  * Ftp下载任务
  */
-class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> {
+class FtpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> {
   private final String TAG = "FtpThreadTask";
-  private boolean isOpenDynamicFile;
-  /**
-   * 2M的动态长度
-   */
-  private final int LEN_INTERVAL = 1024 * 1024 * 2;
 
   FtpThreadTask(StateConstance constance, IDownloadListener listener,
       SubThreadConfig<DownloadTaskEntity> downloadInfo) {
     super(constance, listener, downloadInfo);
-    AriaManager manager = AriaManager.getInstance(AriaManager.APP);
-    mConnectTimeOut = manager.getDownloadConfig().getConnectTimeOut();
-    mReadTimeOut = manager.getDownloadConfig().getIOTimeOut();
-    mBufSize = manager.getDownloadConfig().getBuffSize();
-    isNotNetRetry = manager.getDownloadConfig().isNotNetRetry();
-    isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile;
-    setMaxSpeed(manager.getDownloadConfig().getMaxSpeed());
   }
 
   @Override public void run() {
-    //当前子线程的下载位置
-    mChildCurrentLocation = mConfig.START_LOCATION;
     FTPClient client = null;
     InputStream is = null;
     BufferedRandomAccessFile file = null;
     try {
-      ALog.d(TAG, "任务【"
+      Log.d(TAG, "任务【"
           + mConfig.TEMP_FILE.getName()
           + "】线程__"
           + mConfig.THREAD_ID
@@ -69,46 +57,55 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
           + ",结束位置:"
           + mConfig.END_LOCATION
           + "】");
-      client = createClient();
-      if (client == null) return;
-      if (mConfig.START_LOCATION > 0) {
-        client.setRestartOffset(mConfig.START_LOCATION);
+      String url = mEntity.getUrl();
+      String[] pp = url.split("/")[2].split(":");
+      String serverIp = pp[0];
+      int port = Integer.parseInt(pp[1]);
+      String remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
+      client = new FTPClient();
+      client.connect(serverIp, port);
+      if (!TextUtils.isEmpty(mTaskEntity.account)) {
+        client.login(mTaskEntity.userName, mTaskEntity.userPw);
+      } else {
+        client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
       }
-      //发送第二次指令时,还需要再做一次判断
       int reply = client.getReplyCode();
-      if (!FTPReply.isPositivePreliminary(reply) && reply != FTPReply.COMMAND_OK) {
-        fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply + ",msg:" + client.getReplyString(),
-            null);
+      if (!FTPReply.isPositiveCompletion(reply)) {
         client.disconnect();
+        fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null);
         return;
       }
-      String remotePath =
-          new String(mTaskEntity.getUrlEntity().remotePath.getBytes(charSet), SERVER_CHARSET);
-      ALog.i(TAG, "remotePath【" + remotePath + "】");
-      is = client.retrieveFileStream(remotePath);
+      String charSet = "UTF-8";
+      // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
+      if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
+          client.sendCommand("OPTS UTF8", "ON"))) {
+        charSet = mTaskEntity.charSet;
+      }
+      client.setControlEncoding(charSet);
+      client.setDataTimeout(STATE.READ_TIME_OUT);
+      client.enterLocalPassiveMode();
+      client.setFileType(FTP.BINARY_FILE_TYPE);
+      client.setRestartOffset(mConfig.START_LOCATION);
+      client.allocate(mBufSize);
+      is = client.retrieveFileStream(
+          new String(remotePath.getBytes(charSet), SERVER_CHARSET));
+      //发送第二次指令时,还需要再做一次判断
       reply = client.getReplyCode();
       if (!FTPReply.isPositivePreliminary(reply)) {
-        fail(mChildCurrentLocation, "获取流失败,错误码为:" + reply + ",msg:" + client.getReplyString(),
-            null);
         client.disconnect();
+        fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply, null);
         return;
       }
-
       file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
       file.seek(mConfig.START_LOCATION);
       byte[] buffer = new byte[mBufSize];
       int len;
-
+      //当前子线程的下载位置
+      mChildCurrentLocation = mConfig.START_LOCATION;
       while ((len = is.read(buffer)) != -1) {
-        if (STATE.isCancel || STATE.isStop) {
-          break;
-        }
+        if (STATE.isCancel) break;
+        if (STATE.isStop) break;
         if (mSleepTime > 0) Thread.sleep(mSleepTime);
-        if (isOpenDynamicFile) {
-          file.setLength(
-              STATE.CURRENT_LOCATION + LEN_INTERVAL < mEntity.getFileSize() ? STATE.CURRENT_LOCATION
-                  + LEN_INTERVAL : mEntity.getFileSize());
-        }
         if (mChildCurrentLocation + len >= mConfig.END_LOCATION) {
           len = (int) (mConfig.END_LOCATION - mChildCurrentLocation);
           file.write(buffer, 0, len);
@@ -120,18 +117,17 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
         }
       }
       if (STATE.isCancel || STATE.isStop) return;
-      ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕");
+      Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕");
       writeConfig(true, 1);
       STATE.COMPLETE_THREAD_NUM++;
       if (STATE.isComplete()) {
-        STATE.TASK_RECORD.deleteData();
+        File configFile = new File(mConfigFPath);
+        if (configFile.exists()) {
+          configFile.delete();
+        }
         STATE.isRunning = false;
         mListener.onComplete();
       }
-      if (STATE.isFail()) {
-        STATE.isRunning = false;
-        mListener.onFail(false);
-      }
     } catch (IOException e) {
       fail(mChildCurrentLocation, "下载失败【" + mConfig.URL + "】", e);
     } catch (Exception e) {
@@ -152,8 +148,4 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
       }
     }
   }
-
-  @Override protected String getTaskType() {
-    return "FTP_DOWNLOAD";
-  }
 }

+ 40 - 115
Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java

@@ -16,18 +16,13 @@
 package com.arialyy.aria.core.download.downloader;
 
 import android.text.TextUtils;
+import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.common.CompleteInfo;
-import com.arialyy.aria.core.common.OnFileInfoCallback;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.util.ALog;
-import com.arialyy.aria.util.CheckUtil;
+import com.arialyy.aria.core.download.downloader.ConnectionHelp;
 import com.arialyy.aria.util.CommonUtil;
-import java.io.BufferedReader;
-import java.io.File;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLDecoder;
@@ -53,12 +48,11 @@ class HttpFileInfoThread implements Runnable {
   @Override public void run() {
     HttpURLConnection conn = null;
     try {
-      URL url = new URL(CommonUtil.convertUrl(mEntity.getUrl()));
+      URL url = new URL(mEntity.getUrl());
       conn = ConnectionHelp.handleConnection(url);
       conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
       conn.setRequestProperty("Range", "bytes=" + 0 + "-");
       conn.setConnectTimeout(mConnectTimeOut);
-      //conn.setChunkedStreamingMode(0);
       conn.connect();
       handleConnect(conn);
     } catch (IOException e) {
@@ -67,7 +61,7 @@ class HttpFileInfoThread implements Runnable {
           + "】\n【filePath:"
           + mEntity.getDownloadPath()
           + "】\n"
-          + ALog.getExceptionString(e), true);
+          + CommonUtil.getPrintException(e));
     } finally {
       if (conn != null) {
         conn.disconnect();
@@ -78,136 +72,70 @@ class HttpFileInfoThread implements Runnable {
   private void handleConnect(HttpURLConnection conn) throws IOException {
     long len = conn.getContentLength();
     if (len < 0) {
-      String temp = conn.getHeaderField("Content-Length");
+      String temp = conn.getHeaderField(mTaskEntity.contentLength);
       len = TextUtils.isEmpty(temp) ? -1 : Long.parseLong(temp);
-      // 某些服务,如果设置了conn.setRequestProperty("Range", "bytes=" + 0 + "-");
-      // 会返回 Content-Range: bytes 0-225427911/225427913
-      if (len < 0) {
-        temp = conn.getHeaderField("Content-Range");
-        if (TextUtils.isEmpty(temp)) {
-          len = -1;
-        } else {
-          int start = temp.indexOf("/");
-          len = Long.parseLong(temp.substring(start + 1, temp.length()));
-        }
-      }
     }
     int code = conn.getResponseCode();
-    boolean end = false;
+    boolean isComplete = false;
     if (TextUtils.isEmpty(mEntity.getMd5Code())) {
-      String md5Code = conn.getHeaderField("Content-MD5");
+      String md5Code = conn.getHeaderField(mTaskEntity.md5Key);
       mEntity.setMd5Code(md5Code);
     }
-
-    boolean isChunked = false;
-    final String str = conn.getHeaderField("Transfer-Encoding");
-    if (!TextUtils.isEmpty(str) && str.equals("chunked")) {
-      isChunked = true;
-    }
+    String disposition = conn.getHeaderField(mTaskEntity.dispositionKey);
     //Map<String, List<String>> headers = conn.getHeaderFields();
-    String disposition = conn.getHeaderField("Content-Disposition");
-    if (mTaskEntity.isUseServerFileName() && !TextUtils.isEmpty(disposition)) {
+    if (!TextUtils.isEmpty(disposition)) {
       mEntity.setDisposition(CommonUtil.encryptBASE64(disposition));
-      if (disposition.contains(";")) {
-        String[] infos = disposition.split(";");
-        for (String info : infos) {
-          if (info.startsWith("filename") && info.contains("=")) {
-            String[] temp = info.split("=");
-            if (temp.length > 1) {
-              String newName = URLDecoder.decode(temp[1], "utf-8");
-              mEntity.setServerFileName(newName);
-              fileRename(newName);
-              break;
-            }
-          }
-        }
+      if (disposition.contains(mTaskEntity.dispositionFileKey)) {
+        String[] infos = disposition.split("=");
+        mEntity.setServerFileName(URLDecoder.decode(infos[1], "utf-8"));
       }
     }
 
-    mTaskEntity.setCode(code);
+    mTaskEntity.code = code;
     if (code == HttpURLConnection.HTTP_PARTIAL) {
-      if (!checkLen(len) && !isChunked) {
-        return;
-      }
+      if (!checkLen(len)) return;
       mEntity.setFileSize(len);
-      mTaskEntity.setSupportBP(true);
-      end = true;
+      mTaskEntity.isSupportBP = true;
+      isComplete = true;
     } else if (code == HttpURLConnection.HTTP_OK) {
-      if (conn.getHeaderField("Content-Type").equals("text/html")) {
-        BufferedReader reader =
-            new BufferedReader(new InputStreamReader(ConnectionHelp.convertInputStream(conn)));
-        StringBuilder sb = new StringBuilder();
-        String line;
-        while ((line = reader.readLine()) != null) {
-          sb.append(line);
-        }
-        reader.close();
-        handleUrlReTurn(conn, CommonUtil.getWindowReplaceUrl(sb.toString()));
-        return;
-      } else if (!checkLen(len) && !isChunked) {
-        return;
-      }
+      if (!checkLen(len)) return;
       mEntity.setFileSize(len);
-      mTaskEntity.setNewTask(true);
-      mTaskEntity.setSupportBP(false);
-      end = true;
+      mTaskEntity.isSupportBP = false;
+      isComplete = true;
     } else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
-      failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:404", true);
+      failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:404");
     } else if (code == HttpURLConnection.HTTP_MOVED_TEMP
         || code == HttpURLConnection.HTTP_MOVED_PERM
         || code == 307
         || code == HttpURLConnection.HTTP_SEE_OTHER) {
-      handleUrlReTurn(conn, conn.getHeaderField("Location"));
+      mTaskEntity.redirectUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
+      mEntity.setRedirect(true);
+      mEntity.setRedirectUrl(mTaskEntity.redirectUrl);
+      handle302Turn(conn);
     } else {
-      failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code, true);
+      failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code);
     }
-    if (end) {
-      mTaskEntity.setChunked(isChunked);
-      mTaskEntity.update();
+    if (isComplete) {
       if (onFileInfoListener != null) {
-        CompleteInfo info = new CompleteInfo(code);
-        onFileInfoListener.onComplete(mEntity.getUrl(), info);
+        onFileInfoListener.onComplete(mEntity.getUrl(), code);
       }
+      mEntity.update();
+      mTaskEntity.update();
     }
   }
 
   /**
-   * 重命名文件
-   */
-  private void fileRename(String newName) {
-    if (TextUtils.isEmpty(newName)) {
-      ALog.w(TAG, "重命名失败【服务器返回的文件名为空】");
-      return;
-    }
-    File oldFile = new File(mEntity.getDownloadPath());
-    String newPath = oldFile.getParent() + "/" + newName;
-    if (oldFile.exists()) {
-      oldFile.renameTo(new File(newPath));
-    }
-    mEntity.setFileName(newName);
-    mEntity.setDownloadPath(newPath);
-    mTaskEntity.setKey(newPath);
-  }
-
-  /**
    * 处理30x跳转
    */
-  private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException {
-    ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】");
-    if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null") || !newUrl.startsWith(
-        "http")) {
+  private void handle302Turn(HttpURLConnection conn) throws IOException {
+    String newUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
+    Log.d(TAG, "30x跳转,location【 " + mTaskEntity.redirectUrlKey + "】" + "新url为【" + newUrl + "】");
+    if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) {
       if (onFileInfoListener != null) {
-        onFileInfoListener.onFail(mEntity.getUrl(), "获取重定向链接失败", false);
+        onFileInfoListener.onFail(mEntity.getUrl(), "获取重定向链接失败");
       }
       return;
     }
-    if (!CheckUtil.checkUrl(newUrl)) {
-      failDownload("下载失败,重定向url错误", false);
-      return;
-    }
-    mTaskEntity.setRedirectUrl(newUrl);
-    mEntity.setRedirect(true);
-    mEntity.setRedirectUrl(newUrl);
     String cookies = conn.getHeaderField("Set-Cookie");
     conn = (HttpURLConnection) new URL(newUrl).openConnection();
     conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
@@ -220,26 +148,23 @@ class HttpFileInfoThread implements Runnable {
   }
 
   /**
-   * 检查长度是否合法,并且检查新获取的文件长度是否和数据库的文件长度一直,如果不一致,则表示该任务为新任务
+   * 检查长度是否合法
    *
    * @param len 从服务器获取的文件长度
-   * @return {@code true}合法
+   * @return true, 合法
    */
   private boolean checkLen(long len) {
-    if (len != mEntity.getFileSize()) {
-      mTaskEntity.setNewTask(true);
-    }
     if (len < 0) {
-      failDownload("任务【" + mEntity.getUrl() + "】下载失败,文件长度小于0", true);
+      failDownload("任务【" + mEntity.getUrl() + "】下载失败,文件长度小于0");
       return false;
     }
     return true;
   }
 
-  private void failDownload(String errorMsg, boolean needRetry) {
-    ALog.e(TAG, errorMsg);
+  private void failDownload(String errorMsg) {
+    Log.e(TAG, errorMsg);
     if (onFileInfoListener != null) {
-      onFileInfoListener.onFail(mEntity.getUrl(), errorMsg, needRetry);
+      onFileInfoListener.onFail(mEntity.getUrl(), errorMsg);
     }
   }
 }

+ 37 - 104
Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java

@@ -15,17 +15,15 @@
  */
 package com.arialyy.aria.core.download.downloader;
 
-import com.arialyy.aria.core.AriaManager;
+import android.util.Log;
 import com.arialyy.aria.core.common.AbsThreadTask;
 import com.arialyy.aria.core.common.StateConstance;
 import com.arialyy.aria.core.common.SubThreadConfig;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.IDownloadListener;
-import com.arialyy.aria.util.ALog;
 import com.arialyy.aria.util.BufferedRandomAccessFile;
-import com.arialyy.aria.util.CommonUtil;
-import java.io.BufferedInputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
@@ -38,35 +36,21 @@ import java.net.URL;
  */
 final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> {
   private final String TAG = "HttpThreadTask";
-  /**
-   * 2M的动态长度
-   */
-  private final int LEN_INTERVAL = 1024 * 1024 * 2;
-  private boolean isOpenDynamicFile;
 
   HttpThreadTask(StateConstance constance, IDownloadListener listener,
       SubThreadConfig<DownloadTaskEntity> downloadInfo) {
     super(constance, listener, downloadInfo);
-    AriaManager manager = AriaManager.getInstance(AriaManager.APP);
-    mConnectTimeOut = manager.getDownloadConfig().getConnectTimeOut();
-    mReadTimeOut = manager.getDownloadConfig().getIOTimeOut();
-    mBufSize = manager.getDownloadConfig().getBuffSize();
-    isNotNetRetry = manager.getDownloadConfig().isNotNetRetry();
-    isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile;
-    setMaxSpeed(manager.getDownloadConfig().getMaxSpeed());
   }
 
   @Override public void run() {
     HttpURLConnection conn = null;
-    BufferedInputStream is = null;
+    InputStream is = null;
     BufferedRandomAccessFile file = null;
-    //当前子线程的下载位置
-    mChildCurrentLocation = mConfig.START_LOCATION;
     try {
-      URL url = new URL(CommonUtil.convertUrl(mConfig.URL));
+      URL url = new URL(mConfig.URL);
       conn = ConnectionHelp.handleConnection(url);
       if (mConfig.SUPPORT_BP) {
-        ALog.d(TAG, "任务【"
+        Log.d(TAG, "任务【"
             + mConfig.TEMP_FILE.getName()
             + "】线程__"
             + mConfig.THREAD_ID
@@ -79,28 +63,46 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
         conn.setRequestProperty("Range",
             "bytes=" + mConfig.START_LOCATION + "-" + (mConfig.END_LOCATION - 1));
       } else {
-        ALog.w(TAG, "该下载不支持断点");
+        Log.w(TAG, "该下载不支持断点");
       }
       conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn);
-      conn.setConnectTimeout(mConnectTimeOut);
-      conn.setReadTimeout(mReadTimeOut);  //设置读取流的等待时间,必须设置该参数
-
-      is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
+      conn.setConnectTimeout(STATE.CONNECT_TIME_OUT);
+      conn.setReadTimeout(STATE.READ_TIME_OUT);  //设置读取流的等待时间,必须设置该参数
+      is = conn.getInputStream();
       //创建可设置位置的文件
       file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
       //设置每条线程写入文件的位置
       file.seek(mConfig.START_LOCATION);
-
-      if (mTaskEntity.isChunked()) {
-        readChunk(is, file);
-      } else {
-        readNormal(is, file);
+      byte[] buffer = new byte[mBufSize];
+      int len;
+      //当前子线程的下载位置
+      mChildCurrentLocation = mConfig.START_LOCATION;
+      while ((len = is.read(buffer)) != -1) {
+        if (STATE.isCancel) break;
+        if (STATE.isStop) break;
+        if (mSleepTime > 0) Thread.sleep(mSleepTime);
+        file.write(buffer, 0, len);
+        progress(len);
       }
-
-      if (STATE.isCancel || STATE.isStop) {
-        return;
+      if (STATE.isCancel || STATE.isStop) return;
+      //支持断点的处理
+      if (mConfig.SUPPORT_BP) {
+        Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕");
+        writeConfig(true, 1);
+        STATE.COMPLETE_THREAD_NUM++;
+        if (STATE.isComplete()) {
+          File configFile = new File(mConfigFPath);
+          if (configFile.exists()) {
+            configFile.delete();
+          }
+          STATE.isRunning = false;
+          mListener.onComplete();
+        }
+      } else {
+        Log.i(TAG, "下载任务完成");
+        STATE.isRunning = false;
+        mListener.onComplete();
       }
-      handleComplete();
     } catch (MalformedURLException e) {
       fail(mChildCurrentLocation, "下载链接异常", e);
     } catch (IOException e) {
@@ -123,73 +125,4 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
       }
     }
   }
-
-  /**
-   * 读取chunk模式的文件流
-   *
-   * @deprecated 暂时先这样处理,无chun
-   */
-  private void readChunk(InputStream is, BufferedRandomAccessFile file)
-      throws IOException, InterruptedException {
-    readNormal(is, file);
-  }
-
-  /**
-   * 读取普通的文件流
-   */
-  private void readNormal(InputStream is, BufferedRandomAccessFile file)
-      throws IOException, InterruptedException {
-    byte[] buffer = new byte[mBufSize];
-    int len;
-    while ((len = is.read(buffer)) != -1) {
-      if (STATE.isCancel || STATE.isStop) {
-        break;
-      }
-      if (mSleepTime > 0) {
-        Thread.sleep(mSleepTime);
-      }
-      if (isOpenDynamicFile) {
-        file.setLength(
-            STATE.CURRENT_LOCATION + LEN_INTERVAL < mEntity.getFileSize() ? STATE.CURRENT_LOCATION
-                + LEN_INTERVAL : mEntity.getFileSize());
-      }
-      file.write(buffer, 0, len);
-      progress(len);
-    }
-  }
-
-  /**
-   * 处理完成配置文件的更新或事件回调
-   *
-   * @throws IOException
-   */
-  private void handleComplete() throws IOException {
-    //支持断点的处理
-    if (mConfig.SUPPORT_BP) {
-      if (mChildCurrentLocation == mConfig.END_LOCATION) {
-        ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕");
-        writeConfig(true, 1);
-        STATE.COMPLETE_THREAD_NUM++;
-        if (STATE.isComplete()) {
-          STATE.TASK_RECORD.deleteData();
-          STATE.isRunning = false;
-          mListener.onComplete();
-        }
-      } else {
-        STATE.FAIL_NUM++;
-      }
-      if (STATE.isFail()) {
-        STATE.isRunning = false;
-        mListener.onFail(false);
-      }
-    } else {
-      ALog.i(TAG, "任务下载完成");
-      STATE.isRunning = false;
-      mListener.onComplete();
-    }
-  }
-
-  @Override protected String getTaskType() {
-    return "HTTP_DOWNLOAD";
-  }
 }

+ 1 - 10
Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadGroupListener.java

@@ -17,6 +17,7 @@ package com.arialyy.aria.core.download.downloader;
 
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.inf.IDownloadListener;
+import com.arialyy.aria.core.inf.IEventListener;
 
 /**
  * Created by Aria.Lao on 2017/7/20.
@@ -25,11 +26,6 @@ import com.arialyy.aria.core.inf.IDownloadListener;
 public interface IDownloadGroupListener extends IDownloadListener {
 
   /**
-   * 子任务预处理
-   */
-  void onSubPre(DownloadEntity subEntity);
-
-  /**
    * 子任务支持断点回调
    *
    * @param support true,支持;false 不支持
@@ -60,9 +56,4 @@ public interface IDownloadGroupListener extends IDownloadListener {
    * 子任务取消下载
    */
   void onSubCancel(DownloadEntity subEntity);
-
-  /**
-   * 子任务执行中
-   */
-  void onSubRunning(DownloadEntity subEntity);
 }

+ 17 - 0
Aria/src/main/java/com/arialyy/aria/core/download/downloader/OnFileInfoCallback.java

@@ -0,0 +1,17 @@
+package com.arialyy.aria.core.download.downloader;
+
+interface OnFileInfoCallback {
+  /**
+   * 处理完成
+   *
+   * @param code 状态码
+   */
+  void onComplete(String url, int code);
+
+  /**
+   * 请求失败
+   *
+   * @param errorMsg 错误信息
+   */
+  void onFail(String url, String errorMsg);
+}

+ 14 - 22
Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java

@@ -16,21 +16,17 @@
 
 package com.arialyy.aria.core.download.downloader;
 
-import com.arialyy.aria.core.common.CompleteInfo;
 import com.arialyy.aria.core.common.IUtil;
-import com.arialyy.aria.core.common.OnFileInfoCallback;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IDownloadListener;
-import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.util.ErrorHelp;
 
 /**
  * Created by lyy on 2015/8/25.
- * D_HTTP\FTP单任务下载工具
+ * HTTP单任务下载工具
  */
 public class SimpleDownloadUtil implements IUtil, Runnable {
-  private String TAG = "SimpleDownloadUtil";
+  private static final String TAG = "SimpleDownloadUtil";
   private IDownloadListener mListener;
   private Downloader mDownloader;
   private DownloadTaskEntity mTaskEntity;
@@ -85,17 +81,13 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
     mDownloader.setMaxSpeed(maxSpeed);
   }
 
-  private void failDownload(String msg, boolean needRetry) {
-    mListener.onFail(needRetry);
-    ErrorHelp.saveError(TAG, msg, "");
+  private void failDownload(String msg) {
+    mListener.onFail();
   }
 
   @Override public void run() {
     mListener.onPre();
-    if (mTaskEntity.getEntity().getFileSize() <= 1
-        || mTaskEntity.isRefreshInfo()
-        || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP
-        || mTaskEntity.getState() == IEntity.STATE_FAIL) {
+    if (mTaskEntity.getEntity().getFileSize() <= 1) {
       new Thread(createInfoThread()).start();
     } else {
       mDownloader.start();
@@ -106,25 +98,25 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
    * 通过链接类型创建不同的获取文件信息的线程
    */
   private Runnable createInfoThread() {
-    switch (mTaskEntity.getRequestType()) {
-      case AbsTaskEntity.D_FTP:
+    switch (mTaskEntity.requestType) {
+      case AbsTaskEntity.FTP:
         return new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
-          @Override public void onComplete(String url, CompleteInfo info) {
+          @Override public void onComplete(String url, int code) {
             mDownloader.start();
           }
 
-          @Override public void onFail(String url, String errorMsg, boolean needRetry) {
-            failDownload(errorMsg, needRetry);
+          @Override public void onFail(String url, String errorMsg) {
+            failDownload(errorMsg);
           }
         });
-      case AbsTaskEntity.D_HTTP:
+      case AbsTaskEntity.HTTP:
         return new HttpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
-          @Override public void onComplete(String url, CompleteInfo info) {
+          @Override public void onComplete(String url, int code) {
             mDownloader.start();
           }
 
-          @Override public void onFail(String url, String errorMsg, boolean needRetry) {
-            failDownload(errorMsg, needRetry);
+          @Override public void onFail(String url, String errorMsg) {
+            failDownload(errorMsg);
           }
         });
     }

+ 0 - 44
Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGEWrapper.java

@@ -1,44 +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.download.wrapper;
-
-import com.arialyy.aria.core.download.DownloadEntity;
-import com.arialyy.aria.core.download.DownloadGroupEntity;
-import com.arialyy.aria.orm.AbsWrapper;
-import com.arialyy.aria.orm.annotation.Many;
-import com.arialyy.aria.orm.annotation.One;
-import com.arialyy.aria.orm.annotation.Wrapper;
-import java.util.List;
-
-/**
- * Created by laoyuyu on 2018/3/30.
- * 任务组实体和子任务实体的关系
- */
-@Wrapper
-public class DGEWrapper extends AbsWrapper {
-
-  @One
-  public DownloadGroupEntity groupEntity;
-
-  @Many(parentColumn = "groupName", entityColumn = "groupName")
-  public List<DownloadEntity> subEntity;
-
-  @Override protected void handleConvert() {
-    if (subEntity != null && !subEntity.isEmpty()) {
-      groupEntity.setSubEntities(subEntity);
-    }
-  }
-}

+ 0 - 44
Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGSTEWrapper.java

@@ -1,44 +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.download.wrapper;
-
-import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
-import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.orm.AbsWrapper;
-import com.arialyy.aria.orm.annotation.Many;
-import com.arialyy.aria.orm.annotation.One;
-import com.arialyy.aria.orm.annotation.Wrapper;
-import java.util.List;
-
-/**
- * Created by laoyuyu on 2018/4/11.
- * 任务组任务实体和任务组任务实体的子任务实体对应关系
- */
-@Wrapper
-public class DGSTEWrapper extends AbsWrapper {
-
-  @One
-  public DownloadGroupTaskEntity dgTaskEntity;
-
-  @Many(parentColumn = "key", entityColumn = "groupName")
-  public List<DownloadTaskEntity> subTaskEntity;
-
-  @Override protected void handleConvert() {
-    if (subTaskEntity != null && !subTaskEntity.isEmpty()) {
-      dgTaskEntity.setSubTaskEntities(subTaskEntity);
-    }
-  }
-}

+ 0 - 65
Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGTEWrapper.java

@@ -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.download.wrapper;
-
-import com.arialyy.aria.core.download.DownloadGroupEntity;
-import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
-import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.orm.AbsWrapper;
-import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.orm.annotation.Many;
-import com.arialyy.aria.orm.annotation.One;
-import com.arialyy.aria.orm.annotation.Wrapper;
-import com.arialyy.aria.util.CommonUtil;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Created by laoyuyu on 2018/3/30.
- * 任务组实体和任务组任务实体的关系
- */
-@Wrapper
-public class DGTEWrapper extends AbsWrapper {
-
-  @One
-  public DownloadGroupEntity entity;
-
-  @Many(parentColumn = "groupName", entityColumn = "key")
-  private List<DownloadGroupTaskEntity> taskEntitys;
-
-  public DownloadGroupTaskEntity taskEntity;
-
-  @Override protected void handleConvert() {
-    taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0);
-    if (taskEntity != null) {
-      taskEntity.setEntity(entity);
-      List<DTEWrapper> subWrappers =
-          DbEntity.findRelationData(DTEWrapper.class, "DownloadTaskEntity.groupName=?",
-              taskEntity.getKey());
-      if (subWrappers != null && !subWrappers.isEmpty()) {
-        List<DownloadTaskEntity> temp = new ArrayList<>();
-        for (DTEWrapper dw : subWrappers) {
-          if (dw.taskEntity.getRequestType() == AbsTaskEntity.D_FTP) {
-            dw.taskEntity.setUrlEntity(CommonUtil.getFtpUrlInfo(dw.taskEntity.getUrl()));
-          }
-          temp.add(dw.taskEntity);
-        }
-        taskEntity.setSubTaskEntities(temp);
-      }
-    }
-  }
-}

+ 0 - 46
Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DTEWrapper.java

@@ -1,46 +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.download.wrapper;
-
-import com.arialyy.aria.core.download.DownloadEntity;
-import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.orm.AbsWrapper;
-import com.arialyy.aria.orm.annotation.Many;
-import com.arialyy.aria.orm.annotation.One;
-import com.arialyy.aria.orm.annotation.Wrapper;
-import java.util.List;
-
-/**
- * Created by laoyuyu on 2018/3/30.
- */
-@Wrapper
-public class DTEWrapper extends AbsWrapper {
-
-  @One
-  public DownloadEntity entity;
-
-  @Many(parentColumn = "downloadPath", entityColumn = "key")
-  private List<DownloadTaskEntity> taskEntitys = null;
-
-  public DownloadTaskEntity taskEntity;
-
-  @Override public void handleConvert() {
-    taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0);
-    if (taskEntity != null) {
-      taskEntity.setEntity(entity);
-    }
-  }
-}

+ 150 - 0
Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java

@@ -0,0 +1,150 @@
+/*
+ * 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 android.util.Log;
+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.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.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_HIGHEST_PRIORITY))
+        .exe();
+  }
+
+  /**
+   * 重定向后,新url的key,默认为location
+   */
+  public void setRedirectUrlKey(String redirectUrlKey) {
+    if (TextUtils.isEmpty(redirectUrlKey)) {
+      Log.w("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.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE))
+        .exe();
+  }
+
+  /**
+   * 重新下载
+   */
+  public void reStart() {
+    cancel();
+    start();
+  }
+}

+ 4 - 27
Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java

@@ -18,7 +18,7 @@ package com.arialyy.aria.core.inf;
 import android.os.Parcel;
 import android.os.Parcelable;
 import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.orm.annotation.Ignore;
+import com.arialyy.aria.orm.Ignore;
 
 /**
  * Created by AriaL on 2017/6/29.
@@ -31,7 +31,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
   /**
    * 单位转换后的速度
    */
-  @Ignore private String convertSpeed;
+  @Ignore private String convertSpeed = "";
   /**
    * 下载失败计数,每次开始都重置为0
    */
@@ -40,7 +40,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
   /**
    * 扩展字段
    */
-  private String str;
+  private String str = "";
   /**
    * 文件大小
    */
@@ -48,7 +48,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
   /**
    * 转换后的文件大小
    */
-  private String convertFileSize;
+  private String convertFileSize = "";
 
   private int state = STATE_WAIT;
   /**
@@ -60,11 +60,6 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
    */
   private long completeTime;
 
-  /**
-   * 进度百分比
-   */
-  @Ignore private int percent;
-
   private boolean isComplete = false;
 
   public boolean isComplete() {
@@ -147,27 +142,11 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
     this.completeTime = completeTime;
   }
 
-  public int getPercent() {
-    return percent;
-  }
-
-  public void setPercent(int percent) {
-    this.percent = percent;
-  }
-
   /**
    * 实体唯一标识符
    */
   public abstract String getKey();
 
-  /**
-   * 实体驱动的下载任务类型
-   *
-   * @return {@link AbsTaskEntity#D_FTP}、{@link AbsTaskEntity#D_FTP_DIR}、{@link
-   * AbsTaskEntity#U_HTTP}...
-   */
-  public abstract int getTaskType();
-
   public AbsEntity() {
   }
 
@@ -186,7 +165,6 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
     dest.writeLong(this.currentProgress);
     dest.writeLong(this.completeTime);
     dest.writeByte(this.isComplete ? (byte) 1 : (byte) 0);
-    dest.writeInt(this.percent);
   }
 
   protected AbsEntity(Parcel in) {
@@ -200,6 +178,5 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
     this.currentProgress = in.readLong();
     this.completeTime = in.readLong();
     this.isComplete = in.readByte() != 0;
-    this.percent = in.readInt();
   }
 }

+ 4 - 32
Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java

@@ -17,49 +17,21 @@ package com.arialyy.aria.core.inf;
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import com.arialyy.aria.orm.annotation.Primary;
-import java.util.ArrayList;
-import java.util.List;
+import com.arialyy.aria.orm.Primary;
 
 /**
  * Created by AriaL on 2017/6/3.
  */
 public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
   /**
-   * 组名,组名为任务地址相加的urlMd5
+   * 组名,组名为任务地址相加的urlMd5
    */
-  @Primary protected String groupName;
+  @Primary protected String groupName = "";
 
   /**
    * 任务组别名
    */
-  private String alias;
-
-  /**
-   * 任务组下载文件的文件夹地址
-   */
-  private String dirPath;
-
-  /**
-   * 子任务url地址
-   */
-  private List<String> urls = new ArrayList<>();
-
-  public String getDirPath() {
-    return dirPath;
-  }
-
-  public void setDirPath(String dirPath) {
-    this.dirPath = dirPath;
-  }
-
-  public List<String> getUrls() {
-    return urls;
-  }
-
-  public void setUrls(List<String> urls) {
-    this.urls = urls;
-  }
+  private String alias = "";
 
   public String getGroupName() {
     return groupName;

+ 5 - 39
Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java

@@ -15,51 +15,17 @@
  */
 package com.arialyy.aria.core.inf;
 
-import com.arialyy.aria.core.download.downloader.AbsGroupUtil;
 
 /**
  * Created by AriaL on 2017/6/29.
- * 任务组任务抽象类
  */
-public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskEntity>
-    extends AbsTask<TASK_ENTITY> {
+public abstract class AbsGroupTask<TASK_ENTITY extends AbsTaskEntity, ENTITY extends AbsGroupEntity>
+    extends AbsTask<ENTITY> {
 
-  protected AbsGroupUtil mUtil;
+  protected TASK_ENTITY mTaskEntity;
 
-  @Override public String getKey() {
-    return mTaskEntity.getEntity().getKey();
-  }
-
-  /**
-   * 启动任务组中的子任务
-   *
-   * @param url 子任务下载地址
-   */
-  public void startSubTask(String url) {
-    if (mUtil != null) {
-      mUtil.startSubTask(url);
-    }
-  }
 
-  /**
-   * 停止任务组中的子任务
-   *
-   * @param url 子任务下载地址
-   */
-  public void stopSubTask(String url) {
-    if (mUtil != null) {
-      mUtil.stopSubTask(url);
-    }
-  }
-
-  /**
-   * 删除子任务组中的子任务
-   *
-   * @param url 子任务下载地址
-   */
-  public void cancelSubTask(String url) {
-    if (mUtil != null) {
-      mUtil.cancelSubTask(url);
-    }
+  @Override public String getKey() {
+    return mEntity.getGroupName();
   }
 }

+ 0 - 26
Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTaskEntity.java

@@ -1,26 +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;
-
-/**
- * Created by lyy on 2017/9/5.
- */
-public abstract class AbsGroupTaskEntity<ENTITY extends AbsGroupEntity> extends AbsTaskEntity<ENTITY>{
-  @Override public ENTITY getEntity() {
-    return null;
-  }
-}

+ 5 - 3
Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java

@@ -17,6 +17,8 @@ package com.arialyy.aria.core.inf;
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import com.arialyy.aria.orm.DbEntity;
+import com.arialyy.aria.orm.Ignore;
 
 /**
  * Created by AriaL on 2017/6/3.
@@ -26,12 +28,12 @@ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable {
   /**
    * 服务器地址
    */
-  private String url;
+  private String url = "";
 
   /**
    * 文件名
    */
-  private String fileName;
+  private String fileName = "";
 
   /**
    * 是否是任务组里面的下载实体
@@ -39,7 +41,7 @@ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable {
   private boolean isGroupChild = false;
 
   private boolean isRedirect = false; //是否重定向
-  private String redirectUrl; //重定向链接
+  private String redirectUrl = ""; //重定向链接
 
   public String getUrl() {
     return url;

+ 3 - 2
Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java

@@ -18,8 +18,7 @@ package com.arialyy.aria.core.inf;
 /**
  * Created by lyy on 2017/6/3.
  */
-public abstract class AbsNormalTask<TASK_ENTITY extends AbsNormalTaskEntity>
-    extends AbsTask<TASK_ENTITY> {
+public abstract class AbsNormalTask<ENTITY extends AbsEntity> extends AbsTask<ENTITY> {
 
   /**
    * 暂停任务,并让任务处于等待状态
@@ -40,4 +39,6 @@ public abstract class AbsNormalTask<TASK_ENTITY extends AbsNormalTaskEntity>
   public void setHighestPriority(boolean isHighestPriority) {
     isHeighestTask = isHighestPriority;
   }
+
+
 }

+ 0 - 23
Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTaskEntity.java

@@ -1,23 +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;
-
-/**
- * Created by Aria.Lao on 2017/10/12.
- * 当任务实体
- */
-public abstract class AbsNormalTaskEntity<ENTITY extends AbsEntity> extends AbsTaskEntity<ENTITY> {
-}

+ 1 - 8
Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java

@@ -20,15 +20,8 @@ package com.arialyy.aria.core.inf;
  * Created by AriaL on 2017/6/27.
  */
 
-public abstract class AbsReceiver<ENTITY extends AbsEntity> implements IReceiver<ENTITY> {
+public abstract class AbsReceiver<ENTITY extends AbsEntity> implements IReceiver<ENTITY>{
   public String targetName;
   public Object obj;
-  /**
-   * 当dialog、dialogFragment、popupwindow已经被设置了关闭监听时,需要手动移除receiver
-   */
-  public boolean needRmListener = false;
 
-  public void unRegisterListener(){
-
-  }
 }

+ 75 - 110
Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java

@@ -15,56 +15,37 @@
  */
 package com.arialyy.aria.core.inf;
 
+import android.support.annotation.NonNull;
 import android.text.TextUtils;
+import android.util.Log;
 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.common.RequestEnum;
 import com.arialyy.aria.core.command.normal.NormalCmdFactory;
-import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
-import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.manager.TEManager;
-import com.arialyy.aria.core.upload.UploadTaskEntity;
-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.
  */
 public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
     implements ITarget<TARGET> {
-  protected String TAG = "";
   protected ENTITY mEntity;
   protected TASK_ENTITY mTaskEntity;
   protected String mTargetName;
 
-  protected AbsTarget() {
-    TAG = CommonUtil.getClassName(this);
-  }
-
   /**
-   * 重置状态,将任务状态设置为未开始状态
-   * 注意:如果在后续方法调用链中没有调用 {@link #start()}、{@link #stop()}、{@link #cancel()}、{@link #resume()}
-   * 等操作任务的方法,那么你需要调用{@link #save()}才能将修改保存到数据库
+   * 删除记录
    */
-  public TARGET resetState() {
-    mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
-    mTaskEntity.setRefreshInfo(true);
-    return (TARGET) this;
+  public void removeRecord() {
+    mEntity.deleteData();
   }
 
   /**
-   * 删除记录,如果任务正在执行,则会删除正在下载的任务
+   * 任务是否存在
    */
-  public void removeRecord() {
-    if (isRunning()) {
-      ALog.d("AbsTarget", "任务正在下载,即将删除任务");
-      cancel();
-    } else {
-      mEntity.deleteData();
-      TEManager.getInstance().removeTEntity(mEntity.getKey());
-    }
+  public boolean taskExists() {
+    return false;
   }
 
   /**
@@ -72,7 +53,6 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
    *
    * @return 该任务进度
    */
-  @Override
   public long getCurrentProgress() {
     return mEntity == null ? -1 : mEntity.getCurrentProgress();
   }
@@ -97,8 +77,6 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
 
   /**
    * 设置扩展字段,用来保存你的其它数据,如果你的数据比较多,你可以把你的数据转换为JSON字符串,然后再存到Aria中
-   * 注意:如果在后续方法调用链中没有调用 {@link #start()}、{@link #stop()}、{@link #cancel()}、{@link #resume()}
-   * 等操作任务的方法,那么你需要调用{@link #save()}才能将修改保存到数据库
    *
    * @param str 扩展数据
    */
@@ -106,10 +84,8 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
     if (TextUtils.isEmpty(str)) return (TARGET) this;
     if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) {
       mEntity.setStr(str);
-    } else {
-      ALog.e(TAG, "设置扩展字段失败,扩展字段为null");
+      mEntity.save();
     }
-
     return (TARGET) this;
   }
 
@@ -126,7 +102,6 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
    *
    * @return {@link IEntity}
    */
-  @Override
   public int getTaskState() {
     return mEntity.getState();
   }
@@ -138,7 +113,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
    */
   @Override public int getPercent() {
     if (mEntity == null) {
-      ALog.e("AbsTarget", "下载管理器中没有该任务");
+      Log.e("AbsTarget", "下载管理器中没有该任务");
       return 0;
     }
     if (mEntity.getFileSize() != 0) {
@@ -148,43 +123,46 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
   }
 
   /**
-   * 检查实体是否合法,如果实体合法,将保存实体到数据库,或更新数据库中的实体对象
+   * 给url请求添加头部
    *
-   * @return {@code true} 合法
+   * @param key 头部key
+   * @param header 头部value
    */
-  protected abstract boolean checkEntity();
+  public TARGET addHeader(@NonNull String key, @NonNull String header) {
+    mTaskEntity.headers.put(key, header);
+    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;
+  /**
+   * 给url请求添加头部
+   */
+  public TARGET addHeaders(Map<String, String> headers) {
+    if (headers != null && headers.size() > 0) {
+      Set<String> keys = headers.keySet();
+      for (String key : keys) {
+        mTaskEntity.headers.put(key, headers.get(key));
+      }
     }
-    return taskType;
+    return (TARGET) this;
   }
 
   /**
-   * 保存修改
+   * 设置请求类型
+   *
+   * @param requestEnum {@link RequestEnum}
    */
-  public void save() {
-    if (!checkEntity()) {
-      ALog.e(TAG, "保存修改失败");
-    }
+  public TARGET setRequestMode(RequestEnum requestEnum) {
+    mTaskEntity.requestEnum = requestEnum;
+    return (TARGET) this;
   }
 
   /**
    * 开始任务
    */
   @Override public void start() {
-    if (checkEntity()) {
-      AriaManager.getInstance(AriaManager.APP)
-          .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
-              checkTaskType()))
-          .exe();
-    }
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
+        .exe();
   }
 
   /**
@@ -193,58 +171,31 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
    * @see #stop()
    */
   @Deprecated public void pause() {
-    if (checkEntity()) {
-      stop();
-    }
+    stop();
   }
 
   @Override public void stop() {
-    if (checkEntity()) {
-      AriaManager.getInstance(AriaManager.APP)
-          .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP,
-              checkTaskType()))
-          .exe();
-    }
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP))
+        .exe();
   }
 
   /**
    * 恢复任务
    */
   @Override public void resume() {
-    if (checkEntity()) {
-      AriaManager.getInstance(AriaManager.APP)
-          .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
-              checkTaskType()))
-          .exe();
-    }
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
+        .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));
-      cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
-          taskType));
-      AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe();
-    }
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL))
+        .exe();
   }
 
   /**
@@ -254,21 +205,35 @@ 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();
-    }
+    mTaskEntity.removeFile = removeFile;
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL))
+        .exe();
   }
 
   /**
-   * 重新下载
-   */
-  public void reStart() {
-    if (checkEntity()) {
-      cancel();
-      start();
+   * 创建文件名,如果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);
     }
+    return fileName;
   }
 }

+ 18 - 32
Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java

@@ -22,13 +22,9 @@ import com.arialyy.aria.util.CommonUtil;
 /**
  * Created by AriaL on 2017/6/29.
  */
-public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITask<TASK_ENTITY> {
+public abstract class AbsTask<ENTITY extends AbsEntity> implements ITask<ENTITY> {
 
-  /**
-   * 是否需要重试,默认为true
-   */
-  public boolean needRetry = true;
-  protected TASK_ENTITY mTaskEntity;
+  protected ENTITY mEntity;
   protected Handler mOutHandler;
 
   /**
@@ -36,11 +32,8 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
    */
   private String mTargetName;
   protected Context mContext;
-  protected boolean isHeighestTask = false;
 
-  public Handler getOutHandler() {
-    return mOutHandler;
-  }
+  protected boolean isHeighestTask = false;
 
   /**
    * 任务是否完成
@@ -48,14 +41,14 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
    * @return {@code true} 已经完成,{@code false} 未完成
    */
   public boolean isComplete() {
-    return mTaskEntity.getEntity().isComplete();
+    return mEntity.isComplete();
   }
 
   /**
    * 获取当前下载进度
    */
   @Override public long getCurrentProgress() {
-    return mTaskEntity.getEntity().getCurrentProgress();
+    return mEntity.getCurrentProgress();
   }
 
   /**
@@ -64,10 +57,10 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
    * @return 如:已经下载3mb的大小,则返回{@code 3mb}
    */
   @Override public String getConvertCurrentProgress() {
-    if (mTaskEntity.getEntity().getCurrentProgress() == 0) {
+    if (mEntity.getCurrentProgress() == 0) {
       return "0b";
     }
-    return CommonUtil.formatFileSize(mTaskEntity.getEntity().getCurrentProgress());
+    return CommonUtil.formatFileSize(mEntity.getCurrentProgress());
   }
 
   /**
@@ -76,17 +69,17 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
    * @return 如果文件长度为0,则返回0m,否则返回转换后的长度1b、1kb、1mb、1gb、1tb
    */
   @Override public String getConvertFileSize() {
-    if (mTaskEntity.getEntity().getFileSize() == 0) {
+    if (mEntity.getFileSize() == 0) {
       return "0mb";
     }
-    return CommonUtil.formatFileSize(mTaskEntity.getEntity().getFileSize());
+    return CommonUtil.formatFileSize(mEntity.getFileSize());
   }
 
   /**
    * 获取文件大小
    */
   @Override public long getFileSize() {
-    return mTaskEntity.getEntity().getFileSize();
+    return mEntity.getFileSize();
   }
 
   /**
@@ -95,11 +88,10 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
    * @return 返回百分比进度,如果文件长度为0,返回0
    */
   @Override public int getPercent() {
-    if (mTaskEntity.getEntity().getFileSize() == 0) {
+    if (mEntity.getFileSize() == 0) {
       return 0;
     }
-    return (int) (mTaskEntity.getEntity().getCurrentProgress() * 100 / mTaskEntity.getEntity()
-        .getFileSize());
+    return (int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize());
   }
 
   /**
@@ -108,8 +100,7 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
    * @return {@link IEntity}
    */
   public int getState() {
-    return mTaskEntity.getEntity() == null ? IEntity.STATE_OTHER
-        : mTaskEntity.getEntity().getState();
+    return mEntity == null ? IEntity.STATE_OTHER : mEntity.getState();
   }
 
   /**
@@ -118,7 +109,7 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
    * @return 如果实体不存在,则返回null,否则返回扩展字段
    */
   @Override public String getExtendField() {
-    return mTaskEntity.getEntity() == null ? null : mTaskEntity.getEntity().getStr();
+    return mEntity == null ? null : mEntity.getStr();
   }
 
   /**
@@ -139,7 +130,7 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
    * 才能生效
    */
   @Override public long getSpeed() {
-    return mTaskEntity.getEntity().getSpeed();
+    return mEntity.getSpeed();
   }
 
   /**
@@ -160,18 +151,13 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
    * 才能生效
    */
   @Override public String getConvertSpeed() {
-    return mTaskEntity.getEntity().getConvertSpeed();
+    return mEntity.getConvertSpeed();
   }
 
-  @Override public TASK_ENTITY getTaskEntity() {
-    return mTaskEntity;
+  @Override public ENTITY getEntity() {
+    return mEntity;
   }
 
-  /**
-   * 获取任务名,也就是文件名
-   */
-  public abstract String getTaskName();
-
   public String getTargetName() {
     return mTargetName;
   }

+ 36 - 154
Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java

@@ -15,114 +15,107 @@
  */
 package com.arialyy.aria.core.inf;
 
-import com.arialyy.aria.core.FtpUrlEntity;
 import com.arialyy.aria.core.common.RequestEnum;
 import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.orm.annotation.Ignore;
+import com.arialyy.aria.orm.Ignore;
+import com.arialyy.aria.orm.Primary;
 import java.util.HashMap;
 import java.util.Map;
 
 /**
  * Created by lyy on 2017/2/23.
- * 所有任务实体的父类
  */
 public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
   /**
-   * HTTP单任务
+   * HTTP
    */
-  public static final int D_HTTP = 0x11;
+  public static final int HTTP = 0x11;
   /**
-   * HTTP任务组下载
+   * FTP当文件下载
    */
-  public static final int DG_HTTP = 0x12;
-
-  /**
-   * FTP单文件下载
-   */
-  public static final int D_FTP = 0x13;
+  public static final int FTP = 0x12;
   /**
    * FTP文件夹下载,为避免登录过多,子任务由单线程进行处理
    */
-  public static final int D_FTP_DIR = 0x14;
+  public static final int FTP_DIR = 0x13;
 
   /**
-   * HTTP单文件上传
+   * Task实体对应的key
    */
-  public static final int U_HTTP = 0xA1;
+  @Primary public String key = "";
+
   /**
-   * FTP单文件上传
+   * 账号和密码
    */
-  public static final int U_FTP = 0xA2;
+  @Ignore public String userName, userPw, account, serverIp;
+  @Ignore public int port;
 
   /**
-   * 账号和密码
+   * 请求类型
+   * {@link AbsTaskEntity#HTTP}、{@link AbsTaskEntity#FTP}
    */
-  @Ignore private FtpUrlEntity urlEntity;
+  public int requestType = HTTP;
 
   /**
-   * 刷新信息 {@code true} 重新刷新下载信息
+   * http 请求头
    */
-  @Ignore private boolean refreshInfo = false;
+  public Map<String, String> headers = new HashMap<>();
 
   /**
-   * 是否是新任务,{@code true} 新任务
+   * 字符编码,默认为"utf-8"
    */
-  @Ignore private boolean isNewTask = false;
+  public String charSet = "utf-8";
 
   /**
-   * 任务状态,和Entity的state同步
+   * 网络请求类型
    */
-  private int state = IEntity.STATE_WAIT;
+  public RequestEnum requestEnum = RequestEnum.GET;
 
   /**
-   * 请求类型
-   * {@link AbsTaskEntity#D_HTTP}、{@link AbsTaskEntity#D_FTP}、{@link AbsTaskEntity#D_FTP_DIR}。。。
+   * 从header中含有的文件md5码信息所需要的key
    */
-  private int requestType = D_HTTP;
+  public String md5Key = "Content-MD5";
 
   /**
-   * http 请求头
+   * 从header中获取文件描述信息所需要的key
    */
-  private Map<String, String> headers = new HashMap<>();
+  public String dispositionKey = "Content-Disposition";
 
   /**
-   * 字符编码,默认为"utf-8"
+   * 重定向后,从header中获取新url所需要的key
    */
-  private String charSet = "utf-8";
+  public String redirectUrlKey = "location";
 
   /**
-   * 网络请求类型
+   * 从Disposition获取的文件名说需要的key
    */
-  private RequestEnum requestEnum = RequestEnum.GET;
+  public String dispositionFileKey = "attachment;filename";
 
   /**
-   * 是否使用服务器通过content-disposition传递的文件名,内容格式{@code attachment; filename="filename.jpg"}
-   * {@code true} 使用
+   * 从header中含有的文件长度信息所需要的key
    */
-  private boolean useServerFileName = false;
+  public String contentLength = "Content-Length";
 
   /**
    * 重定向链接
    */
-  private String redirectUrl = "";
+  public String redirectUrl = "";
 
   /**
-   * 删除任务时,是否删除已下载完成的文件
-   * 未完成的任务,不管true还是false,都会删除文件
    * {@code true}  删除任务数据库记录,并且删除已经下载完成的文件
    * {@code false} 如果任务已经完成,只删除任务数据库记录
    */
-  @Ignore private boolean removeFile = false;
+  @Ignore public boolean removeFile = false;
 
   /**
    * 是否支持断点, {@code true} 为支持断点
    */
-  private boolean isSupportBP = true;
+  public boolean isSupportBP = true;
 
   /**
    * 状态码
    */
-  private int code;
+  public int code;
 
   public abstract ENTITY getEntity();
 
@@ -134,115 +127,4 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
   public int getState() {
     return getEntity().getState();
   }
-
-  public abstract String getKey();
-
-  public abstract void setKey(String key);
-
-  @Override public void update() {
-    if (getEntity() != null) {
-      getEntity().update();
-    }
-    super.update();
-  }
-
-  public FtpUrlEntity getUrlEntity() {
-    return urlEntity;
-  }
-
-  public void setUrlEntity(FtpUrlEntity urlEntity) {
-    this.urlEntity = urlEntity;
-  }
-
-  public boolean isRefreshInfo() {
-    return refreshInfo;
-  }
-
-  public void setRefreshInfo(boolean refreshInfo) {
-    this.refreshInfo = refreshInfo;
-  }
-
-  public boolean isNewTask() {
-    return isNewTask;
-  }
-
-  public void setNewTask(boolean newTask) {
-    isNewTask = newTask;
-  }
-
-  public void setState(int state) {
-    this.state = state;
-  }
-
-  public int getRequestType() {
-    return requestType;
-  }
-
-  public void setRequestType(int requestType) {
-    this.requestType = requestType;
-  }
-
-  public Map<String, String> getHeaders() {
-    return headers;
-  }
-
-  public void setHeaders(Map<String, String> headers) {
-    this.headers = headers;
-  }
-
-  public String getCharSet() {
-    return charSet;
-  }
-
-  public void setCharSet(String charSet) {
-    this.charSet = charSet;
-  }
-
-  public RequestEnum getRequestEnum() {
-    return requestEnum;
-  }
-
-  public void setRequestEnum(RequestEnum requestEnum) {
-    this.requestEnum = requestEnum;
-  }
-
-  public boolean isUseServerFileName() {
-    return useServerFileName;
-  }
-
-  public void setUseServerFileName(boolean useServerFileName) {
-    this.useServerFileName = useServerFileName;
-  }
-
-  public String getRedirectUrl() {
-    return redirectUrl;
-  }
-
-  public void setRedirectUrl(String redirectUrl) {
-    this.redirectUrl = redirectUrl;
-  }
-
-  public boolean isRemoveFile() {
-    return removeFile;
-  }
-
-  public void setRemoveFile(boolean removeFile) {
-    this.removeFile = removeFile;
-  }
-
-  public boolean isSupportBP() {
-    return isSupportBP;
-  }
-
-  public void setSupportBP(boolean supportBP) {
-    isSupportBP = supportBP;
-  }
-
-  public int getCode() {
-    return code;
-  }
-
-  public void setCode(int code) {
-    this.code = code;
-  }
 }

+ 80 - 0
Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java

@@ -0,0 +1,80 @@
+/*
+ * 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;
+import java.util.regex.Pattern;
+
+/**
+ * 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) {
+    CheckUtil.checkDownloadUrl(uploadUrl);
+    if (mEntity.getUrl().equals(uploadUrl)) return (TARGET) this;
+    mEntity.setUrl(uploadUrl);
+    mEntity.update();
+    return (TARGET) this;
+  }
+
+  /**
+   * 从数据中读取上传实体,如果数据库查不到,则新创建一个上传实体
+   *
+   * @param filePath 上传文件的文件路径
+   */
+  protected UploadEntity getUploadEntity(String filePath) {
+    UploadEntity entity = UploadEntity.findFirst(UploadEntity.class, "filePath=?", filePath);
+    if (entity == null) {
+      entity = new UploadEntity();
+      String regex = "[/|\\\\|//]";
+      Pattern p = Pattern.compile(regex);
+      String[] strs = p.split(filePath);
+      String fileName = strs[strs.length - 1];
+      entity.setFileName(fileName);
+      entity.setFilePath(filePath);
+      entity.insert();
+    }
+    return entity;
+  }
+
+  /**
+   * 下载任务是否存在
+   */
+  @Override public boolean taskExists() {
+    return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null;
+  }
+
+  /**
+   * 是否在下载
+   */
+  public boolean isUploading() {
+    UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity);
+    return task != null && task.isRunning();
+  }
+}

+ 0 - 34
Aria/src/main/java/com/arialyy/aria/core/inf/GroupSendParams.java

@@ -1,34 +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;
-
-/**
- * Created by lyy on 2017/9/8.
- * 任务组参数传递
- */
-public class GroupSendParams<GROUP_TASK extends AbsGroupTask, ENTITY extends AbsNormalEntity> {
-
-  public GROUP_TASK groupTask;
-  public ENTITY entity;
-
-  public GroupSendParams() {
-  }
-
-  public GroupSendParams(GROUP_TASK groupTask, ENTITY entity) {
-    this.groupTask = groupTask;
-    this.entity = entity;
-  }
-}

+ 3 - 3
Aria/src/main/java/com/arialyy/aria/core/inf/IEntity.java

@@ -15,7 +15,7 @@
  */
 package com.arialyy.aria.core.inf;
 
-import com.arialyy.aria.orm.annotation.Ignore;
+import com.arialyy.aria.orm.Ignore;
 
 /**
  * Created by lyy on 2017/2/23.
@@ -42,7 +42,7 @@ public interface IEntity {
    */
   @Ignore int STATE_WAIT = 3;
   /**
-   * 正在执行
+   * 下载中
    */
   @Ignore int STATE_RUNNING = 4;
   /**
@@ -54,7 +54,7 @@ public interface IEntity {
    */
   @Ignore int STATE_POST_PRE = 6;
   /**
-   * 删除任务
+   * 取消下载
    */
   @Ignore int STATE_CANCEL = 7;
 }

+ 1 - 3
Aria/src/main/java/com/arialyy/aria/core/inf/IEventListener.java

@@ -58,8 +58,6 @@ public interface IEventListener {
 
   /**
    * 下载失败
-   * @param needRetry 是否需要重试{@code true} 需要
    */
-  void onFail(boolean needRetry);
-
+  void onFail();
 }

+ 0 - 43
Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java

@@ -1,43 +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;
-
-/**
- * Created by laoyuyu on 2018/3/9.
- */
-public interface IFtpTarget<TARGET extends ITarget> {
-  /**
-   * 设置字符编码
-   */
-  TARGET charSet(String charSet);
-
-  /**
-   * ftp 用户登录信。
-   *
-   * @param userName ftp用户名
-   * @param password ftp用户密码
-   */
-  TARGET login(String userName, String password);
-
-  /**
-   * ftp 用户登录信息
-   *
-   * @param userName ftp用户名
-   * @param password ftp用户密码
-   * @param account ftp账号
-   */
-  TARGET login(String userName, String password, String account);
-}

+ 0 - 52
Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java

@@ -1,52 +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.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);
-}

+ 5 - 1
Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java

@@ -26,6 +26,10 @@ public interface IReceiver<ENTITY extends IEntity> {
    */
   void destroy();
 
+  /**
+   * 移除事件回调
+   */
+  void removeSchedulerListener();
 
   /**
    * 移除观察者
@@ -52,5 +56,5 @@ public interface IReceiver<ENTITY extends IEntity> {
   /**
    * 获取任务列表
    */
-  List<ENTITY> getTaskList();
+  List<ENTITY> getSimpleTaskList();
 }

+ 24 - 20
Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java

@@ -15,50 +15,53 @@
  */
 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}
+   * 任务文件大小
    */
-  int getTaskState();
+  long getSize();
 
   /**
-   * 任务是否在执行
-   *
-   * @return {@code true} 任务正在执行
+   * 转换后的大小
    */
-  boolean isRunning();
+  String getConvertSize();
 
   /**
-   * 任务是否存在
-   *
-   * @return {@code true} 任务存在
+   * 获取任务进度百分比
    */
-  boolean taskExists();
+  int getPercent();
 
   /**
-   * 任务文件大小
+   * 获取任务进度,如果任务存在,则返回当前进度
    */
-  long getSize();
+  long getCurrentProgress();
 
   /**
-   * 转换后的大小
+   * 给url请求添加头部
+   *
+   * @param key 头部key
+   * @param header 头部value
    */
-  String getConvertSize();
+  TARGET addHeader(@NonNull String key, @NonNull String header) ;
 
   /**
-   * 获取任务进度百分比
+   * 给url请求添加头部
    */
-  int getPercent();
+  TARGET addHeaders(Map<String, String> headers);
 
   /**
-   * 获取任务进度,如果任务存在,则返回当前进度
+   * 设置请求类型
+   *
+   * @param requestEnum {@link RequestEnum}
    */
-  long getCurrentProgress();
+  TARGET setRequestMode(RequestEnum requestEnum);
 
   /**
    * 开始下载
@@ -79,4 +82,5 @@ public interface ITarget<TARGET extends ITarget> {
    * 取消下载
    */
   void cancel();
+
 }

+ 3 - 2
Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java

@@ -18,7 +18,7 @@ package com.arialyy.aria.core.inf;
 /**
  * Created by lyy on 2017/2/13.
  */
-public interface ITask<TASK_ENTITY extends AbsTaskEntity> {
+public interface ITask<ENTITY extends AbsEntity> {
 
   /**
    * 获取下载状态
@@ -45,7 +45,7 @@ public interface ITask<TASK_ENTITY extends AbsTaskEntity> {
   /**
    * 获取信息实体
    */
-  TASK_ENTITY getTaskEntity();
+  ENTITY getEntity();
 
   void start();
 
@@ -91,4 +91,5 @@ public interface ITask<TASK_ENTITY extends AbsTaskEntity> {
   String getConvertCurrentProgress();
 
   void setTargetName(String targetName);
+
 }

+ 2 - 0
Aria/src/main/java/com/arialyy/aria/core/inf/IUploadListener.java

@@ -15,6 +15,8 @@
  */
 package com.arialyy.aria.core.inf;
 
+import com.arialyy.aria.core.inf.IEventListener;
+
 /**
  * Created by lyy on 2017/2/9.
  * 上传监听

+ 0 - 169
Aria/src/main/java/com/arialyy/aria/core/manager/DGTEFactory.java

@@ -1,169 +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.manager;
-
-import com.arialyy.aria.core.download.DownloadEntity;
-import com.arialyy.aria.core.download.DownloadGroupEntity;
-import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
-import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.download.wrapper.DGEWrapper;
-import com.arialyy.aria.core.download.wrapper.DGTEWrapper;
-import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.util.CommonUtil;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Created by Aria.Lao on 2017/11/1.
- * 任务实体工厂
- */
-class DGTEFactory implements IGTEFactory<DownloadGroupEntity, DownloadGroupTaskEntity> {
-  private static final String TAG = "DTEFactory";
-  private static volatile DGTEFactory INSTANCE = null;
-
-  private DGTEFactory() {
-  }
-
-  public static DGTEFactory getInstance() {
-    if (INSTANCE == null) {
-      synchronized (DGTEFactory.class) {
-        INSTANCE = new DGTEFactory();
-      }
-    }
-    return INSTANCE;
-  }
-
-  @Override public DownloadGroupTaskEntity getGTE(String groupName, List<String> urls) {
-    DownloadGroupEntity entity = createDGroupEntity(groupName, urls);
-    List<DGTEWrapper> wrapper =
-        DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.key=?",
-            entity.getGroupName());
-    DownloadGroupTaskEntity gte;
-
-    if (wrapper != null && !wrapper.isEmpty()) {
-      gte = wrapper.get(0).taskEntity;
-      if (gte == null) {
-        // 创建新的任务组任务实体
-        gte = new DownloadGroupTaskEntity();
-        //创建子任务的任务实体
-        gte.setSubTaskEntities(createDGSubTaskEntity(entity));
-      } else if (gte.getSubTaskEntities() == null || gte.getSubTaskEntities().isEmpty()) {
-        gte.setSubTaskEntities(createDGSubTaskEntity(entity));
-      }
-    } else {
-      gte = new DownloadGroupTaskEntity();
-      gte.setSubTaskEntities(createDGSubTaskEntity(entity));
-    }
-    gte.setKey(entity.getGroupName());
-    gte.setEntity(entity);
-
-    return gte;
-  }
-
-  @Override public DownloadGroupTaskEntity getFTE(String ftpUrl) {
-    List<DGTEWrapper> wrapper =
-        DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.key=?",
-            ftpUrl);
-    DownloadGroupTaskEntity fte;
-
-    if (wrapper != null && !wrapper.isEmpty()) {
-      fte = wrapper.get(0).taskEntity;
-      if (fte == null) {
-        fte = new DownloadGroupTaskEntity();
-        DownloadGroupEntity dge = new DownloadGroupEntity();
-        dge.setGroupName(ftpUrl);
-        fte.setEntity(dge);
-      } else if (fte.getEntity() == null) {
-        DownloadGroupEntity dge = new DownloadGroupEntity();
-        dge.setGroupName(ftpUrl);
-        fte.setEntity(dge);
-      }
-    } else {
-      fte = new DownloadGroupTaskEntity();
-      DownloadGroupEntity dge = new DownloadGroupEntity();
-      dge.setGroupName(ftpUrl);
-      fte.setEntity(dge);
-    }
-    fte.setKey(ftpUrl);
-    fte.setUrlEntity(CommonUtil.getFtpUrlInfo(ftpUrl));
-
-    if (fte.getEntity().getSubEntities() == null) {
-      fte.getEntity().setSubEntities(new ArrayList<DownloadEntity>());
-    }
-    if (fte.getSubTaskEntities() == null) {
-      fte.setSubTaskEntities(new ArrayList<DownloadTaskEntity>());
-    }
-    return fte;
-  }
-
-  /**
-   * 创建任务组子任务的任务实体
-   */
-  private List<DownloadTaskEntity> createDGSubTaskEntity(DownloadGroupEntity dge) {
-    List<DownloadTaskEntity> list = new ArrayList<>();
-    for (DownloadEntity entity : dge.getSubEntities()) {
-      DownloadTaskEntity taskEntity = new DownloadTaskEntity();
-      taskEntity.setEntity(entity);
-      taskEntity.setKey(entity.getDownloadPath());
-      taskEntity.setGroupName(dge.getKey());
-      taskEntity.setGroupTask(true);
-      taskEntity.setUrl(entity.getUrl());
-      list.add(taskEntity);
-    }
-    return list;
-  }
-
-  /**
-   * 查询任务组实体,如果数据库不存在该实体,则新创建一个新的任务组实体
-   */
-  private DownloadGroupEntity createDGroupEntity(String groupName, List<String> urls) {
-    List<DGEWrapper> wrapper =
-        DbEntity.findRelationData(DGEWrapper.class, "DownloadGroupEntity.groupName=?",
-            groupName);
-
-    DownloadGroupEntity groupEntity;
-    if (wrapper != null && !wrapper.isEmpty()) {
-      groupEntity = wrapper.get(0).groupEntity;
-      if (groupEntity == null) {
-        groupEntity = new DownloadGroupEntity();
-        groupEntity.setSubEntities(createSubTask(groupName, urls));
-      }
-    } else {
-      groupEntity = new DownloadGroupEntity();
-      groupEntity.setSubEntities(createSubTask(groupName, urls));
-    }
-    groupEntity.setGroupName(groupName);
-    groupEntity.setUrls(urls);
-    return groupEntity;
-  }
-
-  /**
-   * 创建子任务
-   */
-  private List<DownloadEntity> createSubTask(String groupName, List<String> urls) {
-    List<DownloadEntity> list = new ArrayList<>();
-    for (int i = 0, len = urls.size(); i < len; i++) {
-      DownloadEntity entity = new DownloadEntity();
-      entity.setUrl(urls.get(i));
-      entity.setDownloadPath(groupName + "_" + i);
-      entity.setFileName(groupName + "_" + i);
-      entity.setGroupName(groupName);
-      entity.setGroupChild(true);
-      list.add(entity);
-    }
-    return list;
-  }
-}

+ 0 - 0
Aria/src/main/java/com/arialyy/aria/core/manager/DTEFactory.java


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff