修复任务记录删除失败的问题,优化网络连接状态获取的逻辑,修复配置文件的某些配置失效的问题
This commit is contained in:
@@ -21,13 +21,20 @@ import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkRequest;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.widget.PopupWindow;
|
||||
import com.arialyy.aria.BuildConfig;
|
||||
import com.arialyy.aria.core.command.ICmd;
|
||||
import com.arialyy.aria.core.common.QueueMod;
|
||||
import com.arialyy.aria.core.common.RecordHandler;
|
||||
@@ -71,6 +78,10 @@ import org.xml.sax.SAXException;
|
||||
public static final Object LOCK = new Object();
|
||||
public static final String DOWNLOAD_TEMP_DIR = "/Aria/temp/download/";
|
||||
public static final String UPLOAD_TEMP_DIR = "/Aria/temp/upload/";
|
||||
/**
|
||||
* 是否已经联网,true 已经联网
|
||||
*/
|
||||
private static boolean isConnectedNet = true;
|
||||
|
||||
@SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null;
|
||||
private Map<String, AbsReceiver> mReceivers = new ConcurrentHashMap<>();
|
||||
@@ -85,7 +96,6 @@ import org.xml.sax.SAXException;
|
||||
private AppConfig mAConfig;
|
||||
private DGroupConfig mDGConfig;
|
||||
private Handler mAriaHandler;
|
||||
private File[] files;
|
||||
|
||||
private AriaManager(Context context) {
|
||||
APP = context.getApplicationContext();
|
||||
@@ -94,6 +104,7 @@ import org.xml.sax.SAXException;
|
||||
initConfig();
|
||||
initAria();
|
||||
amendTaskState();
|
||||
regNetCallBack(context);
|
||||
}
|
||||
|
||||
public static AriaManager getInstance(Context context) {
|
||||
@@ -109,6 +120,47 @@ import org.xml.sax.SAXException;
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册网络监听,只有配置了检查网络{@link AppConfig#isNetCheck()}才会注册事件
|
||||
*/
|
||||
private void regNetCallBack(Context context) {
|
||||
if (!getAppConfig().isNetCheck()) {
|
||||
return;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
return;
|
||||
}
|
||||
ConnectivityManager cm =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (cm == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkRequest.Builder builder = new NetworkRequest.Builder();
|
||||
NetworkRequest request = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.build();
|
||||
|
||||
cm.registerNetworkCallback(request, new ConnectivityManager.NetworkCallback() {
|
||||
|
||||
@Override public void onLost(Network network) {
|
||||
super.onLost(network);
|
||||
isConnectedNet = false;
|
||||
ALog.d(TAG, "onLost");
|
||||
}
|
||||
|
||||
@Override public void onAvailable(Network network) {
|
||||
super.onAvailable(network);
|
||||
ALog.d(TAG, "onAvailable");
|
||||
isConnectedNet = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化数据库
|
||||
*/
|
||||
private void initDb(Context context) {
|
||||
// 这个地方错误了,获取数据库路径见:https://www.jianshu.com/p/815c9efc5449
|
||||
String oldDbName = "AriaLyyDb";
|
||||
@@ -153,6 +205,10 @@ import org.xml.sax.SAXException;
|
||||
return mAriaHandler;
|
||||
}
|
||||
|
||||
public boolean isConnectedNet() {
|
||||
return isConnectedNet;
|
||||
}
|
||||
|
||||
public Map<String, AbsReceiver> getReceiver() {
|
||||
return mReceivers;
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
return b;
|
||||
}
|
||||
|
||||
public synchronized void cancel() {
|
||||
final public synchronized void cancel() {
|
||||
if (isCancel) {
|
||||
ALog.d(TAG, String.format("任务【%s】正在删除,删除任务失败", mTaskWrapper.getKey()));
|
||||
return;
|
||||
@@ -208,13 +208,24 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
}
|
||||
}
|
||||
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
|
||||
onPostCancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除线程任务前的操作
|
||||
*/
|
||||
protected void onCancel() {
|
||||
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
/**
|
||||
* 删除操作处理完成
|
||||
*/
|
||||
protected void onPostCancel() {
|
||||
|
||||
}
|
||||
|
||||
final public synchronized void stop() {
|
||||
if (isStop) {
|
||||
return;
|
||||
}
|
||||
@@ -229,12 +240,23 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
}
|
||||
}
|
||||
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
|
||||
onPostStop();
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止线程任务前的操作
|
||||
*/
|
||||
protected void onStop() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止操作完成
|
||||
*/
|
||||
protected void onPostStop() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接调用的时候会自动启动线程执行
|
||||
*/
|
||||
|
||||
@@ -175,17 +175,15 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
* 中断任务
|
||||
*/
|
||||
void breakTask() {
|
||||
synchronized (AriaManager.LOCK) {
|
||||
taskBreak = true;
|
||||
if (mTaskWrapper.isSupportBP()) {
|
||||
final long currentTemp = mChildCurrentLocation;
|
||||
sendState(IThreadState.STATE_STOP, null);
|
||||
ALog.d(TAG, String.format("任务【%s】thread__%s__中断【停止位置:%s】", getFileName(),
|
||||
mRecord.threadId, currentTemp));
|
||||
writeConfig(false, currentTemp);
|
||||
} else {
|
||||
ALog.i(TAG, String.format("任务【%s】已中断", getFileName()));
|
||||
}
|
||||
taskBreak = true;
|
||||
if (mTaskWrapper.isSupportBP()) {
|
||||
final long currentTemp = mChildCurrentLocation;
|
||||
sendState(IThreadState.STATE_STOP, null);
|
||||
ALog.d(TAG, String.format("任务【%s】thread__%s__中断【停止位置:%s】", getFileName(),
|
||||
mRecord.threadId, currentTemp));
|
||||
writeConfig(false, currentTemp);
|
||||
} else {
|
||||
ALog.i(TAG, String.format("任务【%s】已中断", getFileName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,28 +274,26 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
* 执行中
|
||||
*/
|
||||
protected void progress(long len) {
|
||||
synchronized (AriaManager.LOCK) {
|
||||
//if (getState().CURRENT_LOCATION > getEntity().getFileSize() && !getTaskWrapper().asHttp()
|
||||
// .isChunked()) {
|
||||
// String errorMsg =
|
||||
// String.format("下载失败,下载长度超出文件真实长度;currentLocation=%s, fileSize=%s",
|
||||
// getState().CURRENT_LOCATION,
|
||||
// getEntity().getFileSize());
|
||||
// taskBreak = true;
|
||||
// fail(mChildCurrentLocation, new FileException(TAG, errorMsg), false);
|
||||
// return;
|
||||
//}
|
||||
mChildCurrentLocation += len;
|
||||
if (!mStateHandler.getLooper().getThread().isAlive()) {
|
||||
return;
|
||||
}
|
||||
mStateHandler.obtainMessage(IThreadState.STATE_RUNNING, len).sendToTarget();
|
||||
if (System.currentTimeMillis() - mLastSaveTime > 5000
|
||||
&& mChildCurrentLocation < mRecord.endLocation) {
|
||||
mLastSaveTime = System.currentTimeMillis();
|
||||
if (!mConfigThreadPool.isShutdown()) {
|
||||
mConfigThreadPool.execute(mConfigThread);
|
||||
}
|
||||
//if (getState().CURRENT_LOCATION > getEntity().getFileSize() && !getTaskWrapper().asHttp()
|
||||
// .isChunked()) {
|
||||
// String errorMsg =
|
||||
// String.format("下载失败,下载长度超出文件真实长度;currentLocation=%s, fileSize=%s",
|
||||
// getState().CURRENT_LOCATION,
|
||||
// getEntity().getFileSize());
|
||||
// taskBreak = true;
|
||||
// fail(mChildCurrentLocation, new FileException(TAG, errorMsg), false);
|
||||
// return;
|
||||
//}
|
||||
mChildCurrentLocation += len;
|
||||
if (!mStateHandler.getLooper().getThread().isAlive()) {
|
||||
return;
|
||||
}
|
||||
mStateHandler.obtainMessage(IThreadState.STATE_RUNNING, len).sendToTarget();
|
||||
if (System.currentTimeMillis() - mLastSaveTime > 5000
|
||||
&& mChildCurrentLocation < mRecord.endLocation) {
|
||||
mLastSaveTime = System.currentTimeMillis();
|
||||
if (!mConfigThreadPool.isShutdown()) {
|
||||
mConfigThreadPool.execute(mConfigThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -350,14 +346,15 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
* 重试ts分片
|
||||
*/
|
||||
private void retryM3U8Peer(boolean needRetry) {
|
||||
if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) {
|
||||
ALog.w(TAG, String.format("任务【%s】重试失败,网络未连接", getFileName()));
|
||||
boolean isConnected = NetUtils.isConnected(AriaManager.APP);
|
||||
if (!isConnected && !isNotNetRetry) {
|
||||
ALog.w(TAG, String.format("ts切片【%s】重试失败,网络未连接", getFileName()));
|
||||
sendFailMsg(null);
|
||||
return;
|
||||
}
|
||||
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP)
|
||||
|| isNotNetRetry) && !isBreak()) {
|
||||
ALog.w(TAG, String.format("任务【%s】正在重试", getFileName()));
|
||||
ALog.w(TAG, String.format("ts切片【%s】正在重试", getFileName()));
|
||||
mFailTimes++;
|
||||
mConfig.tempFile.delete();
|
||||
CommonUtil.createFile(mConfig.tempFile.getPath());
|
||||
@@ -374,13 +371,13 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
*/
|
||||
private void retryBlockTask(boolean needRetry) {
|
||||
if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) {
|
||||
ALog.w(TAG, String.format("任务【%s】重试失败,网络未连接", getFileName()));
|
||||
ALog.w(TAG, String.format("分块【%s】重试失败,网络未连接", getFileName()));
|
||||
sendFailMsg(null);
|
||||
return;
|
||||
}
|
||||
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP)
|
||||
|| isNotNetRetry) && !isBreak()) {
|
||||
ALog.w(TAG, String.format("任务【%s】正在重试", getFileName()));
|
||||
ALog.w(TAG, String.format("分块【%s】正在重试", getFileName()));
|
||||
mFailTimes++;
|
||||
handleBlockRecord();
|
||||
ThreadTaskManager.getInstance().retryThread(this);
|
||||
|
||||
@@ -156,13 +156,13 @@ public abstract class BaseListener<ENTITY extends AbsEntity, TASK_WRAPPER extend
|
||||
mEntity.setCurrentProgress(mEntity.getFileSize());
|
||||
mEntity.setPercent(100);
|
||||
handleSpeed(0);
|
||||
ALog.i(TAG, String.format("任务【%s】完成,将删除线程任务记录", mEntity.getKey()));
|
||||
ALog.i(TAG, String.format("任务【%s】完成,将删除任务任务记录", mEntity.getKey()));
|
||||
if (mEntity instanceof DownloadGroupEntity) {
|
||||
RecordUtil.delGroupTaskRecord((DownloadGroupEntity) mEntity, false, false);
|
||||
} else if (mEntity instanceof DownloadEntity) {
|
||||
RecordUtil.delTaskRecord(mEntity.getKey(), RecordHandler.TYPE_DOWNLOAD, false, false);
|
||||
RecordUtil.delTaskRecord(((DownloadEntity) mEntity).getFilePath(), RecordHandler.TYPE_DOWNLOAD, false, false);
|
||||
} else if (mEntity instanceof UploadEntity) {
|
||||
RecordUtil.delTaskRecord(mEntity.getKey(), RecordHandler.TYPE_UPLOAD, false, false);
|
||||
RecordUtil.delTaskRecord(((UploadEntity) mEntity).getFilePath(), RecordHandler.TYPE_UPLOAD, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ public class RecordHandler {
|
||||
public static final String SUB_PATH = "%s.%s.part";
|
||||
|
||||
@Deprecated private File mConfigFile;
|
||||
private TaskRecord mRecord;
|
||||
private TaskRecord mTaskRecord;
|
||||
private AbsTaskWrapper mTaskWrapper;
|
||||
private AbsNormalEntity mEntity;
|
||||
|
||||
@@ -81,11 +81,11 @@ public class RecordHandler {
|
||||
if (mConfigFile.exists()) {
|
||||
convertDb();
|
||||
} else {
|
||||
mRecord = DbDataHelper.getTaskRecord(getFilePath());
|
||||
if (mRecord == null) {
|
||||
mTaskRecord = DbDataHelper.getTaskRecord(getFilePath());
|
||||
if (mTaskRecord == null) {
|
||||
initRecord(true);
|
||||
} else {
|
||||
if (mRecord.threadRecords == null || mRecord.threadRecords.isEmpty()) {
|
||||
if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.isEmpty()) {
|
||||
initRecord(false);
|
||||
}
|
||||
|
||||
@@ -94,10 +94,12 @@ public class RecordHandler {
|
||||
} else if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) {
|
||||
ALog.i(TAG, "直播下载不处理历史记录");
|
||||
} else {
|
||||
if (mRecord.isBlock) {
|
||||
if (mTaskRecord.isBlock) {
|
||||
handleBlockRecord();
|
||||
} else if (!mTaskWrapper.isSupportBP()) {
|
||||
handleNoSupportBPRecord();
|
||||
} else if (!mTaskRecord.isBlock && mTaskRecord.threadNum > 1) {
|
||||
handleNoBlockMultiThreadRecord();
|
||||
} else {
|
||||
handleSingleThreadRecord();
|
||||
}
|
||||
@@ -105,7 +107,7 @@ public class RecordHandler {
|
||||
}
|
||||
}
|
||||
saveRecord();
|
||||
return mRecord;
|
||||
return mTaskRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +121,7 @@ public class RecordHandler {
|
||||
String cacheDir = wrapper.asM3U8().getCacheDir();
|
||||
long currentProgress = 0;
|
||||
int completeNum = 0;
|
||||
for (ThreadRecord record : mRecord.threadRecords) {
|
||||
for (ThreadRecord record : mTaskRecord.threadRecords) {
|
||||
File temp = new File(BaseM3U8Loader.getTsFilePath(cacheDir, record.threadId));
|
||||
if (!record.isComplete) {
|
||||
if (temp.exists()) {
|
||||
@@ -140,32 +142,45 @@ public class RecordHandler {
|
||||
}
|
||||
wrapper.asM3U8().setCompleteNum(completeNum);
|
||||
wrapper.getEntity().setCurrentProgress(currentProgress);
|
||||
mTaskRecord.bandWidth = wrapper.asM3U8().getBandWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理不支持断点的记录
|
||||
*/
|
||||
private void handleNoSupportBPRecord() {
|
||||
ThreadRecord tr = mRecord.threadRecords.get(0);
|
||||
ThreadRecord tr = mTaskRecord.threadRecords.get(0);
|
||||
tr.startLocation = 0;
|
||||
tr.endLocation = mEntity.getFileSize();
|
||||
tr.key = mRecord.filePath;
|
||||
tr.key = mTaskRecord.filePath;
|
||||
tr.blockLen = tr.endLocation;
|
||||
tr.isComplete = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理为不分块的多线程任务
|
||||
*/
|
||||
private void handleNoBlockMultiThreadRecord() {
|
||||
File file = new File(mTaskRecord.filePath);
|
||||
if (!file.exists()) {
|
||||
ALog.w(TAG, String.format("文件【%s】不存在,重新分配线程区间", mTaskRecord.filePath));
|
||||
DbEntity.deleteData(ThreadRecord.class, "key=?", mTaskRecord.filePath);
|
||||
initRecord(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单线程的任务的记录
|
||||
*/
|
||||
private void handleSingleThreadRecord() {
|
||||
File file = new File(mRecord.filePath);
|
||||
ThreadRecord tr = mRecord.threadRecords.get(0);
|
||||
File file = new File(mTaskRecord.filePath);
|
||||
ThreadRecord tr = mTaskRecord.threadRecords.get(0);
|
||||
if (!file.exists()) {
|
||||
ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath()));
|
||||
tr.startLocation = 0;
|
||||
tr.isComplete = false;
|
||||
tr.endLocation = mEntity.getFileSize();
|
||||
} else if (mRecord.isOpenDynamicFile) {
|
||||
} else if (mTaskRecord.isOpenDynamicFile) {
|
||||
if (file.length() > mEntity.getFileSize()) {
|
||||
ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath()));
|
||||
file.delete();
|
||||
@@ -190,11 +205,11 @@ public class RecordHandler {
|
||||
*/
|
||||
private void handleBlockRecord() {
|
||||
// 默认线程分块长度
|
||||
long normalRectLen = mEntity.getFileSize() / mRecord.threadRecords.size();
|
||||
for (ThreadRecord tr : mRecord.threadRecords) {
|
||||
long normalRectLen = mEntity.getFileSize() / mTaskRecord.threadRecords.size();
|
||||
for (ThreadRecord tr : mTaskRecord.threadRecords) {
|
||||
long threadRect = tr.blockLen;
|
||||
|
||||
File temp = new File(String.format(SUB_PATH, mRecord.filePath, tr.threadId));
|
||||
File temp = new File(String.format(SUB_PATH, mTaskRecord.filePath, tr.threadId));
|
||||
if (!temp.exists()) {
|
||||
ALog.i(TAG, String.format("分块文件【%s】不存在,该分块将重新开始", temp.getPath()));
|
||||
tr.isComplete = false;
|
||||
@@ -269,13 +284,13 @@ public class RecordHandler {
|
||||
return;
|
||||
}
|
||||
mTaskWrapper.setNewTask(false);
|
||||
mRecord = createTaskRecord(threadNum);
|
||||
mRecord.isOpenDynamicFile = false;
|
||||
mRecord.isBlock = false;
|
||||
mTaskRecord = createTaskRecord(threadNum);
|
||||
mTaskRecord.isOpenDynamicFile = false;
|
||||
mTaskRecord.isBlock = false;
|
||||
File tempFile = new File(getFilePath());
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
ThreadRecord tRecord = new ThreadRecord();
|
||||
tRecord.key = mRecord.filePath;
|
||||
tRecord.key = mTaskRecord.filePath;
|
||||
Object state = pro.getProperty(tempFile.getName() + STATE + i);
|
||||
Object record = pro.getProperty(tempFile.getName() + RECORD + i);
|
||||
if (state != null && Integer.parseInt(String.valueOf(state)) == 1) {
|
||||
@@ -288,7 +303,7 @@ public class RecordHandler {
|
||||
} else {
|
||||
tRecord.startLocation = 0;
|
||||
}
|
||||
mRecord.threadRecords.add(tRecord);
|
||||
mTaskRecord.threadRecords.add(tRecord);
|
||||
}
|
||||
mConfigFile.delete();
|
||||
}
|
||||
@@ -301,20 +316,20 @@ public class RecordHandler {
|
||||
*/
|
||||
private void initRecord(boolean newRecord) {
|
||||
if (newRecord) {
|
||||
mRecord = createTaskRecord(getNewTaskThreadNum());
|
||||
mTaskRecord = createTaskRecord(getNewTaskThreadNum());
|
||||
}
|
||||
mTaskWrapper.setNewTask(true);
|
||||
int requestType = mTaskWrapper.getRequestType();
|
||||
if (requestType == ITaskWrapper.M3U8_LIVE) {
|
||||
return;
|
||||
}
|
||||
long blockSize = mEntity.getFileSize() / mRecord.threadNum;
|
||||
long blockSize = mEntity.getFileSize() / mTaskRecord.threadNum;
|
||||
// 处理线程区间记录
|
||||
for (int i = 0; i < mRecord.threadNum; i++) {
|
||||
for (int i = 0; i < mTaskRecord.threadNum; i++) {
|
||||
long startL = i * blockSize, endL = (i + 1) * blockSize;
|
||||
ThreadRecord tr;
|
||||
tr = new ThreadRecord();
|
||||
tr.key = mRecord.filePath;
|
||||
tr.key = mTaskRecord.filePath;
|
||||
tr.threadId = i;
|
||||
tr.startLocation = startL;
|
||||
tr.isComplete = false;
|
||||
@@ -325,13 +340,13 @@ public class RecordHandler {
|
||||
} else {
|
||||
tr.threadType = TaskRecord.TYPE_HTTP_FTP;
|
||||
//最后一个线程的结束位置即为文件的总长度
|
||||
if (i == (mRecord.threadNum - 1)) {
|
||||
if (i == (mTaskRecord.threadNum - 1)) {
|
||||
endL = mEntity.getFileSize();
|
||||
}
|
||||
tr.endLocation = endL;
|
||||
tr.blockLen = RecordUtil.getBlockLen(mEntity.getFileSize(), i, mRecord.threadNum);
|
||||
tr.blockLen = RecordUtil.getBlockLen(mEntity.getFileSize(), i, mTaskRecord.threadNum);
|
||||
}
|
||||
mRecord.threadRecords.add(tr);
|
||||
mTaskRecord.threadRecords.add(tr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,9 +365,11 @@ public class RecordHandler {
|
||||
if (requestType == ITaskWrapper.M3U8_VOD) {
|
||||
record.taskType = TaskRecord.TYPE_M3U8_VOD;
|
||||
record.isOpenDynamicFile = true;
|
||||
record.bandWidth = ((DTaskWrapper)mTaskWrapper).asM3U8().getBandWidth();
|
||||
} else if (requestType == ITaskWrapper.M3U8_LIVE) {
|
||||
record.taskType = TaskRecord.TYPE_M3U8_LIVE;
|
||||
record.isOpenDynamicFile = true;
|
||||
record.bandWidth = ((DTaskWrapper)mTaskWrapper).asM3U8().getBandWidth();
|
||||
} else {
|
||||
if (getRecordType() == TYPE_DOWNLOAD) {
|
||||
record.isBlock = threadNum > 1 && Configuration.getInstance().downloadCfg.isUseBlock();
|
||||
@@ -377,12 +394,12 @@ public class RecordHandler {
|
||||
* 保存任务记录
|
||||
*/
|
||||
private void saveRecord() {
|
||||
mRecord.threadNum = mRecord.threadRecords.size();
|
||||
mRecord.save();
|
||||
if (mRecord.threadRecords != null && !mRecord.threadRecords.isEmpty()) {
|
||||
DbEntity.saveAll(mRecord.threadRecords);
|
||||
mTaskRecord.threadNum = mTaskRecord.threadRecords.size();
|
||||
mTaskRecord.save();
|
||||
if (mTaskRecord.threadRecords != null && !mTaskRecord.threadRecords.isEmpty()) {
|
||||
DbEntity.saveAll(mTaskRecord.threadRecords);
|
||||
}
|
||||
ALog.d(TAG, String.format("保存记录,线程记录数:%s", mRecord.threadRecords.size()));
|
||||
ALog.d(TAG, String.format("保存记录,线程记录数:%s", mTaskRecord.threadRecords.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -89,4 +89,9 @@ public class TaskRecord extends DbEntity {
|
||||
* {@link #TYPE_HTTP_FTP}、{@link #TYPE_M3U8_VOD}
|
||||
*/
|
||||
public int taskType = 0;
|
||||
|
||||
/**
|
||||
* m3u8文件码率
|
||||
*/
|
||||
public long bandWidth = 0;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.common;
|
||||
|
||||
import com.arialyy.aria.orm.ActionPolicy;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/5/8.
|
||||
@@ -25,7 +23,9 @@ import com.arialyy.aria.orm.annotation.Foreign;
|
||||
*/
|
||||
public class ThreadRecord extends DbEntity {
|
||||
|
||||
@Foreign(parent = TaskRecord.class, column = "filePath", onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
|
||||
/**
|
||||
* 任务的文件路径,不是当前线程记录的的分块文件路径
|
||||
*/
|
||||
public String key;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.common.ftp;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.FtpUrlEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTarget;
|
||||
import com.arialyy.aria.core.inf.IFtpTarget;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.net.Proxy;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/9.
|
||||
* ftp 委托
|
||||
*/
|
||||
public class FtpDelegate<TARGET extends AbsTarget> implements IFtpTarget<TARGET> {
|
||||
private static final String TAG = "FtpDelegate";
|
||||
private TARGET mTarget;
|
||||
|
||||
public FtpDelegate(TARGET target) {
|
||||
mTarget = target;
|
||||
}
|
||||
|
||||
@Override public TARGET charSet(String charSet) {
|
||||
if (TextUtils.isEmpty(charSet)) {
|
||||
throw new NullPointerException("字符编码为空");
|
||||
}
|
||||
mTarget.getTaskWrapper().asFtp().setCharSet(charSet);
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
@Override public TARGET login(String userName, String password) {
|
||||
return login(userName, password, null);
|
||||
}
|
||||
|
||||
@Override public TARGET login(String userName, String password, String account) {
|
||||
if (TextUtils.isEmpty(userName)) {
|
||||
ALog.e(TAG, "用户名不能为null");
|
||||
return mTarget;
|
||||
} else if (TextUtils.isEmpty(password)) {
|
||||
ALog.e(TAG, "密码不能为null");
|
||||
return mTarget;
|
||||
}
|
||||
// urlEntity 不能在构造函数中获取,因为ftp上传时url是后于构造函数的
|
||||
FtpUrlEntity urlEntity = mTarget.getTaskWrapper().asFtp().getUrlEntity();
|
||||
urlEntity.needLogin = true;
|
||||
urlEntity.user = userName;
|
||||
urlEntity.password = password;
|
||||
urlEntity.account = account;
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
@Override public TARGET setProxy(Proxy proxy) {
|
||||
mTarget.getTaskWrapper().asFtp().setProxy(proxy);
|
||||
return mTarget;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.common.ftp;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.FtpUrlEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTarget;
|
||||
import com.arialyy.aria.core.inf.IFtpTarget;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.net.Proxy;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/9.
|
||||
* ftp 委托
|
||||
*/
|
||||
public class FtpDelegate<TARGET extends AbsTarget> implements IFtpTarget<TARGET> {
|
||||
private static final String TAG = "FtpDelegate";
|
||||
private TARGET mTarget;
|
||||
|
||||
public FtpDelegate(TARGET target) {
|
||||
mTarget = target;
|
||||
}
|
||||
|
||||
@Override public TARGET charSet(String charSet) {
|
||||
if (TextUtils.isEmpty(charSet)) {
|
||||
throw new NullPointerException("字符编码为空");
|
||||
}
|
||||
mTarget.getTaskWrapper().asFtp().setCharSet(charSet);
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
@Override public TARGET login(String userName, String password) {
|
||||
return login(userName, password, null);
|
||||
}
|
||||
|
||||
@Override public TARGET login(String userName, String password, String account) {
|
||||
if (TextUtils.isEmpty(userName)) {
|
||||
ALog.e(TAG, "用户名不能为null");
|
||||
return mTarget;
|
||||
} else if (TextUtils.isEmpty(password)) {
|
||||
ALog.e(TAG, "密码不能为null");
|
||||
return mTarget;
|
||||
}
|
||||
// urlEntity 不能在构造函数中获取,因为ftp上传时url是后于构造函数的
|
||||
FtpUrlEntity urlEntity = mTarget.getTaskWrapper().asFtp().getUrlEntity();
|
||||
urlEntity.needLogin = true;
|
||||
urlEntity.user = userName;
|
||||
urlEntity.password = password;
|
||||
urlEntity.account = account;
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
//@Override public TARGET setProxy(Proxy proxy) {
|
||||
// mTarget.getTaskWrapper().asFtp().setProxy(proxy);
|
||||
// return mTarget;
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -23,16 +23,23 @@ import java.io.Serializable;
|
||||
*/
|
||||
public class DownloadConfig extends BaseTaskConfig implements Serializable {
|
||||
/**
|
||||
* 下载线程数,下载线程数不能小于1 注意: 1、线程下载数改变后,新的下载任务才会生效; 2、如果任务大小小于1m,该设置不会生效;
|
||||
* 3、从3.4.1开始,如果线程数为1,文件初始化时将不再预占用对应长度的空间,下载多少byte,则占多大的空间; 对于采用多线程的任务或旧任务,依然采用原来的文件空间占用方式;
|
||||
* 下载线程数,下载线程数不能小于1
|
||||
* 注意:
|
||||
* 1、线程下载数改变后,新的下载任务才会生效;
|
||||
* 2、如果任务大小小于1m,该设置不会生效;
|
||||
* 3、从3.4.1开始,如果线程数为1,文件初始化时将不再预占用对应长度的空间,下载多少byte,则占多大的空间;
|
||||
* 对于采用多线程的任务或旧任务,依然采用原来的文件空间占用方式;
|
||||
*/
|
||||
int threadNum = 3;
|
||||
|
||||
/**
|
||||
* 多线程下载是否使用块下载模式,{@code true}使用,{@code false}不使用 注意: 1、使用分块模式,在读写性能底下的手机上,合并文件需要的时间会更加长;
|
||||
* 2、优点是使用多线程的块下载,初始化时,文件初始化时将不会预占用对应长度的空间; 3、只对新的多线程下载任务有效 4、只对多线程的任务有效
|
||||
* 多线程下载是否使用块下载模式,{@code true}使用,{@code false}不使用
|
||||
* 注意:
|
||||
* 1、使用分块模式,在读写性能底下的手机上,合并文件需要的时间会更加长;
|
||||
* 2、优点是使用多线程的块下载,初始化时,文件初始化时将不会预占用对应长度的空间;
|
||||
* 3、只对新的多线程下载任务有效 4、只对多线程的任务有效
|
||||
*/
|
||||
boolean useBlock = false;
|
||||
boolean useBlock = true;
|
||||
|
||||
public boolean isUseBlock() {
|
||||
return useBlock;
|
||||
|
||||
@@ -76,21 +76,21 @@ public class XMLReader extends DefaultHandler {
|
||||
ALog.w(TAG, "任务队列数不能小于 1");
|
||||
maxTaskNum = 2;
|
||||
}
|
||||
setField("maxTaskNum", maxTaskNum, getAllTaskType());
|
||||
setField("maxTaskNum", maxTaskNum, mType);
|
||||
break;
|
||||
case "reTryNum": //任务重试次数
|
||||
setField("reTryNum", checkInt(value) ? Integer.parseInt(value) : 0, getAllTaskType());
|
||||
setField("reTryNum", checkInt(value) ? Integer.parseInt(value) : 0, mType);
|
||||
break;
|
||||
case "connectTimeOut": // 连接超时时间
|
||||
setField("connectTimeOut", checkInt(value) ? Integer.parseInt(value) : 5 * 1000,
|
||||
getAllTaskType());
|
||||
mType);
|
||||
break;
|
||||
case "iOTimeOut": //io流超时时间
|
||||
int iOTimeOut = checkInt(value) ? Integer.parseInt(value) : 10 * 1000;
|
||||
if (iOTimeOut < 10 * 1000) {
|
||||
iOTimeOut = 10 * 1000;
|
||||
}
|
||||
setField("iOTimeOut", iOTimeOut, getAllTaskType());
|
||||
setField("iOTimeOut", iOTimeOut, mType);
|
||||
break;
|
||||
case "reTryInterval": //失败重试间隔
|
||||
int reTryInterval = checkInt(value) ? Integer.parseInt(value) : 2 * 1000;
|
||||
@@ -98,7 +98,7 @@ public class XMLReader extends DefaultHandler {
|
||||
if (reTryInterval < 2 * 1000) {
|
||||
reTryInterval = 2 * 1000;
|
||||
}
|
||||
setField("reTryInterval", reTryInterval, getAllTaskType());
|
||||
setField("reTryInterval", reTryInterval, mType);
|
||||
break;
|
||||
case "buffSize": //缓冲大小
|
||||
int buffSize = checkInt(value) ? Integer.parseInt(value) : 8192;
|
||||
@@ -107,21 +107,21 @@ public class XMLReader extends DefaultHandler {
|
||||
buffSize = 2048;
|
||||
}
|
||||
|
||||
setField("buffSize", buffSize, getAllTaskType());
|
||||
setField("buffSize", buffSize, mType);
|
||||
break;
|
||||
case "ca": // ca证书
|
||||
String caName = attributes.getValue("name");
|
||||
String caPath = attributes.getValue("path");
|
||||
setField("caName", caName, getAllTaskType());
|
||||
setField("caPath", caPath, getAllTaskType());
|
||||
setField("caName", caName, mType);
|
||||
setField("caPath", caPath, mType);
|
||||
break;
|
||||
case "convertSpeed": // 是否转换速度
|
||||
setField("isConvertSpeed", !checkBoolean(value) || Boolean.parseBoolean(value),
|
||||
getAllTaskType());
|
||||
mType);
|
||||
break;
|
||||
case "maxSpeed": // 最大速度
|
||||
int maxSpeed = checkInt(value) ? Integer.parseInt(value) : 0;
|
||||
setField("maxSpeed", maxSpeed, getAllTaskType());
|
||||
setField("maxSpeed", maxSpeed, mType);
|
||||
break;
|
||||
case "queueMod": // 队列类型
|
||||
String mod = "now";
|
||||
@@ -129,11 +129,11 @@ public class XMLReader extends DefaultHandler {
|
||||
"wait"))) {
|
||||
mod = value;
|
||||
}
|
||||
setField("queueMod", mod, getAllTaskType());
|
||||
setField("queueMod", mod, mType);
|
||||
break;
|
||||
case "updateInterval": // 进度更新时间
|
||||
setField("updateInterval", checkLong(value) ? Long.parseLong(value) : 1000,
|
||||
getAllTaskType());
|
||||
mType);
|
||||
break;
|
||||
|
||||
case "useBlock": // 是否使用分块任务
|
||||
@@ -184,25 +184,15 @@ public class XMLReader extends DefaultHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务类型集合,类型有 {@link ConfigType#DOWNLOAD}、{@link ConfigType#UPLOAD}、{@link ConfigType#D_GROUP}
|
||||
*/
|
||||
private int[] getAllTaskType() {
|
||||
return new int[] {ConfigType.DOWNLOAD, ConfigType.UPLOAD,
|
||||
ConfigType.D_GROUP};
|
||||
}
|
||||
|
||||
private void setField(String key, Object value, int... types) {
|
||||
for (int type : types) {
|
||||
if (type == ConfigType.DOWNLOAD) {
|
||||
setField(DownloadConfig.class, mDownloadConfig, key, value);
|
||||
} else if (type == ConfigType.UPLOAD) {
|
||||
setField(UploadConfig.class, mUploadConfig, key, value);
|
||||
} else if (type == ConfigType.APP) {
|
||||
setField(AppConfig.class, mAppConfig, key, value);
|
||||
} else if (type == ConfigType.D_GROUP) {
|
||||
setField(DGroupConfig.class, mDGroupConfig, key, value);
|
||||
}
|
||||
private void setField(String key, Object value, int type) {
|
||||
if (type == ConfigType.DOWNLOAD) {
|
||||
setField(DownloadConfig.class, mDownloadConfig, key, value);
|
||||
} else if (type == ConfigType.UPLOAD) {
|
||||
setField(UploadConfig.class, mUploadConfig, key, value);
|
||||
} else if (type == ConfigType.APP) {
|
||||
setField(AppConfig.class, mAppConfig, key, value);
|
||||
} else if (type == ConfigType.D_GROUP) {
|
||||
setField(DGroupConfig.class, mDGroupConfig, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,14 @@ import android.os.Handler;
|
||||
|
||||
import com.arialyy.aria.core.common.BaseListener;
|
||||
import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IDownloadListener;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.scheduler.ISchedulers;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 下载监听类
|
||||
|
||||
@@ -21,8 +21,8 @@ import android.os.Looper;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.common.IUtil;
|
||||
import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil;
|
||||
import com.arialyy.aria.core.download.m3u8.M3U8LiveDownloadUtil;
|
||||
import com.arialyy.aria.core.download.m3u8.M3U8VodDownloadUtil;
|
||||
import com.arialyy.aria.core.download.m3u8.M3U8LiveUtil;
|
||||
import com.arialyy.aria.core.download.m3u8.M3U8VodUtil;
|
||||
import com.arialyy.aria.core.inf.AbsNormalTask;
|
||||
import com.arialyy.aria.core.inf.IDownloadListener;
|
||||
import com.arialyy.aria.core.inf.ITaskWrapper;
|
||||
@@ -90,9 +90,9 @@ public class DownloadTask extends AbsNormalTask<DTaskWrapper> {
|
||||
|
||||
@Override protected synchronized IUtil createUtil() {
|
||||
if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) {
|
||||
return new M3U8VodDownloadUtil(mTaskWrapper, (IDownloadListener) mListener);
|
||||
return new M3U8VodUtil(mTaskWrapper, (IDownloadListener) mListener);
|
||||
} else if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) {
|
||||
return new M3U8LiveDownloadUtil(mTaskWrapper, (IDownloadListener) mListener);
|
||||
return new M3U8LiveUtil(mTaskWrapper, (IDownloadListener) mListener);
|
||||
} else {
|
||||
return new SimpleDownloadUtil(mTaskWrapper, (IDownloadListener) mListener);
|
||||
}
|
||||
|
||||
@@ -107,8 +107,4 @@ public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
|
||||
@Override public FtpDirDownloadTarget login(String userName, String password, String account) {
|
||||
return mFtpDelegate.login(userName, password, account);
|
||||
}
|
||||
|
||||
@Override public FtpDirDownloadTarget setProxy(Proxy proxy) {
|
||||
return mFtpDelegate.setProxy(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,11 +144,6 @@ public class FtpDownloadTarget extends AbsDTarget<FtpDownloadTarget>
|
||||
return mFtpDelegate.login(userName, password, account);
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
@Override public FtpDownloadTarget setProxy(Proxy proxy) {
|
||||
return mFtpDelegate.setProxy(proxy);
|
||||
}
|
||||
|
||||
@Override public FtpDownloadTarget updateUrl(String newUrl) {
|
||||
return mConfigHandler.updateUrl(newUrl);
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DTaskWrapper> {
|
||||
|
||||
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
|
||||
super.handleFile(remotePath, ftpFile);
|
||||
if (!CommonUtil.checkSDMemorySpace(mEntity.getDownloadPath(), ftpFile.getSize())) {
|
||||
if (!CommonUtil.checkSDMemorySpace(mEntity.getFilePath(), ftpFile.getSize())) {
|
||||
mCallback.onFail(mEntity, new AriaIOException(TAG,
|
||||
String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getDownloadPath())),
|
||||
String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getFilePath())),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public abstract class BaseM3U8Loader extends AbsFileer<DownloadEntity, DTaskWrap
|
||||
|
||||
BaseM3U8Loader(IEventListener listener, DTaskWrapper wrapper) {
|
||||
super(listener, wrapper);
|
||||
mTempFile = new File(wrapper.getEntity().getFilePath());
|
||||
}
|
||||
|
||||
@Override protected long delayTimer() {
|
||||
|
||||
@@ -26,7 +26,7 @@ public interface ITsMergeHandler {
|
||||
/**
|
||||
* 合并ts文件
|
||||
*
|
||||
* @param keyInfo ts文件加密信息,如果ts文件不是加密的,该字段为空
|
||||
* @param keyInfo 密钥信息,如果ts文件不是加密的,该字段为空
|
||||
* @param tsPath ts文件列表
|
||||
* @return {@code true} 合并成功
|
||||
*/
|
||||
|
||||
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.download.m3u8;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* m3u8加密密钥信息
|
||||
*/
|
||||
public class M3U8KeyInfo {
|
||||
public class M3U8KeyInfo implements Parcelable {
|
||||
|
||||
/**
|
||||
* 加密key保存地址
|
||||
@@ -39,4 +42,36 @@ public class M3U8KeyInfo {
|
||||
* key的iv值
|
||||
*/
|
||||
public String iv;
|
||||
|
||||
@Override public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(this.keyPath);
|
||||
dest.writeString(this.keyUrl);
|
||||
dest.writeString(this.method);
|
||||
dest.writeString(this.iv);
|
||||
}
|
||||
|
||||
public M3U8KeyInfo() {
|
||||
}
|
||||
|
||||
protected M3U8KeyInfo(Parcel in) {
|
||||
this.keyPath = in.readString();
|
||||
this.keyUrl = in.readString();
|
||||
this.method = in.readString();
|
||||
this.iv = in.readString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<M3U8KeyInfo> CREATOR =
|
||||
new Parcelable.Creator<M3U8KeyInfo>() {
|
||||
@Override public M3U8KeyInfo createFromParcel(Parcel source) {
|
||||
return new M3U8KeyInfo(source);
|
||||
}
|
||||
|
||||
@Override public M3U8KeyInfo[] newArray(int size) {
|
||||
return new M3U8KeyInfo[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* 4、对于直播来说是没有停止的,停止就代表完成
|
||||
* 5、不处理直播切片下载失败的状态
|
||||
*/
|
||||
public class M3U8LiveDownloadUtil implements IUtil {
|
||||
public class M3U8LiveUtil implements IUtil {
|
||||
private final String TAG = "M3U8LiveDownloadUtil";
|
||||
private DTaskWrapper mWrapper;
|
||||
private IDownloadListener mListener;
|
||||
@@ -52,7 +52,7 @@ public class M3U8LiveDownloadUtil implements IUtil {
|
||||
private ExecutorService mInfoPool = Executors.newCachedThreadPool();
|
||||
private List<String> mPeerUrls = new ArrayList<>();
|
||||
|
||||
public M3U8LiveDownloadUtil(DTaskWrapper wrapper, IDownloadListener listener) {
|
||||
public M3U8LiveUtil(DTaskWrapper wrapper, IDownloadListener listener) {
|
||||
mWrapper = wrapper;
|
||||
mListener = listener;
|
||||
mLoader = new M3U8LiveLoader(mListener, mWrapper);
|
||||
@@ -104,16 +104,6 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
|
||||
}
|
||||
|
||||
@Override protected void onStop() {
|
||||
super.onStop();
|
||||
//notifyLock();
|
||||
}
|
||||
|
||||
@Override protected void onCancel() {
|
||||
super.onCancel();
|
||||
//notifyLock();
|
||||
}
|
||||
|
||||
private void notifyLock() {
|
||||
try {
|
||||
LOCK.lock();
|
||||
@@ -204,7 +194,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
|
||||
(AbsThreadTask) msg.obj);
|
||||
if (isStop()) {
|
||||
ALog.d(TAG, "任务停止");
|
||||
ALog.d(TAG, String.format("vod任务【%s】停止", mTempFile.getName()));
|
||||
mListener.onStop(mProgress);
|
||||
quitLooper();
|
||||
}
|
||||
@@ -214,7 +204,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
|
||||
(AbsThreadTask) msg.obj);
|
||||
if (isCancel()) {
|
||||
ALog.d(TAG, "任务取消");
|
||||
ALog.d(TAG, String.format("vod任务【%s】取消", mTempFile.getName()));
|
||||
mListener.onCancel();
|
||||
quitLooper();
|
||||
}
|
||||
@@ -222,6 +212,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
case STATE_FAIL:
|
||||
mFailNum++;
|
||||
if (isFail()) {
|
||||
ALog.d(TAG, String.format("vod任务【%s】失败", mTempFile.getName()));
|
||||
Bundle b = msg.getData();
|
||||
mListener.onFail(b.getBoolean(KEY_RETRY, true),
|
||||
(BaseException) b.getSerializable(KEY_ERROR_INFO));
|
||||
@@ -235,7 +226,6 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
handlerPercent();
|
||||
notifyLock();
|
||||
if (isComplete()) {
|
||||
ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum);
|
||||
if (mTaskWrapper.asM3U8().isMergeFile()) {
|
||||
if (mergeFile()) {
|
||||
mListener.onComplete();
|
||||
@@ -274,7 +264,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
|
||||
@Override public boolean isFail() {
|
||||
printInfo("isFail");
|
||||
return mStartThreadNum == mStopNum + mFailNum + mCompleteNum + mCancelNum;
|
||||
return mFailNum == mFlagQueue.size();
|
||||
}
|
||||
|
||||
@Override public boolean isComplete() {
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.util.List;
|
||||
* 3、完成所有分片下载后,合并ts文件
|
||||
* 4、删除该隐藏文件夹
|
||||
*/
|
||||
public class M3U8VodDownloadUtil implements IUtil {
|
||||
public class M3U8VodUtil implements IUtil {
|
||||
private final String TAG = "M3U8DownloadUtil";
|
||||
|
||||
private DTaskWrapper mWrapper;
|
||||
@@ -45,7 +45,7 @@ public class M3U8VodDownloadUtil implements IUtil {
|
||||
private List<String> mUrls = new ArrayList<>();
|
||||
private M3U8VodLoader mLoader;
|
||||
|
||||
public M3U8VodDownloadUtil(DTaskWrapper wrapper, IDownloadListener listener) {
|
||||
public M3U8VodUtil(DTaskWrapper wrapper, IDownloadListener listener) {
|
||||
mWrapper = wrapper;
|
||||
mListener = listener;
|
||||
mLoader = new M3U8VodLoader(mListener, mWrapper);
|
||||
@@ -78,7 +78,7 @@ public abstract class AbsTask<TASK_WRAPPER extends AbsTaskWrapper>
|
||||
ALog.e(TAG, "key 为空");
|
||||
return;
|
||||
} else if (obj == null) {
|
||||
ALog.e(TAG, "扩展数据为空");
|
||||
ALog.w(TAG, "扩展数据为空");
|
||||
return;
|
||||
}
|
||||
mExpand.put(key, obj);
|
||||
|
||||
@@ -1,57 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.inf;
|
||||
|
||||
import android.support.annotation.CheckResult;
|
||||
import java.net.Proxy;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/9.
|
||||
*/
|
||||
public interface IFtpTarget<TARGET extends ITargetHandler> {
|
||||
/**
|
||||
* 设置字符编码
|
||||
*/
|
||||
@CheckResult
|
||||
TARGET charSet(String charSet);
|
||||
|
||||
/**
|
||||
* ftp 用户登录信。
|
||||
*
|
||||
* @param userName ftp用户名
|
||||
* @param password ftp用户密码
|
||||
*/
|
||||
@CheckResult
|
||||
TARGET login(String userName, String password);
|
||||
|
||||
/**
|
||||
* ftp 用户登录信息
|
||||
*
|
||||
* @param userName ftp用户名
|
||||
* @param password ftp用户密码
|
||||
* @param account ftp账号
|
||||
*/
|
||||
@CheckResult
|
||||
TARGET login(String userName, String password, String account);
|
||||
|
||||
/**
|
||||
* 设置代理
|
||||
*
|
||||
* @param proxy {@link Proxy}
|
||||
*/
|
||||
@CheckResult
|
||||
TARGET setProxy(Proxy proxy);
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.inf;
|
||||
|
||||
import android.support.annotation.CheckResult;
|
||||
import java.net.Proxy;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/9.
|
||||
*/
|
||||
public interface IFtpTarget<TARGET extends ITargetHandler> {
|
||||
/**
|
||||
* 设置字符编码
|
||||
*/
|
||||
@CheckResult
|
||||
TARGET charSet(String charSet);
|
||||
|
||||
/**
|
||||
* ftp 用户登录信。
|
||||
*
|
||||
* @param userName ftp用户名
|
||||
* @param password ftp用户密码
|
||||
*/
|
||||
@CheckResult
|
||||
TARGET login(String userName, String password);
|
||||
|
||||
/**
|
||||
* ftp 用户登录信息
|
||||
*
|
||||
* @param userName ftp用户名
|
||||
* @param password ftp用户密码
|
||||
* @param account ftp账号
|
||||
*/
|
||||
@CheckResult
|
||||
TARGET login(String userName, String password, String account);
|
||||
|
||||
///**
|
||||
// * 设置代理
|
||||
// *
|
||||
// * @param proxy {@link Proxy}
|
||||
// */
|
||||
//@CheckResult
|
||||
//TARGET setProxy(Proxy proxy);
|
||||
}
|
||||
|
||||
@@ -92,10 +92,6 @@ public class FtpUploadTarget extends AbsUploadTarget<FtpUploadTarget>
|
||||
return mFtpDelegate.login(userName, password, account);
|
||||
}
|
||||
|
||||
@Override public FtpUploadTarget setProxy(Proxy proxy) {
|
||||
return mFtpDelegate.setProxy(proxy);
|
||||
}
|
||||
|
||||
@Override protected boolean checkEntity() {
|
||||
return mConfigHandler.checkEntity();
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class DBConfig {
|
||||
mapping.put("DownloadGroupEntity", DownloadGroupEntity.class);
|
||||
mapping.put("DownloadEntity", DownloadEntity.class);
|
||||
mapping.put("UploadEntity", UploadEntity.class);
|
||||
mapping.put("TaskRecord", TaskRecord.class);
|
||||
mapping.put("ThreadRecord", ThreadRecord.class);
|
||||
mapping.put("TaskRecord", TaskRecord.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,8 +98,8 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
handle314AriaUpdate(db);
|
||||
} else if (oldVersion < 45) {
|
||||
handle360AriaUpdate(db);
|
||||
} else if (oldVersion < 46) {
|
||||
db.execSQL("UPDATE ThreadRecord SET threadId=0 WHERE threadId=-1");
|
||||
} else if (oldVersion < 48) {
|
||||
handle365Update(db);
|
||||
} else {
|
||||
handleDbUpdate(db, null, null);
|
||||
}
|
||||
@@ -227,12 +227,37 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
} catch (Exception e) {
|
||||
ALog.e(TAG, e);
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除重复的repeat数据
|
||||
*/
|
||||
private void delRepeatThreadRecord(SQLiteDatabase db) {
|
||||
String repeatSql =
|
||||
"DELETE FROM ThreadRecord WHERE (key, threadId, endLocation) "
|
||||
+ "IN (SELECT key, threadId, endLocation FROM ThreadRecord GROUP BY key, threadId, endLocation "
|
||||
+ "HAVING COUNT(*) > 1) AND rowid "
|
||||
+ "NOT IN (SELECT MIN(rowid) FROM ThreadRecord GROUP BY key, threadId, endLocation "
|
||||
+ "HAVING COUNT(*)> 1)";
|
||||
ALog.d(TAG, repeatSql);
|
||||
db.execSQL(repeatSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理365版本以下的升级
|
||||
*/
|
||||
private void handle365Update(SQLiteDatabase db) {
|
||||
db.execSQL("UPDATE ThreadRecord SET threadId=0 WHERE threadId=-1");
|
||||
|
||||
// 执行升级操作
|
||||
handleDbUpdate(db, null, null);
|
||||
delRepeatThreadRecord(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理3.6以下版本的数据库升级
|
||||
*/
|
||||
@@ -255,7 +280,10 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
Map<String, String> dGroupNameModify = new HashMap<>();
|
||||
dGroupNameModify.put("dGroupName", "dGroupHash");
|
||||
columnMap.put("TaskRecord", dGroupNameModify);
|
||||
|
||||
// 执行升级操作
|
||||
handleDbUpdate(db, columnMap, null);
|
||||
delRepeatThreadRecord(db);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,9 +20,11 @@ package com.arialyy.aria.util;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Build;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.Aria;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
|
||||
/**
|
||||
* 跟网络相关的工具类
|
||||
@@ -52,12 +54,16 @@ public class NetUtils {
|
||||
|
||||
/**
|
||||
* 判断网络是否连接
|
||||
*
|
||||
* @return {@code true} 网络已连接、{@code false}网络未连接
|
||||
*/
|
||||
public static boolean isConnected(Context context) {
|
||||
if (!Aria.get(context).getAppConfig().isNetCheck()){
|
||||
if (!Aria.get(context).getAppConfig().isNetCheck()) {
|
||||
return true;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
return AriaManager.getInstance(context).isConnectedNet();
|
||||
}
|
||||
ConnectivityManager cm =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo ni = cm.getActiveNetworkInfo();
|
||||
|
||||
@@ -182,6 +182,9 @@ public class RecordUtil {
|
||||
if (TextUtils.isEmpty(filePath)) {
|
||||
throw new NullPointerException("删除记录失败,文件路径为空");
|
||||
}
|
||||
if (!filePath.startsWith("/")) {
|
||||
throw new IllegalArgumentException(String.format("文件路径错误,filePath:%s", filePath));
|
||||
}
|
||||
if (type != RecordHandler.TYPE_DOWNLOAD && type != RecordHandler.TYPE_UPLOAD) {
|
||||
throw new IllegalArgumentException("任务记录类型错误");
|
||||
}
|
||||
@@ -210,7 +213,8 @@ public class RecordUtil {
|
||||
if (record.taskType == TaskRecord.TYPE_M3U8_VOD) { // 删除ts分片文件
|
||||
String cacheDir = null;
|
||||
if (!targetFile.isDirectory()) {
|
||||
cacheDir = targetFile.getParent() + "/." + targetFile.getName();
|
||||
cacheDir = String.format("%s/.%s_%s", targetFile.getParent(), targetFile.getName(),
|
||||
record.bandWidth);
|
||||
}
|
||||
removeTsCache(record, cacheDir);
|
||||
} else if (record.isBlock) { // 删除分块文件
|
||||
@@ -235,6 +239,7 @@ public class RecordUtil {
|
||||
}
|
||||
|
||||
private static void removeRecord(String filePath) {
|
||||
ALog.i(TAG, "删除任务记录");
|
||||
DbEntity.deleteData(ThreadRecord.class, "key=?", filePath);
|
||||
DbEntity.deleteData(TaskRecord.class, "filePath=?", filePath);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
- 修复拦截器可能出现的空指针问题
|
||||
- 移除`DownloadGroupEntity`字段`groupHash`的主键约束,`DownloadEntity`字段`groupHash`的外键约束,`TaskRecord`字段`dGroupHash`的外键约束
|
||||
- 优化关联查询的性能
|
||||
- 修复任务记录删除失败的问题
|
||||
- 优化网络连接状态获取的逻辑
|
||||
- 修复配置文件的某些配置失效的问题
|
||||
+ v_3.6.4 (2019/5/16)
|
||||
- 优化任务接收器的代码结构
|
||||
- 修复`DbEntity.saveAll()`失败的问题
|
||||
|
||||
@@ -50,8 +50,8 @@ dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:${rootProject.ext.kotlin_version}"
|
||||
api project(':Aria')
|
||||
kapt project(':AriaCompiler')
|
||||
// api 'com.arialyy.aria:aria-core:3.6.5_dev_4'
|
||||
// kapt 'com.arialyy.aria:aria-compiler:3.6.5_dev_4'
|
||||
// api 'com.arialyy.aria:aria-core:3.6.4'
|
||||
// kapt 'com.arialyy.aria:aria-compiler:3.6.4'
|
||||
|
||||
// compile 'com.arialyy.aria:aria-core:3.3.14'
|
||||
// annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.14'
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
<!--设置Aria的日志级别,{@link ALog#LOG_LEVEL_VERBOSE}-->
|
||||
<logLevel value="2"/>
|
||||
<!-- 是否检查网络 true: 检查网络,false: 不检查网络-->
|
||||
<netCheck value="false"/>
|
||||
<netCheck value="true"/>
|
||||
<!--除非无法使用注解,否则不建议使用广播来接受任务状态,true:使用广播接收任务状态,false:不适用广播接收状态 -->
|
||||
<!-- http://aria.laoyuyu.me/aria_doc/api/use_broadcast.html -->
|
||||
<useBroadcast value="true"/>
|
||||
<!--断网的时候是否重试,true:断网也重试;false:断网不重试,直接走失败的回调-->
|
||||
<notNetRetry value="true"/>
|
||||
<notNetRetry value="false"/>
|
||||
</app>
|
||||
|
||||
|
||||
|
||||
@@ -34,9 +34,10 @@ public class HttpDownloadModule extends BaseViewModule {
|
||||
|
||||
private final String defUrl =
|
||||
"http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk";
|
||||
//"http://202.98.201.103:7000/vrs/TPK/ZTC440402001Z.tpk";
|
||||
private final String defFilePath =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()
|
||||
+ "/test.apk";
|
||||
+ "/ZTC440402001Z.tpk";
|
||||
|
||||
private MutableLiveData<DownloadEntity> liveData = new MutableLiveData<>();
|
||||
private DownloadEntity singDownloadInfo;
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
@@ -310,6 +311,10 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
||||
//Aria.download(this).unRegister();
|
||||
}
|
||||
|
||||
@Override public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override protected void dataCallback(int result, Object data) {
|
||||
super.dataCallback(result, data);
|
||||
if (result == ModifyUrlDialog.MODIFY_URL_DIALOG_RESULT) {
|
||||
|
||||
@@ -31,7 +31,9 @@ import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTarget;
|
||||
import com.arialyy.aria.core.download.DownloadTask;
|
||||
import com.arialyy.aria.core.download.m3u8.IBandWidthUrlConverter;
|
||||
import com.arialyy.aria.core.download.m3u8.ITsMergeHandler;
|
||||
import com.arialyy.aria.core.download.m3u8.IVodTsUrlConverter;
|
||||
import com.arialyy.aria.core.download.m3u8.M3U8KeyInfo;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
@@ -201,6 +203,8 @@ public class M3U8VodDownloadActivity extends BaseActivity<ActivityM3u8VodBinding
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
getBinding().setStateStr(getString(R.string.start));
|
||||
getBinding().setSpeed("");
|
||||
Log.d(TAG, "fail");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,6 +265,11 @@ public class M3U8VodDownloadActivity extends BaseActivity<ActivityM3u8VodBinding
|
||||
return newUrls;
|
||||
}
|
||||
})
|
||||
.setMergeHandler(new ITsMergeHandler() {
|
||||
@Override public boolean merge(@Nullable M3U8KeyInfo keyInfo, List<String> tsPath) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.arialyy.aria.core.upload.uploader.SimpleUploadUtil;
|
||||
/**
|
||||
* Created by lyy on 2017/2/23. 上传任务
|
||||
*/
|
||||
public class UploadTask extends AbsNormalTask<UploadEntity, UTaskWrapper> {
|
||||
public class UploadTask extends AbsNormalTask<UTaskWrapper> {
|
||||
|
||||
private UploadTask(UTaskWrapper taskWrapper, Handler outHandler) {
|
||||
mTaskWrapper = taskWrapper;
|
||||
|
||||
@@ -43,7 +43,7 @@ task clean(type: Delete) {
|
||||
ext {
|
||||
userOrg = 'arialyy'
|
||||
groupId = 'com.arialyy.aria'
|
||||
publishVersion = '3.6.5_dev_4'
|
||||
publishVersion = '3.6.5_beta_1'
|
||||
// publishVersion = '1.0.4' //FTP插件
|
||||
repoName='maven'
|
||||
desc = 'android 下载框架'
|
||||
|
||||
Reference in New Issue
Block a user