pull/330/head
AriaLyy 7 years ago
commit 5a70764596
  1. 106
      Aria/src/main/java/com/arialyy/aria/core/Aria.java
  2. 1
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  3. 103
      Aria/src/main/java/com/arialyy/aria/core/SubTaskManager.java
  4. 3
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
  5. 4
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java
  6. 39
      Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
  7. 8
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java
  8. 45
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java
  9. 45
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
  10. 8
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java
  11. 1
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
  12. 5
      Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java
  13. 5
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  14. 7
      Aria/src/main/java/com/arialyy/aria/core/common/ProxyHelper.java
  15. 3
      Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java
  16. 19
      Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java
  17. 13
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
  18. 33
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
  19. 2
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
  20. 4
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java
  21. 33
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  22. 124
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  23. 4
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  24. 118
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpClientHelp.java
  25. 2
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
  26. 6
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
  27. 11
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadGroupListener.java
  28. 4
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java
  29. 15
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
  30. 16
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java
  31. 36
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
  32. 10
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  33. 26
      Aria/src/main/java/com/arialyy/aria/core/inf/BaseGroupTaskEntity.java
  34. 34
      Aria/src/main/java/com/arialyy/aria/core/inf/GroupSendParams.java
  35. 4
      Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java
  36. 32
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulerListener.java
  37. 111
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  38. 4
      Aria/src/main/java/com/arialyy/aria/core/scheduler/ISchedulerListener.java
  39. 42
      Aria/src/main/java/com/arialyy/aria/core/scheduler/ISchedulers.java
  40. 1
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java
  41. 24
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
  42. 2
      Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
  43. 21
      Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
  44. 5
      Aria/src/main/java/com/arialyy/aria/orm/SqlUtil.java
  45. 31
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  46. 79
      AriaAnnotations/src/main/java/com/arialyy/annotations/DownloadGroup.java
  47. 11
      AriaCompiler/src/main/java/com/arialyy/compiler/AriaProcessor.java
  48. 127
      AriaCompiler/src/main/java/com/arialyy/compiler/CountFiler.java
  49. 581
      AriaCompiler/src/main/java/com/arialyy/compiler/ElementHandler.java
  50. 231
      AriaCompiler/src/main/java/com/arialyy/compiler/EventProxyFiler.java
  51. 221
      AriaCompiler/src/main/java/com/arialyy/compiler/ParamObtainUtil.java
  52. 2
      AriaCompiler/src/main/java/com/arialyy/compiler/PrintLog.java
  53. 23
      AriaCompiler/src/main/java/com/arialyy/compiler/ProxyClassParam.java
  54. 3
      AriaCompiler/src/main/java/com/arialyy/compiler/ProxyConstance.java
  55. 9
      AriaCompiler/src/main/java/com/arialyy/compiler/TaskEnum.java
  56. 175
      AriaCompiler/src/main/java/com/arialyy/compiler/ValuesUtil.java
  57. 1
      CHINESE_README.md
  58. 1
      DEV_LOG.md
  59. 34
      app/src/main/java/com/arialyy/simple/download/SimpleNotification.java
  60. 8
      app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
  61. 149
      app/src/main/java/com/arialyy/simple/download/group/ChildHandleDialog.java
  62. 26
      app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java
  63. 3
      app/src/main/java/com/arialyy/simple/download/multi_download/MultiTaskActivity.java
  64. 44
      app/src/main/java/com/arialyy/simple/widget/SubStateLinearLayout.java
  65. 5
      app/src/main/res/anim/dialog_enter.xml
  66. 6
      app/src/main/res/anim/dialog_exit.xml
  67. 14
      app/src/main/res/layout/activity_download_group.xml
  68. 76
      app/src/main/res/layout/dialog_sub_task_handler.xml
  69. 28
      app/src/main/res/values/strings.xml
  70. 17
      app/src/main/res/values/styles.xml
  71. 2
      build.gradle
  72. 4
      gradle.properties

@ -114,110 +114,4 @@ import com.arialyy.aria.core.upload.UploadTask;
throw new IllegalArgumentException("不支持的类型");
}
}
/**
* 上传任务状态监听
*
* @see Upload
* @deprecated 请使用注解函数的方式来实现事件的获取
*/
@Deprecated public static class UploadSchedulerListener
implements ISchedulerListener<UploadTask> {
/**
* 预处理有时有些地址链接比较慢这时可以先在这个地方出来一些界面上的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) {
}
}
/**
* 下载任务状态监听
*
* @see Download
* @deprecated 请使用注解函数的方式来实现事件的获取
*/
@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) {
}
}
}

@ -398,7 +398,6 @@ import org.xml.sax.SAXException;
if (key.contains(clsName)) {
IReceiver receiver = mReceivers.get(key);
if (receiver != null) {
receiver.removeSchedulerListener();
receiver.unRegister();
receiver.destroy();
}

@ -0,0 +1,103 @@
/*
* 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;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.command.group.GroupCmdFactory;
import com.arialyy.aria.core.inf.BaseGroupTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.util.List;
/**
* Created by lyy on 2017/9/4.
* 子任务管理器
*/
public class SubTaskManager {
private String TAG = "SubTaskManager";
private BaseGroupTaskEntity mEntity;
private String mTargetName;
public SubTaskManager(String targetName, BaseGroupTaskEntity entity) {
mTargetName = targetName;
mEntity = entity;
}
/**
* 启动任务组中的子任务
*
* @param url 子任务下载地址
*/
public void startSubTask(String url) {
if (checkUrl(url)) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(
CommonUtil.createGroupCmd(mTargetName, mEntity, GroupCmdFactory.SUB_TASK_START, url))
.exe();
}
}
/**
* 停止任务组中的子任务
*
* @param url 子任务下载地址
*/
public void stopSubTask(String url) {
if (checkUrl(url)) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(
CommonUtil.createGroupCmd(mTargetName, mEntity, GroupCmdFactory.SUB_TASK_STOP, url))
.exe();
}
}
/**
* 删除子任务组中的子任务
*
* @param url 子任务下载地址
*/
public void cancelSubTask(String url) {
if (checkUrl(url)) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(
CommonUtil.createGroupCmd(mTargetName, mEntity, GroupCmdFactory.SUB_TASK_CANCEL, url))
.exe();
}
}
/**
* 检查任务地址
*
* @param url 子任务地址
* @return {@code false} 任务地址不合法
*/
private boolean checkUrl(String url) {
if (TextUtils.isEmpty(url)) {
Log.e(TAG, "子任务地址不能为null");
return false;
}
List<String> urls = mEntity.getEntity().getUrls();
if (urls == null || urls.isEmpty()) {
Log.e(TAG, "任务组任务链接为null");
return false;
}
if (!urls.contains(url)) {
Log.e(TAG, "任务组中没有改Url【+ " + url + "】");
return false;
}
return true;
}
}

@ -22,11 +22,12 @@ 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} 上传任务的命令

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

@ -15,21 +15,26 @@
*/
package com.arialyy.aria.core.command.group;
import android.util.Log;
import com.arialyy.aria.core.command.AbsCmd;
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.core.inf.AbsGroupTask;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.BaseGroupTaskEntity;
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.util.CommonUtil;
/**
* Created by AriaL on 2017/6/29.
* 任务组命令
*/
abstract class AbsGroupCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
public abstract class AbsGroupCmd<T extends BaseGroupTaskEntity> extends AbsCmd<T> {
/**
* 需要控制的子任务url
*/
String childUrl;
AbsGroupTask tempTask;
/**
* @param targetName 创建任务的对象名
@ -43,4 +48,26 @@ abstract class AbsGroupCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
isDownloadCmd = true;
}
}
/**
* 创建任务
*
* @return 创建的任务
*/
AbsTask createTask() {
tempTask = (AbsGroupTask) mQueue.createTask(mTargetName, mTaskEntity);
return tempTask;
}
boolean checkTask() {
tempTask = (AbsGroupTask) mQueue.getTask(mTaskEntity.getEntity());
if (tempTask == null) {
createTask();
if (tempTask.isComplete()) {
Log.w(TAG, "任务已完成");
return false;
}
}
return true;
}
}

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

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

@ -15,18 +15,13 @@
*/
package com.arialyy.aria.core.command.group;
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;
import com.arialyy.aria.core.inf.BaseGroupTaskEntity;
/**
* Created by AriaL on 2017/6/29.
* 任务组开始命令该命令负责开始下载或恢复下载的操
* 任务组开始命令该命令负责处理任务组子任务的开始\恢复等工作
*/
class GroupStartCmd<T extends AbsTaskEntity> extends AbsGroupCmd<T> {
class GroupStartCmd<T extends BaseGroupTaskEntity> extends AbsGroupCmd<T> {
/**
* @param targetName 创建任务的对象名
*/
@ -35,38 +30,8 @@ class GroupStartCmd<T extends AbsTaskEntity> extends AbsGroupCmd<T> {
}
@Override public void executeCmd() {
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);
}
if (checkTask()) {
tempTask.startSubTask(childUrl);
}
}
}

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

@ -47,7 +47,6 @@ public class CancelAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
if (mTaskEntity instanceof DownloadTaskEntity
|| mTaskEntity instanceof DownloadGroupTaskEntity) {
handleDownloadRemove();
handleDownloadRemove();
handleDownloadGroupRemove();
} else if (mTaskEntity instanceof UploadTaskEntity) {
handleUploadRemove();

@ -24,7 +24,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
* Created by Lyy on 2016/9/23.
* 命令工厂
*/
public class NormalCmdFactory extends AbsCmdFactory<AbsNormalCmd> {
public class NormalCmdFactory extends AbsCmdFactory<AbsTaskEntity, AbsNormalCmd> {
/**
* 创建任务
*/
@ -82,7 +82,7 @@ public class NormalCmdFactory extends AbsCmdFactory<AbsNormalCmd> {
* @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}
*/
public <T extends AbsTaskEntity> AbsNormalCmd<T> createCmd(String target, T entity, int type) {
public AbsNormalCmd createCmd(String target, AbsTaskEntity entity, int type) {
switch (type) {
case TASK_CREATE:
return new AddCmd<>(target, entity);
@ -105,4 +105,5 @@ public class NormalCmdFactory extends AbsCmdFactory<AbsNormalCmd> {
return null;
}
}
}

@ -67,6 +67,10 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mConstance = new StateConstance();
}
public void setNewTask(boolean newTask) {
mTaskEntity.isNewTask = newTask;
}
@Override public void setMaxSpeed(double maxSpeed) {
for (int i = 0; i < mThreadNum; i++) {
AbsThreadTask task = mTask.get(i);
@ -134,6 +138,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
if (mTimer != null) {
mTimer.purge();
mTimer.cancel();
mTimer = null;
}
}

@ -27,7 +27,7 @@ import static java.util.Collections.unmodifiableSet;
* 代理参数获取
*/
public class ProxyHelper {
public Set<String> downloadCounter, uploadCounter, downloadGroupCounter;
public Set<String> downloadCounter, uploadCounter, downloadGroupCounter, downloadGroupSubCounter;
public static volatile ProxyHelper INSTANCE = null;
@ -49,6 +49,7 @@ public class ProxyHelper {
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);
@ -59,6 +60,10 @@ public class ProxyHelper {
if (dgc != null) {
downloadGroupCounter = unmodifiableSet((Set<String>) dgc);
}
Object dgsc = downloadGroupSub.invoke(object);
if (dgsc != null){
downloadGroupSubCounter = unmodifiableSet((Set<? extends String>) dgsc);
}
Object uc = upload.invoke(object);
if (uc != null) {
uploadCounter = unmodifiableSet((Set<String>) uc);

@ -30,7 +30,7 @@ import java.lang.ref.WeakReference;
*/
class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
implements IDownloadListener {
private WeakReference<Handler> outHandler;
protected WeakReference<Handler> outHandler;
private long mLastLen = 0; //上一次发送长度
private boolean isFirst = true;
protected ENTITY mEntity;
@ -117,6 +117,7 @@ class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
} else {
mEntity.setSpeed(speed < 0 ? 0 : speed);
}
mEntity.setPercent((int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()));
}
/**

@ -16,9 +16,10 @@
package com.arialyy.aria.core.download;
import android.text.TextUtils;
import com.arialyy.aria.core.SubTaskManager;
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.core.inf.BaseGroupTaskEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
@ -28,7 +29,7 @@ import java.util.List;
/**
* Created by Aria.Lao on 2017/7/26.
*/
abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends AbsTaskEntity>
abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends BaseGroupTaskEntity>
extends AbsDownloadTarget<TARGET, DownloadGroupEntity, TASK_ENTITY> {
List<String> mUrls = new ArrayList<>();
@ -42,6 +43,8 @@ abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends Abs
*/
private boolean isSetDirPathed = false;
private SubTaskManager mSubTaskManager;
/**
* 查询任务组实体如果数据库不存在该实体则新创建一个新的任务组实体
*/
@ -57,6 +60,18 @@ abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends Abs
return entity;
}
/**
* 获取子任务管理器
*
* @return 子任务管理器
*/
public SubTaskManager getSubTaskManager() {
if (mSubTaskManager == null) {
mSubTaskManager = new SubTaskManager(mTargetName, mTaskEntity);
}
return mSubTaskManager;
}
/**
* 设置任务组别名
*/

@ -31,11 +31,6 @@ public class DownloadGroupEntity extends AbsGroupEntity {
@OneToMany(table = DownloadEntity.class, key = "groupName") private List<DownloadEntity> subtask =
new ArrayList<>();
/**
* 子任务链接组
*/
@NormalList(clazz = String.class) private List<String> urls = new ArrayList<>();
/**
* 任务组下载文件的文件夹地址
*
@ -59,14 +54,6 @@ public class DownloadGroupEntity extends AbsGroupEntity {
this.dirPath = dirPath;
}
public List<String> getUrls() {
return urls;
}
public void setUrls(List<String> urls) {
this.urls = urls;
}
void setGroupName(String key) {
this.groupName = key;
}

@ -17,6 +17,8 @@ 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.
@ -25,9 +27,16 @@ import com.arialyy.aria.core.download.downloader.IDownloadGroupListener;
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) {
@ -35,23 +44,43 @@ class DownloadGroupListener extends BaseDListener<DownloadGroupEntity, DownloadG
}
@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 entity) {
@Override public void onSubCancel(DownloadEntity subEntity) {
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() {

@ -19,6 +19,7 @@ import android.os.Handler;
import android.os.Looper;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.downloader.AbsGroupUtil;
import com.arialyy.aria.core.download.downloader.DownloadGroupUtil;
import com.arialyy.aria.core.download.downloader.FtpDirDownloadUtil;
import com.arialyy.aria.core.inf.AbsGroupTask;
@ -33,7 +34,6 @@ import com.arialyy.aria.util.CheckUtil;
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;

@ -15,13 +15,13 @@
*/
package com.arialyy.aria.core.download;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.BaseGroupTaskEntity;
import com.arialyy.aria.orm.OneToOne;
/**
* Created by AriaL on 2017/7/1.
*/
public class DownloadGroupTaskEntity extends AbsTaskEntity<DownloadGroupEntity> {
public class DownloadGroupTaskEntity extends BaseGroupTaskEntity<DownloadGroupEntity> {
@OneToOne(table = DownloadGroupEntity.class, key = "groupName") public DownloadGroupEntity entity;

@ -139,10 +139,12 @@ 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)) {
if ((dgCounter != null && dgCounter.contains(className)) || (dgsCounter != null
&& dgsCounter.contains(className))) {
DownloadGroupSchedulers.getInstance().register(obj);
}
return this;
@ -155,10 +157,12 @@ 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().unRegister(obj);
}
if (dgCounter != null && dgCounter.contains(className)) {
if (dgCounter != null && dgCounter.contains(className) || (dgsCounter != null
&& dgsCounter.contains(className))) {
DownloadGroupSchedulers.getInstance().unRegister(obj);
}
if (needRmReceiver) {
@ -166,29 +170,6 @@ public class DownloadReceiver extends AbsReceiver {
}
}
/**
* 添加调度器回调
*
* @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;
@ -300,7 +281,7 @@ public class DownloadReceiver extends AbsReceiver {
@Override public void removeAllTask(boolean removeFile) {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
CancelAllCmd cancelCmd =
(CancelAllCmd) CommonUtil.createCmd(targetName, new DownloadTaskEntity(),
(CancelAllCmd) CommonUtil.createNormalCmd(targetName, new DownloadTaskEntity(),
NormalCmdFactory.TASK_CANCEL_ALL);
cancelCmd.removeFile = removeFile;
ariaManager.setCmd(cancelCmd).exe();

@ -15,6 +15,7 @@
*/
package com.arialyy.aria.core.download.downloader;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.DownloadEntity;
@ -38,7 +39,7 @@ import java.util.concurrent.Executors;
* Created by AriaL on 2017/6/30.
* 任务组核心逻辑
*/
abstract class AbsGroupUtil implements IUtil {
public abstract class AbsGroupUtil implements IUtil {
private final String TAG = "AbsGroupUtil";
/**
* 任务组所有任务总大小
@ -48,7 +49,7 @@ abstract class AbsGroupUtil implements IUtil {
private ExecutorService mExePool;
protected IDownloadGroupListener mListener;
protected DownloadGroupTaskEntity mTaskEntity;
private boolean isRunning = true;
private boolean isRunning = false;
private Timer mTimer;
/**
* 初始化完成的任务书数
@ -81,6 +82,8 @@ abstract class AbsGroupUtil implements IUtil {
private int mCompleteNum = 0;
//失败的任务数
private int mFailNum = 0;
//停止的任务数
private int mStopNum = 0;
//实际的下载任务数
int mActualTaskNum = 0;
/**
@ -97,6 +100,7 @@ abstract class AbsGroupUtil implements IUtil {
if (tasks != null && !tasks.isEmpty()) {
for (DownloadTaskEntity te : tasks) {
te.removeFile = mTaskEntity.removeFile;
if (te.getEntity() == null) continue;
mTasksMap.put(te.getEntity().getUrl(), te);
}
}
@ -107,6 +111,7 @@ abstract class AbsGroupUtil implements IUtil {
if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) {
mCompleteNum++;
mInitNum++;
mStopNum++;
mCurrentLocation += entity.getFileSize();
} else {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
@ -127,6 +132,84 @@ abstract class AbsGroupUtil implements IUtil {
}
}
/**
* 启动子任务下载
*
* @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 cancelSunTask(String url) {
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) {
Log.w(TAG, "任务【" + url + "】已完成," + type + "失败");
return false;
}
} else {
Log.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);
}
return d;
}
@Override public long getFileSize() {
return mTotalSize;
}
@ -232,6 +315,7 @@ abstract class AbsGroupUtil implements IUtil {
if (mTimer != null) {
mTimer.purge();
mTimer.cancel();
mTimer = null;
}
}
@ -242,6 +326,10 @@ abstract class AbsGroupUtil implements IUtil {
closeTimer(true);
mListener.onPostPre(mTotalSize);
mListener.onStart(mCurrentLocation);
startTimer();
}
private void startTimer() {
mTimer = new Timer(true);
mTimer.schedule(new TimerTask() {
@Override public void run() {
@ -255,15 +343,27 @@ abstract class AbsGroupUtil implements IUtil {
}
/**
* 启动子任务下载器
* 创建子任务下载器默认创建完成自动启动
*/
Downloader createChildDownload(DownloadTaskEntity taskEntity) {
return createChildDownload(taskEntity, true);
}
/**
* 创建子任务下载器启动子任务下载器
*
* @param start 是否启动下载
*/
void startChildDownload(DownloadTaskEntity taskEntity) {
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;
if (mExePool.isShutdown()) return dt;
if (start) {
mExePool.execute(dt);
}
return dt;
}
/**
* 创建子任务下载信息
@ -276,6 +376,7 @@ abstract class AbsGroupUtil implements IUtil {
taskEntity.userName = mTaskEntity.userName;
taskEntity.userPw = mTaskEntity.userPw;
taskEntity.account = mTaskEntity.account;
mTasksMap.put(entity.getUrl(), taskEntity);
return taskEntity;
}
taskEntity = new DownloadTaskEntity();
@ -293,6 +394,7 @@ abstract class AbsGroupUtil implements IUtil {
taskEntity.account = mTaskEntity.account;
taskEntity.key = entity.getDownloadPath();
taskEntity.save();
mTasksMap.put(entity.getUrl(), taskEntity);
return taskEntity;
}
@ -321,30 +423,39 @@ abstract class AbsGroupUtil implements IUtil {
entity.setFileSize(fileSize);
entity.setConvertFileSize(CommonUtil.formatFileSize(fileSize));
saveData(IEntity.STATE_POST_PRE, -1);
mListener.onSubPre(entity);
}
@Override public void onResume(long resumeLocation) {
saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
lastLen = resumeLocation;
mListener.onSubStart(entity);
}
@Override public void onStart(long startLocation) {
saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
lastLen = startLocation;
mListener.onSubStart(entity);
}
@Override public void onProgress(long currentLocation) {
long speed = currentLocation - lastLen;
mCurrentLocation += speed;
lastLen = currentLocation;
entity.setCurrentProgress(currentLocation);
handleSpeed(speed);
mListener.onSubRunning(entity);
lastLen = currentLocation;
}
@Override public void onStop(long stopLocation) {
saveData(IEntity.STATE_STOP, stopLocation);
handleSpeed(0);
mListener.onSubStop(entity);
mStopNum++;
if (mStopNum + mCompleteNum >= mInitNum) {
closeTimer(false);
mListener.onStop(mCurrentLocation);
}
}
@Override public void onCancel() {
@ -407,6 +518,7 @@ abstract class AbsGroupUtil implements IUtil {
private void handleSpeed(long speed) {
entity.setSpeed(speed);
entity.setConvertSpeed(speed <= 0 ? "" : CommonUtil.formatFileSize(speed) + "/s");
entity.setPercent((int) (entity.getCurrentProgress() * 100 / entity.getFileSize()));
}
private void saveData(int state, long location) {

@ -65,7 +65,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
if (taskEntity != null) {
if (taskEntity.getState() != IEntity.STATE_FAIL
&& taskEntity.getState() != IEntity.STATE_WAIT) {
startChildDownload(taskEntity);
createChildDownload(taskEntity);
i++;
} else {
mInfoPool.execute(createFileInfoThread(taskEntity));
@ -94,7 +94,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
if (isNeedLoadFileSize) {
mTotalSize += te.getEntity().getFileSize();
}
startChildDownload(te);
createChildDownload(te);
}
mInitNum++;
if (mInitNum + mInitFailNum >= mTaskEntity.getEntity().getSubTask().size()

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

@ -60,7 +60,7 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
for (String key : keys) {
DownloadTaskEntity taskEntity = mExeMap.get(key);
if (taskEntity != null) {
startChildDownload(taskEntity);
createChildDownload(taskEntity);
i++;
}
}

@ -24,6 +24,7 @@ import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
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;
@ -45,7 +46,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
@Override public void run() {
HttpURLConnection conn = null;
InputStream is = null;
BufferedInputStream is = null;
BufferedRandomAccessFile file = null;
try {
URL url = new URL(CommonUtil.convertUrl(mConfig.URL));
@ -69,7 +70,8 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn);
conn.setConnectTimeout(STATE.CONNECT_TIME_OUT);
conn.setReadTimeout(STATE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数
is = conn.getInputStream();
//is = conn.getInputStream();
is = new BufferedInputStream(conn.getInputStream());
//创建可设置位置的文件
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
//设置每条线程写入文件的位置

@ -17,7 +17,6 @@ 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,6 +24,11 @@ import com.arialyy.aria.core.inf.IEventListener;
*/
public interface IDownloadGroupListener extends IDownloadListener {
/**
* 子任务预处理
*/
void onSubPre(DownloadEntity subEntity);
/**
* 子任务支持断点回调
*
@ -56,4 +60,9 @@ public interface IDownloadGroupListener extends IDownloadListener {
* 子任务取消下载
*/
void onSubCancel(DownloadEntity subEntity);
/**
* 子任务执行中
*/
void onSubRunning(DownloadEntity subEntity);
}

@ -98,7 +98,7 @@ public abstract class AbsDownloadTarget<TARGET extends AbsTarget, ENTITY extends
protected void setHighestPriority() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(
CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_HIGHEST_PRIORITY))
CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_HIGHEST_PRIORITY))
.exe();
}
@ -136,7 +136,7 @@ public abstract class AbsDownloadTarget<TARGET extends AbsTarget, ENTITY extends
*/
public void add() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE))
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE))
.exe();
}

@ -60,6 +60,11 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
*/
private long completeTime;
/**
* 进度百分比
*/
@Ignore private int percent;
private boolean isComplete = false;
public boolean isComplete() {
@ -142,6 +147,14 @@ 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;
}
/**
* 实体唯一标识符
*/
@ -165,6 +178,7 @@ 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) {
@ -178,5 +192,6 @@ 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();
}
}

@ -17,7 +17,10 @@ package com.arialyy.aria.core.inf;
import android.os.Parcel;
import android.os.Parcelable;
import com.arialyy.aria.orm.NormalList;
import com.arialyy.aria.orm.Primary;
import java.util.ArrayList;
import java.util.List;
/**
* Created by AriaL on 2017/6/3.
@ -33,6 +36,19 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
*/
private String alias = "";
/**
* 子任务链接组
*/
@NormalList(clazz = String.class) private List<String> urls = new ArrayList<>();
public List<String> getUrls() {
return urls;
}
public void setUrls(List<String> urls) {
this.urls = urls;
}
public String getGroupName() {
return groupName;
}

@ -15,17 +15,53 @@
*/
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 AbsTaskEntity, ENTITY extends AbsGroupEntity>
extends AbsTask<ENTITY> {
protected TASK_ENTITY mTaskEntity;
protected AbsGroupUtil mUtil;
@Override public String getKey() {
return mEntity.getGroupName();
}
/**
* 启动任务组中的子任务
*
* @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.cancelSunTask(url);
}
}
}

@ -162,7 +162,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*/
@Override public void start() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
.exe();
}
@ -177,7 +177,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
@Override public void stop() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP))
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP))
.exe();
}
@ -186,7 +186,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*/
@Override public void resume() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
.exe();
}
@ -195,7 +195,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*/
@Override public void cancel() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL))
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL))
.exe();
}
@ -207,7 +207,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*/
public void cancel(boolean removeFile) {
CancelCmd cancelCmd =
(CancelCmd) CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL);
(CancelCmd) CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL);
cancelCmd.removeFile = removeFile;
AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe();
}

@ -0,0 +1,26 @@
/*
* 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 BaseGroupTaskEntity<ENTITY extends AbsGroupEntity> extends AbsTaskEntity<ENTITY>{
@Override public ENTITY getEntity() {
return null;
}
}

@ -0,0 +1,34 @@
/*
* 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;
}
}

@ -26,10 +26,6 @@ public interface IReceiver<ENTITY extends IEntity> {
*/
void destroy();
/**
* 移除事件回调
*/
void removeSchedulerListener();
/**
* 移除观察者

@ -15,12 +15,14 @@
*/
package com.arialyy.aria.core.scheduler;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.ITask;
/**
* Created by Aria.Lao on 2017/6/7.
*/
public class AbsSchedulerListener<TASK extends ITask> implements ISchedulerListener<TASK> {
public class AbsSchedulerListener<TASK extends ITask, SUB_ENTITY extends AbsNormalEntity> implements ISchedulerListener<TASK> {
@Override public void onPre(TASK task) {
}
@ -64,4 +66,32 @@ public class AbsSchedulerListener<TASK extends ITask> implements ISchedulerListe
public void setListener(Object obj) {
}
public void onSubTaskPre(TASK task, SUB_ENTITY subTask) {
}
public void onSubTaskStart(TASK task, SUB_ENTITY subTask) {
}
public void onSubTaskStop(TASK task, SUB_ENTITY subTask) {
}
public void onSubTaskCancel(TASK task, SUB_ENTITY subTask) {
}
public void onSubTaskComplete(TASK task, SUB_ENTITY subTask) {
}
public void onSubTaskFail(TASK task, SUB_ENTITY subTask) {
}
public void onSubTaskRunning(TASK task, SUB_ENTITY subTask) {
}
}

@ -21,8 +21,10 @@ import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsEntity;
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.GroupSendParams;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.queue.ITaskQueue;
import com.arialyy.aria.core.upload.UploadTask;
@ -45,9 +47,8 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
protected QUEUE mQueue;
private Map<String, ISchedulerListener<TASK>> mSchedulerListeners = new ConcurrentHashMap<>();
private Map<String, AbsSchedulerListener<TASK>> mObservers = new ConcurrentHashMap<>();
private Map<String, AbsSchedulerListener<TASK, AbsNormalEntity>> mObservers =
new ConcurrentHashMap<>();
/**
* 设置调度器类型
@ -59,33 +60,9 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
*/
abstract String getProxySuffix();
/**
* @param targetName 观察者创建该监听器的对象类名
* @param schedulerListener {@link ISchedulerListener}
* @see #register(Object)
*/
@Deprecated @Override public void addSchedulerListener(String targetName,
ISchedulerListener<TASK> schedulerListener) {
mSchedulerListeners.put(targetName, schedulerListener);
}
/**
* @param targetName 观察者创建该监听器的对象类名
* @see #unRegister(Object)
*/
@Override public void removeSchedulerListener(String targetName,
ISchedulerListener<TASK> schedulerListener) {
//该内存泄露解决方案:http://stackoverflow.com/questions/14585829/how-safe-is-to-delete-already-removed-concurrenthashmap-element
for (Iterator<Map.Entry<String, ISchedulerListener<TASK>>> iter =
mSchedulerListeners.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<String, ISchedulerListener<TASK>> entry = iter.next();
if (entry.getKey().equals(targetName)) iter.remove();
}
}
@Override public void register(Object obj) {
String targetName = obj.getClass().getName();
AbsSchedulerListener<TASK> listener = mObservers.get(targetName);
AbsSchedulerListener<TASK, AbsNormalEntity> listener = mObservers.get(targetName);
if (listener == null) {
listener = createListener(targetName);
if (listener != null) {
@ -98,9 +75,9 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
}
@Override public void unRegister(Object obj) {
for (Iterator<Map.Entry<String, AbsSchedulerListener<TASK>>> iter =
for (Iterator<Map.Entry<String, AbsSchedulerListener<TASK, AbsNormalEntity>>> iter =
mObservers.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<String, AbsSchedulerListener<TASK>> entry = iter.next();
Map.Entry<String, AbsSchedulerListener<TASK, AbsNormalEntity>> entry = iter.next();
if (entry.getKey().equals(obj.getClass().getName())) iter.remove();
}
}
@ -110,11 +87,11 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
*
* @param targetName 通过观察者创建对应的Aria事件代理
*/
private AbsSchedulerListener<TASK> createListener(String targetName) {
AbsSchedulerListener<TASK> listener = null;
private AbsSchedulerListener<TASK, AbsNormalEntity> createListener(String targetName) {
AbsSchedulerListener<TASK, AbsNormalEntity> listener = null;
try {
Class clazz = Class.forName(targetName + getProxySuffix());
listener = (AbsSchedulerListener<TASK>) clazz.newInstance();
listener = (AbsSchedulerListener<TASK, AbsNormalEntity>) clazz.newInstance();
} catch (ClassNotFoundException e) {
Log.e(TAG, targetName + ",没有Aria的Download或Upload注解方法");
} catch (InstantiationException e) {
@ -126,13 +103,62 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
}
@Override public boolean handleMessage(Message msg) {
if (msg.arg1 == IS_SUB_TASK) {
return handleSubEvent(msg);
}
TASK task = (TASK) msg.obj;
if (task == null) {
Log.e(TAG, "请传入下载任务");
return true;
}
ENTITY entity = task.getEntity();
handleNormalEvent(task, msg.what);
return true;
}
/**
* 处理任务组子任务事件
*/
private boolean handleSubEvent(Message msg) {
GroupSendParams params = (GroupSendParams) msg.obj;
if (mObservers.size() > 0) {
Set<String> keys = mObservers.keySet();
for (String key : keys) {
AbsSchedulerListener<TASK, AbsNormalEntity> listener = mObservers.get(key);
switch (msg.what) {
case SUB_PRE:
listener.onSubTaskPre((TASK) params.groupTask, params.entity);
break;
case SUB_START:
listener.onSubTaskStart((TASK) params.groupTask, params.entity);
break;
case SUB_STOP:
listener.onSubTaskStop((TASK) params.groupTask, params.entity);
break;
case SUB_FAIL:
listener.onSubTaskFail((TASK) params.groupTask, params.entity);
break;
case SUB_RUNNING:
listener.onSubTaskRunning((TASK) params.groupTask, params.entity);
break;
case SUB_CANCEL:
listener.onSubTaskCancel((TASK) params.groupTask, params.entity);
break;
case SUB_COMPLETE:
listener.onSubTaskComplete((TASK) params.groupTask, params.entity);
break;
}
}
}
return true;
}
/**
* 处理普通任务事件
*/
private void handleNormalEvent(TASK task, int what) {
ENTITY entity = task.getEntity();
switch (what) {
case STOP:
if (task.getEntity().getState() == IEntity.STATE_WAIT) {
break;
@ -153,8 +179,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
handleFailTask(task);
break;
}
callback(msg.what, task);
return true;
callback(what, task);
}
/**
@ -163,12 +188,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
* @param state 状态
*/
private void callback(int state, TASK task) {
if (mSchedulerListeners.size() > 0) {
Set<String> keys = mSchedulerListeners.keySet();
for (String key : keys) {
callback(state, task, mSchedulerListeners.get(key));
}
} else if (mObservers.size() > 0) {
if (mObservers.size() > 0) {
Set<String> keys = mObservers.keySet();
for (String key : keys) {
callback(state, task, mObservers.get(key));
@ -176,7 +196,8 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
}
}
private void callback(int state, TASK task, ISchedulerListener<TASK> listener) {
private void callback(int state, TASK task,
AbsSchedulerListener<TASK, AbsNormalEntity> listener) {
if (listener != null) {
if (task == null) {
Log.e(TAG, "TASK 为null,回调失败");
@ -211,9 +232,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
listener.onTaskFail(task);
break;
case SUPPORT_BREAK_POINT:
if (listener instanceof IDownloadSchedulerListener) {
((IDownloadSchedulerListener<TASK>) listener).onNoSupportBreakPoint(task);
}
listener.onNoSupportBreakPoint(task);
break;
}
}

@ -66,4 +66,8 @@ public interface ISchedulerListener<TASK extends ITask> {
* 任务执行中
*/
void onTaskRunning(TASK task);
}

@ -24,6 +24,11 @@ import com.arialyy.aria.core.inf.AbsTask;
* 调度器功能接口
*/
public interface ISchedulers<Task extends AbsTask> extends Handler.Callback {
/**
* 为任务组任务
*/
int IS_SUB_TASK = 0xd1;
/**
* 断点支持
*/
@ -67,18 +72,39 @@ public interface ISchedulers<Task extends AbsTask> extends Handler.Callback {
int RESUME = 8;
/**
* 注册下载器监听一个观察者只能注册一次监听
*
* @param targetName 观察者创建该监听器的对象类名
* @param schedulerListener {@link ISchedulerListener}
* 任务组子任务预处理
*/
int SUB_PRE = 0xa1;
/**
* 任务组子任务开始
*/
int SUB_START = 0xa2;
/**
* 任务组子任务停止
*/
int SUB_STOP = 0xa3;
/**
* 任务组子任务取消
*/
int SUB_CANCEL = 0xa4;
/**
* 任务组子任务失败
*/
int SUB_FAIL = 0xa5;
/**
* 任务组子任务执行执行中
*/
void addSchedulerListener(String targetName, ISchedulerListener<Task> schedulerListener);
int SUB_RUNNING = 0xa6;
/**
* @param targetName 观察者创建该监听器的对象类名
* 取消注册监听器
* 任务组子任务完成
*/
void removeSchedulerListener(String targetName, ISchedulerListener<Task> schedulerListener);
int SUB_COMPLETE = 0xa7;
/**
* 将当前类注册到Aria

@ -106,6 +106,7 @@ class BaseUListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
} else {
mEntity.setSpeed(speed < 0 ? 0 : speed);
}
mEntity.setPercent((int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()));
}
/**

@ -92,13 +92,11 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
@Override public void removeAllTask(boolean removeFile) {
final AriaManager am = AriaManager.getInstance(AriaManager.APP);
am.setCmd(CommonUtil.createCmd(targetName, new DownloadTaskEntity(),
am.setCmd(CommonUtil.createNormalCmd(targetName, new DownloadTaskEntity(),
NormalCmdFactory.TASK_CANCEL_ALL)).exe();
Set<String> keys = am.getReceiver().keySet();
for (String key : keys) {
IReceiver receiver = am.getReceiver().get(key);
receiver.removeSchedulerListener();
am.getReceiver().remove(key);
}
}
@ -108,26 +106,6 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
listener = null;
}
/**
* 添加调度器回调
*
* @see #register()
*/
@Deprecated public UploadReceiver addSchedulerListener(ISchedulerListener<UploadTask> listener) {
this.listener = listener;
UploadSchedulers.getInstance().addSchedulerListener(targetName, listener);
return this;
}
/**
* @see #unRegister()
*/
@Deprecated @Override public void removeSchedulerListener() {
if (listener != null) {
UploadSchedulers.getInstance().removeSchedulerListener(targetName, listener);
}
}
/**
* 将当前类注册到Aria
*/

@ -33,7 +33,7 @@ import java.util.Map;
class DBConfig {
static Map<String, Class> mapping = new HashMap<>();
static String DB_NAME;
static int VERSION = 14;
static int VERSION = 15;
static {
if (TextUtils.isEmpty(DB_NAME)) {

@ -26,6 +26,7 @@ import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
@ -180,7 +181,7 @@ final class SqlHelper extends SQLiteOpenHelper {
print(FIND_DATA, sql);
Cursor cursor = db.rawQuery(sql, null);
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
cursor.close();
closeCursor(cursor);
close(db);
return data;
}
@ -223,7 +224,7 @@ final class SqlHelper extends SQLiteOpenHelper {
print(FIND_DATA, sb.toString());
Cursor cursor = db.rawQuery(sb.toString(), null);
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
cursor.close();
closeCursor(cursor);
close(db);
return data;
}
@ -238,7 +239,7 @@ final class SqlHelper extends SQLiteOpenHelper {
print(FIND_ALL_DATA, sb.toString());
Cursor cursor = db.rawQuery(sb.toString(), null);
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
cursor.close();
closeCursor(cursor);
close(db);
return data;
}
@ -394,7 +395,7 @@ final class SqlHelper extends SQLiteOpenHelper {
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) cursor.close();
closeCursor(cursor);
close(db);
}
return false;
@ -564,7 +565,7 @@ final class SqlHelper extends SQLiteOpenHelper {
entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
entitys.add(entity);
}
cursor.close();
closeCursor(cursor);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
@ -586,6 +587,16 @@ final class SqlHelper extends SQLiteOpenHelper {
return findData(db, params[0], params[1] + "=?", primary);
}
private static void closeCursor(Cursor cursor){
if (cursor != null && !cursor.isClosed()) {
try {
cursor.close();
} catch (android.database.SQLException e) {
e.printStackTrace();
}
}
}
private static void close(SQLiteDatabase db) {
//if (db != null && db.isOpen()) db.close();
}

@ -145,8 +145,11 @@ final class SqlUtil {
// field.isSynthetic(), 使用as热启动App时,AS会自动给你的class添加change字段
Ignore ignore = field.getAnnotation(Ignore.class);
int modifiers = field.getModifiers();
String fieldName = field.getName();
return (ignore != null && ignore.value())
|| field.getName().equals("rowID")
|| fieldName.equals("rowID")
|| fieldName.equals("shadow$_klass_")
|| fieldName.equals("shadow$_monitor_")
|| field.isSynthetic()
|| Modifier.isStatic(modifiers)
|| Modifier.isFinal(modifiers);

@ -24,13 +24,16 @@ import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.command.group.AbsGroupCmd;
import com.arialyy.aria.core.command.group.GroupCmdFactory;
import com.arialyy.aria.core.command.normal.AbsNormalCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
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.core.inf.BaseGroupTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.orm.DbEntity;
@ -43,6 +46,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URLEncoder;
@ -58,11 +66,6 @@ import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
/**
* Created by lyy on 2016/1/22.
@ -432,10 +435,24 @@ public class CommonUtil {
}
}
public static <T extends AbsTaskEntity> AbsNormalCmd createCmd(String target, T entity, int cmd) {
/**
* 创建任务命令
*/
public static <T extends AbsTaskEntity> AbsNormalCmd createNormalCmd(String target, T entity,
int cmd) {
return NormalCmdFactory.getInstance().createCmd(target, entity, cmd);
}
/**
* 创建任务组命令
*
* @param childUrl 子任务url
*/
public static <T extends BaseGroupTaskEntity> AbsGroupCmd createGroupCmd(String target, T entity,
int cmd, String childUrl) {
return GroupCmdFactory.getInstance().createCmd(target, entity, cmd, childUrl);
}
/**
* 创建隐性的Intent
*/

@ -25,75 +25,134 @@ import java.lang.annotation.Target;
* Aria下载事件被注解的方法中参数仅能有一个参数类型为{@link com.arialyy.aria.core.download.DownloadGroupTask}
* <pre>
* <code>
* {@literal @}Download.onPre(groupName)
* {@literal @}DownloadGroup.onPre(groupName)
* protected void onPre(DownloadGroupTask task) {
* }
* </code>
* </pre>
* {@literal @}Download.onPre("myGroupName")如果你的注解中增加了url描述
* 则表示所有下载任务中只有下载地址为"myGroupName"的任务才能回调该注解的方法
*
*
* 如果希望获取子任务的状态可以使用onSub..类的注解
* <pre>
* <code>
* {@literal @}DownloadGroup.onSubPre(groupName)
* protected void onPre(DownloadGroupTask task, String url) {
* }
* </code>
* </pre>
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface DownloadGroup {
/**
* 如果你在方法中添加{@code @Download.onPre}注解在预处理完成时Aria会调用该方法
* 如果你在方法中添加{@code @DownloadGroup.onPre}注解在预处理完成时Aria会调用该方法
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onPre {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 如果你在方法中添加{@code @Download.onTaskPre}注解在任务预处理完成时Aria会调用该方法
* 如果你在方法中添加{@code @DownloadGroup.onTaskPre}注解在任务预处理完成时Aria会调用该方法
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskPre {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 如果你在方法中添加{@code @Download.onTaskResume}注解在任务恢复下载时Aria会调用该方法
* 如果你在方法中添加{@code @DownloadGroup.onTaskResume}注解在任务恢复下载时Aria会调用该方法
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskResume {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 如果你在方法中添加{@code @Download.onTaskStart}注解在任务开始下载时Aria会调用该方法
* 如果你在方法中添加{@code @DownloadGroup.onTaskStart}注解在任务开始下载时Aria会调用该方法
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStart {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 如果你在方法中添加{@code @Download.onTaskStop}注解在任务停止时Aria会调用该方法
* 如果你在方法中添加{@code @DownloadGroup.onTaskStop}注解在任务停止时Aria会调用该方法
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStop {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 如果你在方法中添加{@code @Download.onTaskCancel}l注解在任务取消时Aria会调用该方法
* 如果你在方法中添加{@code @DownloadGroup.onTaskCancel}l注解在任务取消时Aria会调用该方法
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskCancel {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 如果你在方法中添加{@code @Download.onTaskFail)注解在任务预失败时Aria会调用该方法
* 如果你在方法中添加{@code @DownloadGroup.onTaskFail)注解在任务预失败时Aria会调用该方法
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskFail {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 如果你在方法中添加{@code @Download.onTaskComplete}注解在任务完成时Aria会调用该方法
* 如果你在方法中添加{@code @DownloadGroup.onTaskComplete}注解在任务完成时Aria会调用该方法
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskComplete {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 如果你在方法中添加{@code @Download.onTaskRunning}注解在任务正在下载Aria会调用该方法
* 如果你在方法中添加{@code @DownloadGroup.onTaskRunning}注解在任务正在下载Aria会调用该方法
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskRunning {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 任务组子任务预处理的注解
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onSubTaskPre {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 任务组子任务开始的注解
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onSubTaskStart {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 任务组子任务停止的注解
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onSubTaskStop {
String[] value() default { AriaConstance.NO_URL };
}
///**
// * 任务组子任务删除的注解
// */
//@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onSubTaskCancel {
// String[] value() default { AriaConstance.NO_URL };
//}
/**
* 任务组子任务失败的注解
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onSubTaskFail {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 任务组子任务完成的注解
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onSubTaskComplete {
String[] value() default { AriaConstance.NO_URL };
}
/**
* 任务组子任务正在执行的注解
*/
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onSubTaskRunning {
String[] value() default { AriaConstance.NO_URL };
}
}

@ -54,7 +54,7 @@ import javax.lang.model.element.TypeElement;
annotataions.add(Download.onTaskRunning.class.getCanonicalName());
annotataions.add(Download.onTaskStart.class.getCanonicalName());
annotataions.add(Download.onTaskStop.class.getCanonicalName());
//下载任务的注解
//下载任务的注解
annotataions.add(DownloadGroup.onPre.class.getCanonicalName());
annotataions.add(DownloadGroup.onTaskCancel.class.getCanonicalName());
annotataions.add(DownloadGroup.onTaskComplete.class.getCanonicalName());
@ -64,6 +64,14 @@ import javax.lang.model.element.TypeElement;
annotataions.add(DownloadGroup.onTaskRunning.class.getCanonicalName());
annotataions.add(DownloadGroup.onTaskStart.class.getCanonicalName());
annotataions.add(DownloadGroup.onTaskStop.class.getCanonicalName());
//任务组子任务的注解
annotataions.add(DownloadGroup.onSubTaskPre.class.getCanonicalName());
//annotataions.add(DownloadGroup.onSubTaskCancel.class.getCanonicalName());
annotataions.add(DownloadGroup.onSubTaskComplete.class.getCanonicalName());
annotataions.add(DownloadGroup.onSubTaskFail.class.getCanonicalName());
annotataions.add(DownloadGroup.onSubTaskRunning.class.getCanonicalName());
annotataions.add(DownloadGroup.onSubTaskStart.class.getCanonicalName());
annotataions.add(DownloadGroup.onSubTaskStop.class.getCanonicalName());
//上传任务的注解
annotataions.add(Upload.onPre.class.getCanonicalName());
annotataions.add(Upload.onNoSupportBreakPoint.class.getCanonicalName());
@ -86,6 +94,7 @@ import javax.lang.model.element.TypeElement;
mHandler.clean();
mHandler.handleDownload(roundEnv);
mHandler.handleDownloadGroup(roundEnv);
mHandler.handleDownloadGroupSub(roundEnv);
mHandler.handleUpload(roundEnv);
mHandler.createProxyFile();
return true;

@ -0,0 +1,127 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.compiler;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.Filer;
import javax.lang.model.element.Modifier;
/**
* Created by lyy on 2017/9/6.
* 各类注解统计技术类
*/
final class CountFiler {
private Filer mFiler;
private ParamObtainUtil mPbUtil;
CountFiler(Filer filer, ParamObtainUtil pbUtil) {
mFiler = filer;
mPbUtil = pbUtil;
}
/**
* 每一种注解对应的统计类
*/
void createCountFile() throws IOException {
Set<String> keys = mPbUtil.getListenerClass().keySet();
if (keys.size() == 0) return;
TypeSpec.Builder builder = TypeSpec.classBuilder(ProxyConstance.PROXY_COUNTER_NAME)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
FieldSpec mappingField = FieldSpec.builder(
ParameterizedTypeName.get(ClassName.get(Map.class), ClassName.get(String.class),
ParameterizedTypeName.get(ClassName.get(Set.class), ClassName.get(String.class))),
ProxyConstance.PROXY_COUNTER_MAP)
.addModifiers(Modifier.PRIVATE)
.initializer("new $T()", HashMap.class)
.build();
builder.addField(mappingField);
//增加构造函数
CodeBlock.Builder cb = CodeBlock.builder();
cb.add("Set<String> set = null;\n");
for (String key : keys) {
addTypeData(key, mPbUtil.getListenerClass().get(key), cb);
}
MethodSpec structure =
MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC).addCode(cb.build()).build();
builder.addMethod(structure);
builder.addMethod(
createMethod(ProxyConstance.COUNT_METHOD_DOWNLOAD, ProxyConstance.COUNT_DOWNLOAD));
builder.addMethod(
createMethod(ProxyConstance.COUNT_METHOD_UPLOAD, ProxyConstance.COUNT_UPLOAD));
builder.addMethod(createMethod(ProxyConstance.COUNT_METHOD_DOWNLOAD_GROUP,
ProxyConstance.COUNT_DOWNLOAD_GROUP));
builder.addMethod(createMethod(ProxyConstance.COUNT_METHOD_DOWNLOAD_GROUP_SUB,
ProxyConstance.COUNT_DOWNLOAD_GROUP_SUB));
JavaFile jf = JavaFile.builder(ProxyConstance.PROXY_COUNTER_PACKAGE, builder.build()).build();
createFile(jf);
}
/**
* 创建不同任务类型的代理类集合
*
* @param key {@link ParamObtainUtil#addListenerMapping(String, String)}
*/
private MethodSpec createMethod(String methodName, String key) {
MethodSpec.Builder builder = MethodSpec.methodBuilder(methodName);
ParameterizedTypeName returnName =
ParameterizedTypeName.get(ClassName.get(Set.class), ClassName.get(String.class));
builder.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.returns(returnName)
.addCode("return " + ProxyConstance.PROXY_COUNTER_MAP + ".get(\"" + key + "\");\n");
return builder.build();
}
/**
* 添加每一种注解对应类
*
* @param type {@link ParamObtainUtil#addListenerMapping(String, String)}
*/
private void addTypeData(String type, Set<String> clsNames, CodeBlock.Builder cb) {
if (clsNames == null || clsNames.isEmpty()) return;
StringBuilder sb = new StringBuilder();
sb.append("set = new $T();\n");
for (String clsName : clsNames) {
sb.append("set.add(\"").append(clsName).append("\");\n");
}
sb.append("typeMapping.put(\"").append(type).append("\", ").append("set);\n");
cb.add(sb.toString(), ClassName.get(HashSet.class));
}
private void createFile(JavaFile jf) throws IOException {
//jf.writeTo(System.out);
if (ProxyConstance.DEBUG) {
// 如果需要在控制台打印生成的文件,则去掉下面的注释
jf.writeTo(System.out);
} else {
jf.writeTo(mFiler);
}
}
}

@ -18,31 +18,9 @@ package com.arialyy.compiler;
import com.arialyy.annotations.Download;
import com.arialyy.annotations.DownloadGroup;
import com.arialyy.annotations.Upload;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.Filer;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
/**
@ -50,16 +28,13 @@ import javax.lang.model.util.Elements;
* 元素处理
*/
class ElementHandler {
private static final boolean DEBUG = false;
private Filer mFiler;
private Elements mElementUtil;
private Map<String, ProxyMethodParam> mMethods = new HashMap<>();
private Map<String, Set<String>> mListenerClass = new HashMap<>();
private ParamObtainUtil mPbUtil;
ElementHandler(Filer filer, Elements elements) {
mFiler = filer;
mElementUtil = elements;
mPbUtil = new ParamObtainUtil(elements);
}
/**
@ -69,43 +44,68 @@ class ElementHandler {
* PackageElement 一般代表Package
*/
void handleDownload(RoundEnvironment roundEnv) {
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onNoSupportBreakPoint.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onNoSupportBreakPoint.class,
ProxyConstance.TASK_NO_SUPPORT_BREAKPOINT);
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onPre.class, ProxyConstance.PRE);
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskCancel.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onPre.class, ProxyConstance.PRE);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskCancel.class,
ProxyConstance.TASK_CANCEL);
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskComplete.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskComplete.class,
ProxyConstance.TASK_COMPLETE);
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskFail.class, ProxyConstance.TASK_FAIL);
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskPre.class, ProxyConstance.TASK_PRE);
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskResume.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskFail.class,
ProxyConstance.TASK_FAIL);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskPre.class,
ProxyConstance.TASK_PRE);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskResume.class,
ProxyConstance.TASK_RESUME);
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskRunning.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskRunning.class,
ProxyConstance.TASK_RUNNING);
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskStart.class, ProxyConstance.TASK_START);
saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskStop.class, ProxyConstance.TASK_STOP);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskStart.class,
ProxyConstance.TASK_START);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD, roundEnv, Download.onTaskStop.class,
ProxyConstance.TASK_STOP);
}
/**
* 处理搜索到的下载任务组注解
*/
void handleDownloadGroup(RoundEnvironment roundEnv) {
saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onPre.class, ProxyConstance.PRE);
saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskCancel.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onPre.class,
ProxyConstance.PRE);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskCancel.class,
ProxyConstance.TASK_CANCEL);
saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskComplete.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskComplete.class,
ProxyConstance.TASK_COMPLETE);
saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskFail.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskFail.class,
ProxyConstance.TASK_FAIL);
saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskPre.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskPre.class,
ProxyConstance.TASK_PRE);
saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskResume.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskResume.class,
ProxyConstance.TASK_RESUME);
saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskRunning.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskRunning.class,
ProxyConstance.TASK_RUNNING);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskStart.class,
ProxyConstance.TASK_START);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskStop.class,
ProxyConstance.TASK_STOP);
}
/**
* 处理搜索到的下载任务组子任务注解
*/
void handleDownloadGroupSub(RoundEnvironment roundEnv) {
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP_SUB, roundEnv, DownloadGroup.onSubTaskPre.class,
ProxyConstance.TASK_PRE);
//mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP_SUB, roundEnv, DownloadGroup.onSubTaskCancel.class,
// ProxyConstance.TASK_CANCEL);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP_SUB, roundEnv, DownloadGroup.onSubTaskComplete.class,
ProxyConstance.TASK_COMPLETE);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP_SUB, roundEnv, DownloadGroup.onSubTaskFail.class,
ProxyConstance.TASK_FAIL);
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP_SUB, roundEnv, DownloadGroup.onSubTaskRunning.class,
ProxyConstance.TASK_RUNNING);
saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskStart.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP_SUB, roundEnv, DownloadGroup.onSubTaskStart.class,
ProxyConstance.TASK_START);
saveMethod(TaskEnum.DOWNLOAD_GROUP, roundEnv, DownloadGroup.onTaskStop.class,
mPbUtil.saveMethod(TaskEnum.DOWNLOAD_GROUP_SUB, roundEnv, DownloadGroup.onSubTaskStop.class,
ProxyConstance.TASK_STOP);
}
@ -113,488 +113,39 @@ class ElementHandler {
* 处理搜索到的上传注解F
*/
void handleUpload(RoundEnvironment roundEnv) {
saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onNoSupportBreakPoint.class,
mPbUtil.saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onNoSupportBreakPoint.class,
ProxyConstance.TASK_NO_SUPPORT_BREAKPOINT);
saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onPre.class, ProxyConstance.PRE);
saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskCancel.class, ProxyConstance.TASK_CANCEL);
saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskComplete.class,
mPbUtil.saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onPre.class, ProxyConstance.PRE);
mPbUtil.saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskCancel.class,
ProxyConstance.TASK_CANCEL);
mPbUtil.saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskComplete.class,
ProxyConstance.TASK_COMPLETE);
saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskFail.class, ProxyConstance.TASK_FAIL);
saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskResume.class, ProxyConstance.TASK_RESUME);
saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskRunning.class, ProxyConstance.TASK_RUNNING);
saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskStart.class, ProxyConstance.TASK_START);
saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskStop.class, ProxyConstance.TASK_STOP);
mPbUtil.saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskFail.class,
ProxyConstance.TASK_FAIL);
mPbUtil.saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskResume.class,
ProxyConstance.TASK_RESUME);
mPbUtil.saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskRunning.class,
ProxyConstance.TASK_RUNNING);
mPbUtil.saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskStart.class,
ProxyConstance.TASK_START);
mPbUtil.saveMethod(TaskEnum.UPLOAD, roundEnv, Upload.onTaskStop.class,
ProxyConstance.TASK_STOP);
}
/**
* 在build文件夹中生成如下代码的文件
* <pre>
* <code>
* package com.arialyy.simple.download;
*
* import com.arialyy.aria.core.download.DownloadTask;
* import com.arialyy.aria.core.scheduler.AbsSchedulerListener;
*
* public final class SingleTaskActivity$$DownloadListenerProxy extends
* AbsSchedulerListener<DownloadTask> {
* private SingleTaskActivity obj;
*
* public void onPre(final DownloadTask task) {
* obj.onPre((DownloadTask)task);
* }
*
* public void onTaskStart(final DownloadTask task) {
* obj.onStart((DownloadTask)task);
* }
*
* public void setListener(final Object obj) {
* this.obj = (SingleTaskActivity)obj;
* }
* }
* </code>
* </pre>
* 在build文件夹中生成代理文件
*/
void createProxyFile() {
try {
createProxyListenerFile();
createProxyClassFile();
new EventProxyFiler(mFiler, mPbUtil).createEventProxyFile();
new CountFiler(mFiler, mPbUtil).createCountFile();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 创建事件代理文件
*/
private void createProxyListenerFile() throws IOException {
Set<String> keys = mMethods.keySet();
for (String key : keys) {
ProxyMethodParam entity = mMethods.get(key);
for (TaskEnum taskEnum : entity.taskEnums) {
JavaFile jf =
JavaFile.builder(entity.packageName, createProxyClass(entity, taskEnum)).build();
createFile(jf);
}
}
}
private void createFile(JavaFile jf) throws IOException {
if (DEBUG) {
// 如果需要在控制台打印生成的文件,则去掉下面的注释
jf.writeTo(System.out);
} else {
jf.writeTo(mFiler);
}
}
/**
* 每一种注解对应的类集合
*/
private void createProxyClassFile() throws IOException {
Set<String> keys = mListenerClass.keySet();
TypeSpec.Builder builder = TypeSpec.classBuilder(ProxyConstance.PROXY_COUNTER_NAME)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
FieldSpec mappingField = FieldSpec.builder(
ParameterizedTypeName.get(ClassName.get(Map.class), ClassName.get(String.class),
ParameterizedTypeName.get(ClassName.get(Set.class), ClassName.get(String.class))),
ProxyConstance.PROXY_COUNTER_MAP)
.addModifiers(Modifier.PRIVATE)
.initializer("new $T()", HashMap.class)
.build();
builder.addField(mappingField);
//增加构造函数
CodeBlock.Builder cb = CodeBlock.builder();
cb.add("Set<String> set = null;\n");
for (String key : keys) {
addTypeData(key, mListenerClass.get(key), cb);
}
MethodSpec structure =
MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC).addCode(cb.build()).build();
builder.addMethod(structure);
builder.addMethod(
creatMethod(ProxyConstance.COUNT_METHOD_DOWNLOAD, ProxyConstance.COUNT_DOWNLOAD));
builder.addMethod(creatMethod(ProxyConstance.COUNT_METHOD_UPLOAD, ProxyConstance.COUNT_UPLOAD));
builder.addMethod(creatMethod(ProxyConstance.COUNT_METHOD_DOWNLOAD_GROUP,
ProxyConstance.COUNT_DOWNLOAD_GROUP));
JavaFile jf = JavaFile.builder(ProxyConstance.PROXY_COUNTER_PACKAGE, builder.build()).build();
createFile(jf);
}
/**
* 创建不同任务类型的代理类集合
*
* @param key {@link #addListenerMapping(String, String)}
*/
private MethodSpec creatMethod(String methodName, String key) {
MethodSpec.Builder builder = MethodSpec.methodBuilder(methodName);
ParameterizedTypeName returnName =
ParameterizedTypeName.get(ClassName.get(Set.class), ClassName.get(String.class));
builder.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.returns(returnName)
.addCode("return " + ProxyConstance.PROXY_COUNTER_MAP + ".get(\"" + key + "\");\n");
return builder.build();
}
/**
* 添加每一种注解对应类
*
* @param type {@link #addListenerMapping(String, String)}
*/
private void addTypeData(String type, Set<String> clsNames, CodeBlock.Builder cb) {
if (clsNames == null || clsNames.isEmpty()) return;
StringBuilder sb = new StringBuilder();
sb.append("set = new $T();\n");
for (String clsName : clsNames) {
sb.append("set.add(\"").append(clsName).append("\");\n");
}
sb.append("typeMapping.put(\"").append(type).append("\", ").append("set);\n");
cb.add(sb.toString(), ClassName.get(HashSet.class));
}
/**
* 创建代理方法
*
* @param taskEnum 任务类型枚举{@link TaskEnum}
* @param annotation {@link Download}{@link Upload}
* @param methodName 被代理类注解的方法名
*/
private MethodSpec createProxyMethod(TaskEnum taskEnum, Class<? extends Annotation> annotation,
String methodName) {
ClassName task = ClassName.get(taskEnum.getPkg(), taskEnum.getClassName());
ParameterSpec parameterSpec =
ParameterSpec.builder(task, "task").addModifiers(Modifier.FINAL).build();
StringBuilder sb = new StringBuilder();
sb.append("Set<String> keys = keyMapping.get(\"").append(methodName).append("\");\n");
sb.append("if (keys != null) {\n\tif (keys.contains(task.getKey())) {\n")
.append("\t\tobj.")
.append(methodName)
.append("((")
.append(taskEnum.getClassName())
.append(")task);\n")
.append("\t}\n} else {\n")
.append("\tobj.")
.append(methodName)
.append("((")
.append(taskEnum.getClassName())
.append(")task);\n}\n");
return MethodSpec.methodBuilder(annotation.getSimpleName())
.addModifiers(Modifier.PUBLIC)
.returns(void.class)
.addParameter(parameterSpec)
.addAnnotation(Override.class)
.addCode(sb.toString())
.build();
}
/**
* 创建代理类
*/
private TypeSpec createProxyClass(ProxyMethodParam entity, TaskEnum taskEnum) {
TypeSpec.Builder builder = TypeSpec.classBuilder(entity.className + taskEnum.getProxySuffix())
.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
//添加被代理的类的字段
ClassName obj = ClassName.get(entity.packageName, entity.className);
FieldSpec observerField = FieldSpec.builder(obj, "obj").addModifiers(Modifier.PRIVATE).build();
builder.addField(observerField);
//添加url映射表
FieldSpec mappingField = FieldSpec.builder(
ParameterizedTypeName.get(ClassName.get(Map.class), ClassName.get(String.class),
ParameterizedTypeName.get(ClassName.get(Set.class), ClassName.get(String.class))),
"keyMapping").addModifiers(Modifier.PRIVATE).initializer("new $T()", HashMap.class).build();
builder.addField(mappingField);
//添加注解方法
Map<Class<? extends Annotation>, String> temp = entity.methods.get(taskEnum);
if (temp != null) {
for (Class<? extends Annotation> annotation : temp.keySet()) {
MethodSpec method = createProxyMethod(taskEnum, annotation, temp.get(annotation));
builder.addMethod(method);
}
}
//增加构造函数
CodeBlock.Builder cb = CodeBlock.builder();
cb.add("Set<String> set = null;\n");
for (String methodName : entity.keyMappings.keySet()) {
Set<String> keys = entity.keyMappings.get(methodName);
if (keys == null || keys.size() == 0) continue;
StringBuilder sb = new StringBuilder();
sb.append("set = new $T();\n");
for (String key : keys) {
if (key.isEmpty()) continue;
sb.append("set.add(\"").append(key).append("\");\n");
}
sb.append("keyMapping.put(\"").append(methodName).append("\", ").append("set);\n");
cb.add(sb.toString(), ClassName.get(HashSet.class));
}
MethodSpec structure =
MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC).addCode(cb.build()).build();
builder.addMethod(structure);
//添加设置代理的类
ParameterSpec parameterSpec =
ParameterSpec.builder(Object.class, "obj").addModifiers(Modifier.FINAL).build();
MethodSpec listener = MethodSpec.methodBuilder(ProxyConstance.SET_LISTENER)
.addModifiers(Modifier.PUBLIC)
.returns(void.class)
.addParameter(parameterSpec)
.addAnnotation(Override.class)
.addCode("this.obj = (" + entity.className + ")obj;\n")
.build();
builder.addJavadoc("该文件为Aria自动生成的代理文件,请不要修改该文件的任何代码!\n");
//创建父类参数
ClassName superClass = ClassName.get("com.arialyy.aria.core.scheduler", "AbsSchedulerListener");
//创建泛型
ClassName typeVariableName = ClassName.get(taskEnum.getPkg(), taskEnum.getClassName());
builder.superclass(ParameterizedTypeName.get(superClass, typeVariableName));
builder.addMethod(listener);
return builder.build();
}
void clean() {
mMethods.clear();
}
/**
* 查找并保存扫描到的方法
*/
private void saveMethod(TaskEnum taskEnum, RoundEnvironment roundEnv,
Class<? extends Annotation> annotationClazz, int annotationType) {
for (Element element : roundEnv.getElementsAnnotatedWith(annotationClazz)) {
ElementKind kind = element.getKind();
if (kind == ElementKind.METHOD) {
ExecutableElement method = (ExecutableElement) element;
TypeElement classElement = (TypeElement) method.getEnclosingElement();
PackageElement packageElement = mElementUtil.getPackageOf(classElement);
checkDownloadMethod(taskEnum, method);
String methodName = method.getSimpleName().toString();
String className = method.getEnclosingElement().toString(); //全类名
ProxyMethodParam proxyEntity = mMethods.get(className);
if (proxyEntity == null) {
proxyEntity = new ProxyMethodParam();
proxyEntity.taskEnums = new HashSet<>();
proxyEntity.packageName = packageElement.getQualifiedName().toString();
proxyEntity.className = classElement.getSimpleName().toString();
mMethods.put(className, proxyEntity);
}
proxyEntity.taskEnums.add(taskEnum);
if (proxyEntity.methods.get(taskEnum) == null) {
proxyEntity.methods.put(taskEnum, new HashMap<Class<? extends Annotation>, String>());
}
proxyEntity.methods.get(taskEnum).put(annotationClazz, methodName);
proxyEntity.keyMappings.put(methodName, getValues(taskEnum, method, annotationType));
}
}
}
/**
* 获取注解的内容
*/
private Set<String> getValues(TaskEnum taskEnum, ExecutableElement method, int annotationType) {
String clsName = method.getEnclosingElement().toString();
String[] keys = null;
switch (taskEnum) {
case DOWNLOAD:
keys = getDownloadValues(method, annotationType);
addListenerMapping(clsName, ProxyConstance.COUNT_DOWNLOAD);
break;
case UPLOAD:
keys = getUploadValues(method, annotationType);
addListenerMapping(clsName, ProxyConstance.COUNT_UPLOAD);
break;
case DOWNLOAD_GROUP:
keys = getDownloadGroupValues(method, annotationType);
addListenerMapping(clsName, ProxyConstance.COUNT_DOWNLOAD_GROUP);
break;
}
return keys == null ? null : convertSet(keys);
}
/**
* 添加方法映射
*
* @param clsName 注解事件的类
* @param key {@link ProxyConstance#COUNT_DOWNLOAD}{@link ProxyConstance#COUNT_UPLOAD}{@link
* ProxyConstance#COUNT_DOWNLOAD_GROUP}
*/
private void addListenerMapping(String clsName, String key) {
Set<String> cls = mListenerClass.get(key);
if (cls == null) {
cls = new HashSet<>();
mListenerClass.put(key, cls);
}
cls.add(clsName);
}
/**
* 获取下载任务组的注解数据
*/
private String[] getDownloadGroupValues(ExecutableElement method, int annotationType) {
String[] values = null;
switch (annotationType) {
case ProxyConstance.PRE:
values = method.getAnnotation(DownloadGroup.onPre.class).value();
break;
case ProxyConstance.TASK_PRE:
values = method.getAnnotation(DownloadGroup.onTaskPre.class).value();
break;
case ProxyConstance.TASK_RESUME:
values = method.getAnnotation(DownloadGroup.onTaskResume.class).value();
break;
case ProxyConstance.TASK_START:
values = method.getAnnotation(DownloadGroup.onTaskStart.class).value();
break;
case ProxyConstance.TASK_RUNNING:
values = method.getAnnotation(DownloadGroup.onTaskRunning.class).value();
break;
case ProxyConstance.TASK_STOP:
values = method.getAnnotation(DownloadGroup.onTaskStop.class).value();
break;
case ProxyConstance.TASK_COMPLETE:
values = method.getAnnotation(DownloadGroup.onTaskComplete.class).value();
break;
case ProxyConstance.TASK_CANCEL:
values = method.getAnnotation(DownloadGroup.onTaskCancel.class).value();
break;
case ProxyConstance.TASK_FAIL:
values = method.getAnnotation(DownloadGroup.onTaskFail.class).value();
break;
}
return values;
}
/**
* 获取上传的注解数据
*/
private String[] getUploadValues(ExecutableElement method, int annotationType) {
String[] values = null;
switch (annotationType) {
case ProxyConstance.PRE:
values = method.getAnnotation(Upload.onPre.class).value();
break;
case ProxyConstance.TASK_PRE:
//values = method.getAnnotation(Upload.onTaskPre.class).value();
break;
case ProxyConstance.TASK_RESUME:
values = method.getAnnotation(Upload.onTaskResume.class).value();
break;
case ProxyConstance.TASK_START:
values = method.getAnnotation(Upload.onTaskStart.class).value();
break;
case ProxyConstance.TASK_RUNNING:
values = method.getAnnotation(Upload.onTaskRunning.class).value();
break;
case ProxyConstance.TASK_STOP:
values = method.getAnnotation(Upload.onTaskStop.class).value();
break;
case ProxyConstance.TASK_COMPLETE:
values = method.getAnnotation(Upload.onTaskComplete.class).value();
break;
case ProxyConstance.TASK_CANCEL:
values = method.getAnnotation(Upload.onTaskCancel.class).value();
break;
case ProxyConstance.TASK_FAIL:
values = method.getAnnotation(Upload.onTaskFail.class).value();
break;
case ProxyConstance.TASK_NO_SUPPORT_BREAKPOINT:
//values = method.getAnnotation(Upload.onNoSupportBreakPoint.class).value();
break;
}
return values;
}
/**
* 获取下载的注解数据
*/
private String[] getDownloadValues(ExecutableElement method, int annotationType) {
String[] values = null;
switch (annotationType) {
case ProxyConstance.PRE:
values = method.getAnnotation(Download.onPre.class).value();
break;
case ProxyConstance.TASK_PRE:
values = method.getAnnotation(Download.onTaskPre.class).value();
break;
case ProxyConstance.TASK_RESUME:
values = method.getAnnotation(Download.onTaskResume.class).value();
break;
case ProxyConstance.TASK_START:
values = method.getAnnotation(Download.onTaskStart.class).value();
break;
case ProxyConstance.TASK_RUNNING:
values = method.getAnnotation(Download.onTaskRunning.class).value();
break;
case ProxyConstance.TASK_STOP:
values = method.getAnnotation(Download.onTaskStop.class).value();
break;
case ProxyConstance.TASK_COMPLETE:
values = method.getAnnotation(Download.onTaskComplete.class).value();
break;
case ProxyConstance.TASK_CANCEL:
values = method.getAnnotation(Download.onTaskCancel.class).value();
break;
case ProxyConstance.TASK_FAIL:
values = method.getAnnotation(Download.onTaskFail.class).value();
break;
case ProxyConstance.TASK_NO_SUPPORT_BREAKPOINT:
values = method.getAnnotation(Download.onNoSupportBreakPoint.class).value();
break;
}
return values;
}
/**
* 检查和下载相关的方法如果被注解的方法为private或参数不合法则抛异常
*/
private void checkDownloadMethod(TaskEnum taskEnum, ExecutableElement method) {
String methodName = method.getSimpleName().toString();
String className = method.getEnclosingElement().toString();
Set<Modifier> modifiers = method.getModifiers();
if (modifiers.contains(Modifier.PRIVATE)) {
throw new IllegalAccessError(className + "." + methodName + "不能为private方法");
}
List<VariableElement> params = (List<VariableElement>) method.getParameters();
if (params.size() > 1) {
throw new IllegalArgumentException(
className + "." + methodName + "参数错误, 参数只有一个,且参数必须是" + getCheckParams(taskEnum));
}
if (!params.get(0).asType().toString().equals(getCheckParams(taskEnum))) {
throw new IllegalArgumentException(className
+ "."
+ methodName
+ "参数【"
+ params.get(0).getSimpleName()
+ "】类型错误,参数必须是"
+ getCheckParams(taskEnum));
}
}
/**
* 字符串数组转set
*
* @param keys 注解中查到的key
*/
private Set<String> convertSet(final String[] keys) {
if (keys == null || keys.length == 0) {
return null;
}
if (keys[0].isEmpty()) return null;
Set<String> set = new HashSet<>();
Collections.addAll(set, keys);
return set;
}
private String getCheckParams(TaskEnum taskEnum) {
return taskEnum.pkg + "." + taskEnum.getClassName();
mPbUtil.getMethodParams().clear();
mPbUtil.getListenerClass().clear();
}
}

@ -0,0 +1,231 @@
/*
* 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.compiler;
import com.arialyy.annotations.Download;
import com.arialyy.annotations.Upload;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.Filer;
import javax.lang.model.element.Modifier;
/**
* Created by lyy on 2017/9/6.
* 任务事件代理文件
*
* <pre>
* <code>
* package com.arialyy.simple.download;
*
* import com.arialyy.aria.core.download.DownloadTask;
* import com.arialyy.aria.core.scheduler.AbsSchedulerListener;
*
* public final class SingleTaskActivity$$DownloadListenerProxy extends
* AbsSchedulerListener<DownloadTask> {
* private SingleTaskActivity obj;
*
* public void onPre(final DownloadTask task) {
* obj.onPre((DownloadTask)task);
* }
*
* public void onTaskStart(final DownloadTask task) {
* obj.onStart((DownloadTask)task);
* }
*
* public void setListener(final Object obj) {
* this.obj = (SingleTaskActivity)obj;
* }
* }
* </code>
* </pre>
*/
final class EventProxyFiler {
private Filer mFiler;
private ParamObtainUtil mPbUtil;
EventProxyFiler(Filer filer, ParamObtainUtil pbUtil) {
mFiler = filer;
mPbUtil = pbUtil;
}
/**
* 创建任务事件代理文件
*/
void createEventProxyFile() throws IOException {
Set<String> keys = mPbUtil.getMethodParams().keySet();
for (String key : keys) {
ProxyClassParam entity = mPbUtil.getMethodParams().get(key);
JavaFile jf = JavaFile.builder(entity.packageName, createProxyClass(entity)).build();
createFile(jf);
}
}
/**
* 创建代理方法
*
* @param taskEnum 任务类型枚举{@link TaskEnum}
* @param annotation {@link Download}{@link Upload}
* @param methodName 被代理类注解的方法名
*/
private MethodSpec createProxyMethod(TaskEnum taskEnum, Class<? extends Annotation> annotation,
String methodName) {
ClassName task = ClassName.get(taskEnum.getPkg(), taskEnum.getClassName());
ParameterSpec taskParam =
ParameterSpec.builder(task, "task").addModifiers(Modifier.FINAL).build();
String callCode;
if (taskEnum == TaskEnum.DOWNLOAD_GROUP_SUB) {
callCode = "task, subEntity";
} else {
callCode = "task";
}
StringBuilder sb = new StringBuilder();
sb.append("Set<String> keys = keyMapping.get(\"").append(methodName).append("\");\n");
sb.append("if (keys != null) {\n\tif (keys.contains(task.getKey())) {\n")
.append("\t\tobj.")
.append(methodName)
.append("((")
.append(taskEnum.getClassName())
.append(")")
.append(callCode)
.append(");\n\t}\n} else {\n")
.append("\tobj.")
.append(methodName)
.append("((")
.append(taskEnum.getClassName())
.append(")")
.append(callCode)
.append(");\n}\n");
MethodSpec.Builder builder = MethodSpec.methodBuilder(annotation.getSimpleName())
.addModifiers(Modifier.PUBLIC)
.returns(void.class)
.addParameter(taskParam)
.addAnnotation(Override.class)
.addCode(sb.toString());
//任务组接口
if (taskEnum == TaskEnum.DOWNLOAD_GROUP_SUB) {
ClassName subTask = ClassName.get(TaskEnum.DOWNLOAD_ENTITY.pkg, TaskEnum.DOWNLOAD_ENTITY.className);
ParameterSpec subTaskParam =
ParameterSpec.builder(subTask, "subEntity").addModifiers(Modifier.FINAL).build();
builder.addParameter(subTaskParam);
}
return builder.build();
}
/**
* 创建代理类
*/
private TypeSpec createProxyClass(ProxyClassParam entity) {
TypeSpec.Builder builder =
TypeSpec.classBuilder(entity.proxyClassName).addModifiers(Modifier.PUBLIC, Modifier.FINAL);
//添加被代理的类的字段
ClassName obj = ClassName.get(entity.packageName, entity.className);
FieldSpec observerField = FieldSpec.builder(obj, "obj").addModifiers(Modifier.PRIVATE).build();
builder.addField(observerField);
//添加url映射表
FieldSpec mappingField = FieldSpec.builder(
ParameterizedTypeName.get(ClassName.get(Map.class), ClassName.get(String.class),
ParameterizedTypeName.get(ClassName.get(Set.class), ClassName.get(String.class))),
"keyMapping").addModifiers(Modifier.PRIVATE).initializer("new $T()", HashMap.class).build();
builder.addField(mappingField);
//添加注解方法
for (TaskEnum te : entity.methods.keySet()) {
Map<Class<? extends Annotation>, String> temp = entity.methods.get(te);
if (temp != null) {
for (Class<? extends Annotation> annotation : temp.keySet()) {
MethodSpec method = createProxyMethod(te, annotation, temp.get(annotation));
builder.addMethod(method);
}
}
}
//增加构造函数
CodeBlock.Builder cb = CodeBlock.builder();
cb.add("Set<String> set = null;\n");
for (String methodName : entity.keyMappings.keySet()) {
//PrintLog.getInstance().info("methodName ====> " + methodName);
Set<String> keys = entity.keyMappings.get(methodName);
if (keys == null || keys.size() == 0) continue;
StringBuilder sb = new StringBuilder();
sb.append("set = new $T();\n");
for (String key : keys) {
if (key.isEmpty()) continue;
sb.append("set.add(\"").append(key).append("\");\n");
}
sb.append("keyMapping.put(\"").append(methodName).append("\", ").append("set);\n");
cb.add(sb.toString(), ClassName.get(HashSet.class));
}
MethodSpec structure =
MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC).addCode(cb.build()).build();
builder.addMethod(structure);
//添加设置代理的类
ParameterSpec parameterSpec =
ParameterSpec.builder(Object.class, "obj").addModifiers(Modifier.FINAL).build();
MethodSpec listener = MethodSpec.methodBuilder(ProxyConstance.SET_LISTENER)
.addModifiers(Modifier.PUBLIC)
.returns(void.class)
.addParameter(parameterSpec)
.addAnnotation(Override.class)
.addCode("this.obj = (" + entity.className + ")obj;\n")
.build();
builder.addJavadoc("该文件为Aria自动生成的代理文件,请不要修改该文件的任何代码!\n");
//创建父类参数
ClassName superClass = ClassName.get("com.arialyy.aria.core.scheduler", "AbsSchedulerListener");
//主任务泛型参数
ClassName taskTypeVariable =
ClassName.get(entity.mainTaskEnum.pkg, entity.mainTaskEnum.className);
//子任务泛型参数
ClassName subTaskTypeVariable =
ClassName.get(entity.subTaskEnum.pkg, entity.subTaskEnum.className);
builder.superclass(
ParameterizedTypeName.get(superClass, taskTypeVariable, subTaskTypeVariable));
builder.addMethod(listener);
return builder.build();
}
private void createFile(JavaFile jf) throws IOException {
if (ProxyConstance.DEBUG) {
// 如果需要在控制台打印生成的文件,则去掉下面的注释
jf.writeTo(System.out);
} else {
jf.writeTo(mFiler);
}
}
}

@ -0,0 +1,221 @@
/*
* 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.compiler;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
/**
* Created by Aria.Lao on 2017/9/6.
* 构建代理文件的参数获取工具
*/
class ParamObtainUtil {
private Map<String, ProxyClassParam> mMethodParams = new HashMap<>();
private Map<String, Set<String>> mListenerClass = new HashMap<>();
private Elements mElementUtil;
ParamObtainUtil(Elements elements) {
mElementUtil = elements;
}
/**
* 获取需要创建的代理类参数
*/
Map<String, Set<String>> getListenerClass() {
return mListenerClass;
}
/**
* 获取搜索到的代理方法参数
*/
Map<String, ProxyClassParam> getMethodParams() {
return mMethodParams;
}
/**
* 查找并保存扫描到的方法
*/
void saveMethod(TaskEnum taskEnum, RoundEnvironment roundEnv,
Class<? extends Annotation> annotationClazz, int annotationType) {
for (Element element : roundEnv.getElementsAnnotatedWith(annotationClazz)) {
ElementKind kind = element.getKind();
if (kind == ElementKind.METHOD) {
ExecutableElement method = (ExecutableElement) element;
TypeElement classElement = (TypeElement) method.getEnclosingElement();
PackageElement packageElement = mElementUtil.getPackageOf(classElement);
checkDownloadMethod(taskEnum, method);
String methodName = method.getSimpleName().toString();
String className = method.getEnclosingElement().toString(); //全类名\
String key = className + taskEnum.proxySuffix;
ProxyClassParam proxyEntity = mMethodParams.get(key);
if (proxyEntity == null) {
proxyEntity = new ProxyClassParam();
proxyEntity.taskEnums = new HashSet<>();
proxyEntity.packageName = packageElement.getQualifiedName().toString();
proxyEntity.className = classElement.getSimpleName().toString();
proxyEntity.proxyClassName = proxyEntity.className + taskEnum.proxySuffix;
proxyEntity.mainTaskEnum = taskEnum;
if (taskEnum == TaskEnum.DOWNLOAD_GROUP_SUB || taskEnum == TaskEnum.DOWNLOAD_GROUP) {
proxyEntity.subTaskEnum = TaskEnum.DOWNLOAD_ENTITY;
}
mMethodParams.put(key, proxyEntity);
}
proxyEntity.taskEnums.add(taskEnum);
if (proxyEntity.methods.get(taskEnum) == null) {
proxyEntity.methods.put(taskEnum, new HashMap<Class<? extends Annotation>, String>());
}
proxyEntity.methods.get(taskEnum).put(annotationClazz, methodName);
proxyEntity.keyMappings.put(methodName, getValues(taskEnum, method, annotationType));
}
}
}
/**
* 获取注解的内容
*/
private Set<String> getValues(TaskEnum taskEnum, ExecutableElement method, int annotationType) {
String clsName = method.getEnclosingElement().toString();
String[] keys = null;
switch (taskEnum) {
case DOWNLOAD:
keys = ValuesUtil.getDownloadValues(method, annotationType);
addListenerMapping(clsName, ProxyConstance.COUNT_DOWNLOAD);
break;
case UPLOAD:
keys = ValuesUtil.getUploadValues(method, annotationType);
addListenerMapping(clsName, ProxyConstance.COUNT_UPLOAD);
break;
case DOWNLOAD_GROUP:
keys = ValuesUtil.getDownloadGroupValues(method, annotationType);
addListenerMapping(clsName, ProxyConstance.COUNT_DOWNLOAD_GROUP);
break;
case DOWNLOAD_GROUP_SUB:
keys = ValuesUtil.getDownloadGroupSubValues(method, annotationType);
addListenerMapping(clsName, ProxyConstance.COUNT_DOWNLOAD_GROUP_SUB);
break;
}
return keys == null ? null : convertSet(keys);
}
/**
* 添加方法映射
*
* @param clsName 注解事件的类
* @param key {@link ProxyConstance#COUNT_DOWNLOAD}{@link ProxyConstance#COUNT_UPLOAD}{@link
* ProxyConstance#COUNT_DOWNLOAD_GROUP}{@link ProxyConstance#COUNT_DOWNLOAD_GROUP_SUB}
*/
void addListenerMapping(String clsName, String key) {
Set<String> cls = mListenerClass.get(key);
if (cls == null) {
cls = new HashSet<>();
mListenerClass.put(key, cls);
}
cls.add(clsName);
}
/**
* 检查和下载相关的方法如果被注解的方法为private或参数不合法则抛异常
*/
private void checkDownloadMethod(TaskEnum taskEnum, ExecutableElement method) {
String methodName = method.getSimpleName().toString();
String className = method.getEnclosingElement().toString();
Set<Modifier> modifiers = method.getModifiers();
if (modifiers.contains(Modifier.PRIVATE)) {
throw new IllegalAccessError(className + "." + methodName + "不能为private方法");
}
List<VariableElement> params = (List<VariableElement>) method.getParameters();
if (taskEnum == TaskEnum.DOWNLOAD_GROUP_SUB) {
if (params.size() != 2) {
throw new IllegalArgumentException(className
+ "."
+ methodName
+ "参数错误, 参数只有两个,且第一个参数必须是"
+ getCheckParams(taskEnum)
+ ",第二个参数必须是"
+ getCheckSubParams(taskEnum));
}
} else {
if (params.size() != 1) {
throw new IllegalArgumentException(
className + "." + methodName + "参数错误, 参数只能有一个,且参数必须是" + getCheckParams(taskEnum));
}
}
if (!params.get(0).asType().toString().equals(getCheckParams(taskEnum))) {
throw new IllegalArgumentException(className
+ "."
+ methodName
+ "参数【"
+ params.get(0).getSimpleName()
+ "】类型错误,参数必须是"
+ getCheckParams(taskEnum));
}
if (taskEnum == TaskEnum.DOWNLOAD_GROUP_SUB) {
if (!params.get(1).asType().toString().equals(getCheckSubParams(taskEnum))) {
throw new IllegalArgumentException(className
+ "."
+ methodName
+ "参数【"
+ params.get(0).getSimpleName()
+ "】类型错误,参数必须是"
+ getCheckSubParams(taskEnum));
}
}
}
/**
* 字符串数组转set
*
* @param keys 注解中查到的key
*/
private Set<String> convertSet(final String[] keys) {
if (keys == null || keys.length == 0) {
return null;
}
if (keys[0].isEmpty()) return null;
Set<String> set = new HashSet<>();
Collections.addAll(set, keys);
return set;
}
private String getCheckParams(TaskEnum taskEnum) {
return taskEnum.pkg + "." + taskEnum.className;
}
/**
* 检查任务组子任务第二个参数
*/
private String getCheckSubParams(TaskEnum taskEnum) {
if (taskEnum == TaskEnum.DOWNLOAD_GROUP_SUB) {
return TaskEnum.DOWNLOAD_ENTITY.pkg + "." + TaskEnum.DOWNLOAD_ENTITY.className;
}
return "";
}
}

@ -55,7 +55,7 @@ class PrintLog {
mMessager.printMessage(Diagnostic.Kind.ERROR, String.format(msg, args));
}
private void warning(String msg) {
public void warning(String msg) {
mMessager.printMessage(Diagnostic.Kind.WARNING, msg);
}

@ -22,11 +22,30 @@ import java.util.Set;
/**
* Created by Aria.Lao on 2017/6/7.
* 创建代理方法的参数
* 代理类参数
*/
class ProxyClassParam {
/**
* 代理文件名
*/
String proxyClassName;
/**
* 被代理的类所在的包
*/
class ProxyMethodParam {
String packageName;
/**
* 被代理的类
*/
String className;
/**
* 主任务泛型参数
*/
TaskEnum mainTaskEnum;
/**
* 子任务泛型参数
*/
TaskEnum subTaskEnum = TaskEnum.NORMAL_ENTITY;
Set<TaskEnum> taskEnums;
Map<String, Set<String>> keyMappings = new HashMap<>();
Map<TaskEnum, Map<Class<? extends Annotation>, String>> methods = new HashMap<>();

@ -20,6 +20,7 @@ package com.arialyy.compiler;
* 扫描器常量
*/
interface ProxyConstance {
boolean DEBUG = false;
/**
* 设置观察者的方法
*/
@ -41,10 +42,12 @@ interface ProxyConstance {
String COUNT_DOWNLOAD = "download";
String COUNT_DOWNLOAD_GROUP = "downloadGroup";
String COUNT_DOWNLOAD_GROUP_SUB = "downloadGroupSub";
String COUNT_UPLOAD = "upload";
String COUNT_METHOD_DOWNLOAD = "getDownloadCounter";
String COUNT_METHOD_DOWNLOAD_GROUP = "getDownloadGroupCounter";
String COUNT_METHOD_DOWNLOAD_GROUP_SUB = "getDownloadGroupSubCounter";
String COUNT_METHOD_UPLOAD = "getUploadCounter";
int PRE = 0X11;

@ -22,9 +22,12 @@ package com.arialyy.compiler;
enum TaskEnum {
DOWNLOAD("com.arialyy.aria.core.download", "DownloadTask",
"$$DownloadListenerProxy"), DOWNLOAD_GROUP("com.arialyy.aria.core.download",
"DownloadGroupTask", "$$DownloadGroupListenerProxy"), UPLOAD("com.arialyy.aria.core.upload",
"UploadTask", "$$UploadListenerProxy"), UPLOAD_GROUP("com.arialyy.aria.core.upload",
"UploadGroupTask", "$$UploadGroupListenerProxy");
"DownloadGroupTask", "$$DownloadGroupListenerProxy"), DOWNLOAD_GROUP_SUB(
"com.arialyy.aria.core.download", "DownloadGroupTask", "$$DownloadGroupListenerProxy"), UPLOAD(
"com.arialyy.aria.core.upload", "UploadTask", "$$UploadListenerProxy"), UPLOAD_GROUP(
"com.arialyy.aria.core.upload", "UploadGroupTask",
"$$UploadGroupListenerProxy"), NORMAL_ENTITY("com.arialyy.aria.core.inf", "AbsNormalEntity",
""), DOWNLOAD_ENTITY("com.arialyy.aria.core.download", "DownloadEntity", "");
String pkg, className, proxySuffix;

@ -0,0 +1,175 @@
/*
* 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.compiler;
import com.arialyy.annotations.Download;
import com.arialyy.annotations.DownloadGroup;
import com.arialyy.annotations.Upload;
import javax.lang.model.element.ExecutableElement;
/**
* Created by lyy on 2017/9/6.
* 获取注解value工具
*/
final class ValuesUtil {
/**
* 获取下载任务组子任务的的注解数据
*/
static String[] getDownloadGroupSubValues(ExecutableElement method, int annotationType) {
String[] values = null;
switch (annotationType) {
case ProxyConstance.TASK_PRE:
values = method.getAnnotation(DownloadGroup.onSubTaskPre.class).value();
break;
case ProxyConstance.TASK_START:
values = method.getAnnotation(DownloadGroup.onSubTaskStart.class).value();
break;
case ProxyConstance.TASK_RUNNING:
values = method.getAnnotation(DownloadGroup.onSubTaskRunning.class).value();
break;
case ProxyConstance.TASK_STOP:
values = method.getAnnotation(DownloadGroup.onSubTaskStop.class).value();
break;
case ProxyConstance.TASK_COMPLETE:
values = method.getAnnotation(DownloadGroup.onSubTaskComplete.class).value();
break;
case ProxyConstance.TASK_CANCEL:
//values = method.getAnnotation(DownloadGroup.onSubTaskCancel.class).value();
break;
case ProxyConstance.TASK_FAIL:
values = method.getAnnotation(DownloadGroup.onSubTaskFail.class).value();
break;
}
return values;
}
/**
* 获取下载任务组的注解数据
*/
static String[] getDownloadGroupValues(ExecutableElement method, int annotationType) {
String[] values = null;
switch (annotationType) {
case ProxyConstance.PRE:
values = method.getAnnotation(DownloadGroup.onPre.class).value();
break;
case ProxyConstance.TASK_PRE:
values = method.getAnnotation(DownloadGroup.onTaskPre.class).value();
break;
case ProxyConstance.TASK_RESUME:
values = method.getAnnotation(DownloadGroup.onTaskResume.class).value();
break;
case ProxyConstance.TASK_START:
values = method.getAnnotation(DownloadGroup.onTaskStart.class).value();
break;
case ProxyConstance.TASK_RUNNING:
values = method.getAnnotation(DownloadGroup.onTaskRunning.class).value();
break;
case ProxyConstance.TASK_STOP:
values = method.getAnnotation(DownloadGroup.onTaskStop.class).value();
break;
case ProxyConstance.TASK_COMPLETE:
values = method.getAnnotation(DownloadGroup.onTaskComplete.class).value();
break;
case ProxyConstance.TASK_CANCEL:
values = method.getAnnotation(DownloadGroup.onTaskCancel.class).value();
break;
case ProxyConstance.TASK_FAIL:
values = method.getAnnotation(DownloadGroup.onTaskFail.class).value();
break;
}
return values;
}
/**
* 获取上传的注解数据
*/
static String[] getUploadValues(ExecutableElement method, int annotationType) {
String[] values = null;
switch (annotationType) {
case ProxyConstance.PRE:
values = method.getAnnotation(Upload.onPre.class).value();
break;
case ProxyConstance.TASK_PRE:
//values = method.getAnnotation(Upload.onTaskPre.class).value();
break;
case ProxyConstance.TASK_RESUME:
values = method.getAnnotation(Upload.onTaskResume.class).value();
break;
case ProxyConstance.TASK_START:
values = method.getAnnotation(Upload.onTaskStart.class).value();
break;
case ProxyConstance.TASK_RUNNING:
values = method.getAnnotation(Upload.onTaskRunning.class).value();
break;
case ProxyConstance.TASK_STOP:
values = method.getAnnotation(Upload.onTaskStop.class).value();
break;
case ProxyConstance.TASK_COMPLETE:
values = method.getAnnotation(Upload.onTaskComplete.class).value();
break;
case ProxyConstance.TASK_CANCEL:
values = method.getAnnotation(Upload.onTaskCancel.class).value();
break;
case ProxyConstance.TASK_FAIL:
values = method.getAnnotation(Upload.onTaskFail.class).value();
break;
case ProxyConstance.TASK_NO_SUPPORT_BREAKPOINT:
//values = method.getAnnotation(Upload.onNoSupportBreakPoint.class).value();
break;
}
return values;
}
/**
* 获取下载的注解数据
*/
static String[] getDownloadValues(ExecutableElement method, int annotationType) {
String[] values = null;
switch (annotationType) {
case ProxyConstance.PRE:
values = method.getAnnotation(Download.onPre.class).value();
break;
case ProxyConstance.TASK_PRE:
values = method.getAnnotation(Download.onTaskPre.class).value();
break;
case ProxyConstance.TASK_RESUME:
values = method.getAnnotation(Download.onTaskResume.class).value();
break;
case ProxyConstance.TASK_START:
values = method.getAnnotation(Download.onTaskStart.class).value();
break;
case ProxyConstance.TASK_RUNNING:
values = method.getAnnotation(Download.onTaskRunning.class).value();
break;
case ProxyConstance.TASK_STOP:
values = method.getAnnotation(Download.onTaskStop.class).value();
break;
case ProxyConstance.TASK_COMPLETE:
values = method.getAnnotation(Download.onTaskComplete.class).value();
break;
case ProxyConstance.TASK_CANCEL:
values = method.getAnnotation(Download.onTaskCancel.class).value();
break;
case ProxyConstance.TASK_FAIL:
values = method.getAnnotation(Download.onTaskFail.class).value();
break;
case ProxyConstance.TASK_NO_SUPPORT_BREAKPOINT:
values = method.getAnnotation(Download.onNoSupportBreakPoint.class).value();
break;
}
return values;
}
}

@ -317,6 +317,7 @@ Aria.download(this).load(DOWNLOAD_URL).setExtendField(str)
-keep class com.arialyy.aria.**{*;}
-keep class **$$DownloadListenerProxy{ *; }
-keep class **$$UploadListenerProxy{ *; }
-keep class **$$DownloadGroupSubListenerProxy{*;}
-keepclasseswithmembernames class * {
@Download.* <methods>;
@Upload.* <methods>;

@ -1,4 +1,5 @@
## 开发日志
+ v_3.3.0 增加任务组子任务暂停和开始控制功能、修复5.0系统以上数据库多生成两个字段的bug、去掉addSchedulerListener事件
+ v_3.2.26 修复任务组有时注解不起作用的问题
+ v_3.2.25 修复删除任务组文件,记录无法删除的问题
+ v_3.2.17 修复一个版本兼容性问题,线程中使用Aria出错问题

@ -20,6 +20,7 @@ import android.app.NotificationManager;
import android.content.Context;
import android.os.Environment;
import android.support.v4.app.NotificationCompat;
import com.arialyy.annotations.Download;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.simple.R;
@ -50,14 +51,13 @@ public class SimpleNotification {
.setProgress(100, 0, false)
.setSmallIcon(R.mipmap.ic_launcher);
mManager.notify(mNotifiyId, mBuilder.build());
Aria.download(mContext).addSchedulerListener(new DownloadCallback(mBuilder, mManager));
Aria.download(mContext).register();
}
public void start() {
Aria.download(mContext)
.load(DOWNLOAD_URL)
.setDownloadPath(
Environment.getExternalStorageDirectory() + "/Download/消灭星星.apk")
.setDownloadPath(Environment.getExternalStorageDirectory() + "/Download/消灭星星.apk")
.start();
}
@ -65,29 +65,16 @@ public class SimpleNotification {
Aria.download(mContext).load(DOWNLOAD_URL).pause();
}
private static class DownloadCallback extends Aria.DownloadSchedulerListener {
NotificationCompat.Builder mBuilder;
NotificationManager mManager;
private DownloadCallback(NotificationCompat.Builder builder, NotificationManager manager) {
mBuilder = builder;
mManager = manager;
}
@Override public void onTaskStart(DownloadTask task) {
super.onTaskStart(task);
@Download.onTaskStart public void onTaskStart(DownloadTask task) {
}
@Override public void onTaskPre(DownloadTask task) {
super.onTaskPre(task);
@Download.onTaskPre public void onTaskPre(DownloadTask task) {
}
@Override public void onTaskStop(DownloadTask task) {
super.onTaskStop(task);
@Download.onTaskStop public void onTaskStop(DownloadTask task) {
}
@Override public void onTaskRunning(DownloadTask task) {
super.onTaskRunning(task);
@Download.onTaskRunning public void onTaskRunning(DownloadTask task) {
long len = task.getFileSize();
int p = (int) (task.getCurrentProgress() * 100 / len);
if (mBuilder != null) {
@ -96,16 +83,13 @@ public class SimpleNotification {
}
}
@Override public void onTaskComplete(DownloadTask task) {
super.onTaskComplete(task);
@Download.onTaskComplete public void onTaskComplete(DownloadTask task) {
if (mBuilder != null) {
mBuilder.setProgress(100, 100, false);
mManager.notify(mNotifiyId, mBuilder.build());
}
}
@Override public void onTaskCancel(DownloadTask task) {
super.onTaskCancel(task);
}
@Download.onTaskCancel public void onTaskCancel(DownloadTask task) {
}
}

@ -18,7 +18,6 @@ package com.arialyy.simple.download;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@ -27,10 +26,12 @@ import android.widget.RadioGroup;
import android.widget.Toast;
import butterknife.Bind;
import com.arialyy.annotations.Download;
import com.arialyy.annotations.DownloadGroup;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadTarget;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.frame.util.show.L;
@ -45,7 +46,8 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
private static final String DOWNLOAD_URL =
//"http://kotlinlang.org/docs/kotlin-docs.pdf";
//"https://atom-installer.github.com/v1.13.0/AtomSetup.exe?s=1484074138&ext=.exe";
"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
//"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
"http://sitcac.daxincf.cn/wp-content/uploads/swift_vido/01/element.mp4";
//"http://120.25.196.56:8000/filereq?id=15692406294&ipncid=105635&client=android&filename=20170819185541.avi";
//"http://down2.xiaoshuofuwuqi.com/d/file/filetxt/20170608/14/%BA%DA%CE%D7%CA%A6%E1%C8%C6%F0.txt";
//"http://tinghuaapp.oss-cn-shanghai.aliyuncs.com/20170612201739607815";

@ -0,0 +1,149 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.simple.download.group;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import butterknife.Bind;
import butterknife.OnClick;
import com.arialyy.annotations.DownloadGroup;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.frame.util.show.L;
import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseDialog;
import com.arialyy.simple.databinding.DialogSubTaskHandlerBinding;
import com.arialyy.simple.widget.HorizontalProgressBarWithNumber;
import java.util.List;
/**
* Created by Aria.Lao on 2017/9/5.
*/
@SuppressLint("ValidFragment") public class ChildHandleDialog
extends BaseDialog<DialogSubTaskHandlerBinding> {
@Bind(R.id.sub_task) TextView mSub;
@Bind(R.id.task_group) TextView mGroup;
@Bind(R.id.pb) HorizontalProgressBarWithNumber mPb;
private String mGroupName;
private String mChildName;
private List<String> mUrls;
private DownloadEntity mChildEntity;
public ChildHandleDialog(Context context, List<String> urls, DownloadEntity childEntity) {
super(context);
setStyle(STYLE_NO_TITLE, R.style.Theme_Light_Dialog);
mChildEntity = childEntity;
mGroupName = "任务组测试";
mUrls = urls;
mChildName = childEntity.getFileName();
}
@Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
Aria.download(this).register();
initWidget();
}
@Override public void onDestroy() {
super.onDestroy();
Aria.download(this).unRegister();
}
private void initWidget() {
mGroup.setText("任务组:" + mGroupName);
mSub.setText("子任务:" + mChildName);
mPb.setProgress((int) (mChildEntity.getCurrentProgress() * 100 / mChildEntity.getFileSize()));
Window window = getDialog().getWindow();
window.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
WindowManager.LayoutParams p = window.getAttributes();
p.width = ViewGroup.LayoutParams.MATCH_PARENT;
window.setAttributes(p);
window.setWindowAnimations(R.style.dialogStyle);
}
@DownloadGroup.onSubTaskRunning void onSubTaskRunning(DownloadGroupTask groupTask,
DownloadEntity subEntity) {
if (!subEntity.getUrl().equals(mChildEntity.getUrl())) return;
mPb.setProgress(subEntity.getPercent());
}
@DownloadGroup.onSubTaskPre void onSubTaskPre(DownloadGroupTask groupTask,
DownloadEntity subEntity) {
if (!subEntity.getUrl().equals(mChildEntity.getUrl())) return;
L.d(TAG, subEntity.getPercent() + "");
}
@DownloadGroup.onSubTaskStop void onSubTaskStop(DownloadGroupTask groupTask,
DownloadEntity subEntity) {
if (!subEntity.getUrl().equals(mChildEntity.getUrl())) return;
mSub.setText("子任务:" + mChildName + ",状态:任务停止");
}
@DownloadGroup.onSubTaskStart void onSubTaskStart(DownloadGroupTask groupTask,
DownloadEntity subEntity) {
if (!subEntity.getUrl().equals(mChildEntity.getUrl())) return;
mSub.setText("子任务:" + mChildName + ",状态:下载中");
}
//@DownloadGroup.onSubTaskCancel void onSubTaskCancel(DownloadGroupTask groupTask,
// DownloadEntity subEntity) {
// mSub.setText("子任务:" + mChildName + ",状态:取消下载");
//}
@DownloadGroup.onSubTaskComplete void onSubTaskComplete(DownloadGroupTask groupTask,
DownloadEntity subEntity) {
if (!subEntity.getUrl().equals(mChildEntity.getUrl())) return;
mSub.setText("子任务:" + mChildName + ",状态:任务完成");
mPb.setProgress(100);
}
@DownloadGroup.onSubTaskFail void onSubTaskFail(DownloadGroupTask groupTask,
DownloadEntity subEntity) {
if (!subEntity.getUrl().equals(mChildEntity.getUrl())) return;
L.d(TAG, subEntity.getPercent() + "");
}
@Override protected int setLayoutId() {
return R.layout.dialog_sub_task_handler;
}
@OnClick({ R.id.start, R.id.stop }) void onClick(View view) {
switch (view.getId()) {
case R.id.start:
Aria.download(this).load(mUrls).getSubTaskManager().startSubTask(mChildEntity.getUrl());
break;
case R.id.stop:
Aria.download(this).load(mUrls).getSubTaskManager().stopSubTask(mChildEntity.getUrl());
break;
//case R.id.cancel:
// Aria.download(this).load(mUrls).getSubTaskManager().cancelSubTask(mChildEntity.getUrl());
// break;
}
}
@Override protected void dataCallback(int result, Object obj) {
}
}

@ -17,14 +17,12 @@ package com.arialyy.simple.download.group;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.support.design.widget.FloatingActionButton;
import android.view.View;
import android.widget.Button;
import butterknife.Bind;
import com.arialyy.annotations.DownloadGroup;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
@ -49,7 +47,6 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
Aria.download(this).register();
setTitle("任务组");
mUrls = getModule(GroupModule.class).getUrls();
DownloadGroupEntity e = Aria.download(this).getGroupTaskList().get(0);
DownloadGroupTaskEntity entity = Aria.download(this).getDownloadGroupTask(mUrls);
if (entity != null && entity.getEntity() != null) {
DownloadGroupEntity groupEntity = entity.getEntity();
@ -62,6 +59,19 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
: (int) (groupEntity.getCurrentProgress() * 100 / groupEntity.getFileSize()));
}
}
mChildList.setOnItemClickListener(new SubStateLinearLayout.OnItemClickListener() {
@Override public void onItemClick(int position, View view) {
showPopupWindow(position);
}
});
}
private void showPopupWindow(int position) {
ChildHandleDialog dialog =
new ChildHandleDialog(this, mUrls, mChildList.getSubData().get(position));
dialog.show(getSupportFragmentManager(), "sub_dialog");
}
@Override protected int setLayoutId() {
@ -77,7 +87,7 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
Environment.getExternalStorageDirectory().getPath() + "/Download/group_test_3")
.setGroupAlias("任务组测试")
.setSubFileName(getModule(GroupModule.class).getSubName())
.setFileSize(32895492)
//.setFileSize(32895492)
.start();
break;
case R.id.stop:
@ -99,7 +109,7 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
}
L.d(TAG, "group task pre");
getBinding().setFileSize(task.getConvertFileSize());
if (mChildList.getSubData().size() <= 0){
if (mChildList.getSubData().size() <= 0) {
mChildList.addData(task.getEntity().getSubTask());
}
}
@ -109,7 +119,6 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
}
@DownloadGroup.onTaskRunning() protected void running(DownloadGroupTask task) {
L.d(TAG, "P ==> " + task.getPercent());
getBinding().setProgress(task.getPercent());
getBinding().setSpeed(task.getConvertSpeed());
mChildList.updateChildProgress(task.getEntity().getSubTask());
@ -141,4 +150,5 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
T.showShort(this, "任务组下载完成");
L.d(TAG, "任务组下载完成");
}
}

@ -66,7 +66,8 @@ public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> {
dialog.show(getSupportFragmentManager(), "download_num");
break;
case R.id.stop_all:
Aria.download(this).stopAllTask();
//Aria.download(this).stopAllTask();
Aria.download(this).removeAllTask(true);
break;
case R.id.turn:
startActivity(new Intent(this, MultiDownloadActivity.class));

@ -1,8 +1,24 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.simple.widget;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
@ -17,16 +33,22 @@ import java.util.WeakHashMap;
/**
* Created by Aria.Lao on 2017/7/17.
*/
public class SubStateLinearLayout extends LinearLayout {
public class SubStateLinearLayout extends LinearLayout implements View.OnClickListener {
interface OnShowCallback {
void onShow(boolean visibility);
}
OnShowCallback callback;
public interface OnItemClickListener {
void onItemClick(int position, View view);
}
OnShowCallback mShowCallback;
OnItemClickListener mItemClickListener;
List<DownloadEntity> mSubData = new LinkedList<>();
Map<String, Integer> mPosition = new WeakHashMap<>();
SparseArray<View> mViews = new SparseArray<>();
public SubStateLinearLayout(Context context) {
super(context);
@ -50,15 +72,25 @@ public class SubStateLinearLayout extends LinearLayout {
createShowView();
int i = 1;
for (DownloadEntity entity : datas) {
TextView view = createView(entity);
TextView view = createView(i - 1, entity);
mPosition.put(entity.getDownloadPath(), i);
addView(view, i);
i++;
}
}
@Override public void onClick(View v) {
if (mItemClickListener != null) {
mItemClickListener.onItemClick(mViews.indexOfValue(v), v);
}
}
public void setOnShowCallback(OnShowCallback callback) {
this.callback = callback;
this.mShowCallback = callback;
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.mItemClickListener = listener;
}
public List<DownloadEntity> getSubData() {
@ -79,10 +111,12 @@ public class SubStateLinearLayout extends LinearLayout {
}
}
private TextView createView(DownloadEntity entity) {
private TextView createView(int position, DownloadEntity entity) {
TextView view =
(TextView) LayoutInflater.from(getContext()).inflate(R.layout.layout_child_state, null);
view.setText(entity.getFileName() + ": " + getPercent(entity) + "%");
view.setOnClickListener(this);
mViews.append(position, view);
return view;
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="100%"
android:duration="100"/>
</set>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="100"
android:toYDelta="100%"/>
</set>

@ -17,7 +17,7 @@
/>
</data>
<LinearLayout
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
@ -27,18 +27,24 @@
<include
layout="@layout/content_single"
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/toolbar"
bind:fileSize="@{fileSize}"
bind:progress="@{progress}"
bind:speed="@{speed}"
/>
<com.arialyy.simple.widget.SubStateLinearLayout
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:id="@+id/child_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/content"
android:paddingLeft="16dp"
android:paddingRight="16dp"
/>
</RelativeLayout>
</LinearLayout>
</layout>

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:padding="16dp"
>
<TextView
android:id="@+id/task_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="任务组:"
/>
<TextView
android:id="@+id/sub_task"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/task_group"
android:layout_marginTop="5dp"
android:text="子任务:"
/>
<com.arialyy.simple.widget.HorizontalProgressBarWithNumber
android:id="@+id/pb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/sub_task"
android:layout_marginTop="10dp"
android:max="100"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/pb"
android:orientation="horizontal"
>
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="开始"
style="?buttonBarButtonStyle"
/>
<Button
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="停止"
style="?buttonBarButtonStyle"
/>
<!--<Button-->
<!--android:id="@+id/cancel"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_weight="1"-->
<!--android:text="删除"-->
<!--style="?buttonBarButtonStyle"-->
<!--/>-->
</LinearLayout>
</RelativeLayout>
</layout>

@ -49,45 +49,45 @@
<string-array name="group_urls">
<!--<item>https://res5.d.cn/5a6a3384c1b2be1a65d84b914e6a6fef697637578b6db2eb1056d50b09cf1dcf289d4045df7ef95746e498e3d6a848ab84c89b77aa60194e2c48e5a7cb748265.apk</item>-->
<!--<item>https://res5.d.cn/5a6a3384c1b2be1a52034c72752e8475414630ebc69318b84ef584115ebf5eaaab945ae07b7fe3596afc72a7940ff328d4a9553f6ae92d6c09ba4bfb533137f6.apk</item>-->
<!--<item>https://res5.d.cn/5a6a3384c1b2be1a426f06bfc69034d69c44ae1a01da180cab8e59bd1a5e1a784bac46ba0c64579d14f0e80a4ce4f068af89b0369a393456f4f449a8829cad5c.apk</item>-->
<item>https://res5.d.cn/5a6a3384c1b2be1a426f06bfc69034d69c44ae1a01da180cab8e59bd1a5e1a784bac46ba0c64579d14f0e80a4ce4f068af89b0369a393456f4f449a8829cad5c.apk</item>
<item>http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk</item>
<item>http://static.ilongyuan.cn/rayark/RayarkFZ_2.0.7.apk</item>
</string-array>
<string-array name="group_urls_1">
<item>http://droidweb.smartgame-down.com/201708171123/C183E9C2010C7CABACFB398250A3DB75/new/game1/1/107001/qq_1502875308555.apk?f=web_1</item>
<item>http://droidweb.smartgame-down.com/201708171124/6E5AF91791661236D0A2F60125D3B45F/new/game1/93/113093/00D42A6AA63A039485F510C2E4D69BAA_1498831237.apk?f=web_1</item>
<item>http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk</item>
<item>http://hzdown.muzhiwan.com/2017/09/05/com.mir.iphone.empire83jie.mzw_59ae6d5a3638d.apk</item>
</string-array>
<string-array name="group_urls_2">
<item>http://droidweb.smartgame-down.com/201708171125/005BCF0FFBB75510958D14074286B25F/new/game1/2/106202/qqkj_1502868291416.apk?f=web_1</item>
<item>http://droidweb.smartgame-down.com/201708171126/05FAAA4FD294BC63AA8F792636961D19/new/game1/72/110472/com.taobao.taobao-6.9.0-157-0629_1498744826.apk?f=web_1</item>
<item>http://down.muzhiwan.com/2017/04/05/org.sanguoqy01_58e4993914424.apk</item>
<item>http://apk500.bce.baidu-mgame.com/game/67000/67734/20170622040827_oem_5502845.apk?r=1</item>
</string-array>
<string-array name="group_urls_3">
<item>http://droidweb.smartgame-down.com/201708171127/F55445FD8B7BBA8D72CA4B7D7BD91F90/new/game1/84/33184/txtim_1502854269836.apk?f=web_1</item>
<item>http://droidweb.smartgame-down.com/201708171128/5C4D0289F0B83690BF252420F473FB9F/new/game1/46/108046/com.shuqi.controller-10.5.2.50-137-0703_1499083244.apk?f=web_1</item>
<item>http://apk500.bce.baidu-mgame.com/game/883000/883227/20170828102306_oem_5502845.apk?r=1</item>
<item>http://static.gaoshouyou.com/d/92/12/5592a647b8126755647abbe8074fde39.apk</item>
</string-array>
<string-array name="group_names">
<item>王者荣耀.apk</item>
<item>战斗吧剑灵.apk</item>
<!--<item>天魔幻想.apk</item>-->
<item>天魔幻想.apk</item>
</string-array>
<string-array name="group_names_1">
<item>QQ.apk</item>
<item>百度贴吧.apk</item>
<item>新大陆.apk</item>
<item>罗马战争.apk</item>
</string-array>
<string-array name="group_names_2">
<item>QQ空间.apk</item>
<item>淘宝.apk</item>
<item>三国群英传.apk</item>
<item>海岛骑兵</item>
</string-array>
<string-array name="group_names_3">
<item>TIM.apk</item>
<item>书旗小说.apk</item>
<item>部落冲突.apk</item>
<item>城堡争霸.apk</item>
</string-array>
</resources>

@ -22,4 +22,21 @@
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
<style name="dialogStyle" parent="@android:style/Animation.Dialog">
<item name="@android:windowEnterAnimation">@anim/dialog_enter</item>
<!-- 进入时的动画 -->
<item name="@android:windowExitAnimation">@anim/dialog_exit</item>
<!-- 退出时的动画 -->
</style>
<!-- 对话框样式 -->
<style name="Theme.Light.Dialog" parent="android:style/Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:scrollHorizontally">true</item>
</style>
</resources>

@ -37,7 +37,7 @@ task clean(type: Delete) {
ext {
userOrg = 'arialyy'
groupId = 'com.arialyy.aria'
publishVersion = '3.2.26'
publishVersion = '3.3.0'
repoName='maven'
desc = 'android 下载框架'
website = 'https://github.com/AriaLyy/Aria'

@ -13,7 +13,9 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Wed Dec 07 20:19:22 CST 2016
org.gradle.daemon=true
org.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
# gradle proxy https://chaosleong.github.io/2017/02/10/Configuring-Gradle-Proxy/
#systemProp.socksProxyHost=127.0.0.1
#systemProp.socksProxyPort=58224
#systemProp.socksProxyPort=51110
#systemprop.socksProxyVersion=5
Loading…
Cancel
Save