fix bug https://github.com/AriaLyy/Aria/issues/542
fix bug https://github.com/AriaLyy/Aria/issues/547
修复下载失败时,中断重试无效的问题
增加忽略权限检查的api,`ignoreCheckPermissions()`
This commit is contained in:
laoyuyu
2019-12-02 19:31:39 +08:00
parent 91daecd039
commit 669aa6981c
38 changed files with 294 additions and 241 deletions

View File

@@ -23,6 +23,8 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import com.arialyy.aria.core.config.AppConfig;
import com.arialyy.aria.core.config.Configuration;
import com.arialyy.aria.core.config.DGroupConfig;
@@ -56,6 +58,7 @@ public class AriaConfig {
* 是否已经联网true 已经联网
*/
private static boolean isConnectedNet = true;
private Handler mAriaHandler;
private AriaConfig(Context context) {
APP = context.getApplicationContext();
@@ -105,6 +108,13 @@ public class AriaConfig {
return mDGConfig;
}
public synchronized Handler getAriaHandler() {
if (mAriaHandler == null) {
mAriaHandler = new Handler(Looper.getMainLooper());
}
return mAriaHandler;
}
/**
* 注册网络监听,只有配置了检查网络{@link AppConfig#isNetCheck()}才会注册事件
*/

View File

@@ -1,55 +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.listener;
import com.arialyy.aria.exception.BaseException;
/**
* Created by lyy on 2017/2/23.
*/
class UploadListener implements IUploadListener {
@Override public void onPre() {
}
@Override public void onStart(long startLocation) {
}
@Override public void onResume(long resumeLocation) {
}
@Override public void onStop(long stopLocation) {
}
@Override public void onProgress(long currentLocation) {
}
@Override public void onCancel() {
}
@Override public void onComplete() {
}
@Override public void onFail(boolean needRetry, BaseException e) {
}
}

View File

@@ -84,7 +84,7 @@ public class ThreadStateManager implements IThreadState {
mFailNum++;
if (isFail()) {
Bundle b = msg.getData();
mListener.onFail(b.getBoolean(KEY_RETRY, true),
mListener.onFail(b.getBoolean(KEY_RETRY, false),
(BaseException) b.getSerializable(KEY_ERROR_INFO));
quitLooper();
}

View File

@@ -353,7 +353,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
} else {
ALog.e(TAG, String.format("任务【%s】执行失败", getFileName()));
ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
sendFailMsg(null);
sendFailMsg(null, needRetry);
}
}
}
@@ -365,7 +365,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
boolean isConnected = NetUtils.isConnected(AriaConfig.getInstance().getAPP());
if (!isConnected && !isNotNetRetry) {
ALog.w(TAG, String.format("ts切片【%s】重试失败网络未连接", getFileName()));
sendFailMsg(null);
sendFailMsg(null, false);
return;
}
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(
@@ -377,7 +377,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
FileUtil.createFile(mConfig.tempFile);
ThreadTaskManager.getInstance().retryThread(this);
} else {
sendFailMsg(null);
sendFailMsg(null, needRetry);
}
}
@@ -389,7 +389,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
private void retryBlockTask(boolean needRetry) {
if (!NetUtils.isConnected(AriaConfig.getInstance().getAPP()) && !isNotNetRetry) {
ALog.w(TAG, String.format("分块【%s】重试失败网络未连接", getFileName()));
sendFailMsg(null);
sendFailMsg(null, false);
return;
}
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(
@@ -400,7 +400,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
handleBlockRecord();
ThreadTaskManager.getInstance().retryThread(this);
} else {
sendFailMsg(null);
sendFailMsg(null, needRetry);
}
}
@@ -448,13 +448,14 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
/**
* 发送失败信息
*/
private void sendFailMsg(@Nullable BaseException e) {
private void sendFailMsg(@Nullable BaseException e,boolean needRetry) {
Bundle b = new Bundle();
b.putBoolean(IThreadState.KEY_RETRY, needRetry);
if (e != null) {
Bundle b = new Bundle();
b.putSerializable(IThreadState.KEY_ERROR_INFO, e);
updateState(IThreadState.STATE_FAIL, b);
} else {
updateState(IThreadState.STATE_FAIL, null);
updateState(IThreadState.STATE_FAIL, b);
}
}

View File

@@ -32,7 +32,7 @@ import java.util.Map;
class DBConfig {
/*adb pull /mnt/sdcard/Android/data/com.arialyy.simple/files/DB/AriaLyyDb d:/db*/
static boolean DEBUG = false;
static Map<String, Class> mapping = new LinkedHashMap<>();
static Map<String, Class<? extends DbEntity>> mapping = new LinkedHashMap<>();
static String DB_NAME;
static int VERSION = 56;
@@ -51,8 +51,8 @@ class DBConfig {
}
static {
mapping.put("DownloadGroupEntity", DownloadGroupEntity.class);
mapping.put("DownloadEntity", DownloadEntity.class);
mapping.put("DownloadGroupEntity", DownloadGroupEntity.class);
mapping.put("UploadEntity", UploadEntity.class);
mapping.put("ThreadRecord", ThreadRecord.class);
mapping.put("TaskRecord", TaskRecord.class);

View File

@@ -221,4 +221,22 @@ class DelegateCommon extends AbsDelegate {
db.execSQL(str);
}
}
/**
* 通过class 获取该class的表字段
*
* @return 表字段列表
*/
List<String> getColumns(Class<? extends DbEntity> clazz) {
List<String> columns = new ArrayList<>();
List<Field> fields = CommonUtil.getAllFields(clazz);
for (Field field : fields) {
field.setAccessible(true);
if (SqlUtil.isIgnore(field)) {
continue;
}
columns.add(field.getName());
}
return columns;
}
}

View File

@@ -100,14 +100,14 @@ final class SqlHelper extends SQLiteOpenHelper {
} else if (oldVersion < 53) {
handle366Update(db);
} else {
handleDbUpdate(db, null, null);
handleDbUpdate(db, null);
}
}
}
@Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion > newVersion) {
handleDbUpdate(db, null, null);
handleDbUpdate(db, null);
}
}
@@ -145,10 +145,8 @@ final class SqlHelper extends SQLiteOpenHelper {
*
* @param modifyColumns 需要修改的表字段的映射key为表名
* value{@code Map<String, String>}中的Map的key为老字段名称value为该老字段对应的新字段名称
* @param delColumns 需要删除的表字段key为表名value{@code List<String>}为需要删除的字段列表
*/
private void handleDbUpdate(SQLiteDatabase db, Map<String, Map<String, String>> modifyColumns,
Map<String, List<String>> delColumns) {
private void handleDbUpdate(SQLiteDatabase db, Map<String, Map<String, String>> modifyColumns) {
if (db == null) {
ALog.e("SqlHelper", "db 为 null");
return;
@@ -161,7 +159,7 @@ final class SqlHelper extends SQLiteOpenHelper {
db.beginTransaction();
Set<String> tables = DBConfig.mapping.keySet();
for (String tableName : tables) {
Class clazz = DBConfig.mapping.get(tableName);
Class<? extends DbEntity> clazz = DBConfig.mapping.get(tableName);
if (mDelegate.tableExists(db, clazz)) {
//修改表名为中介表名
String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName);
@@ -178,46 +176,57 @@ final class SqlHelper extends SQLiteOpenHelper {
// 复制数据
if (count > 0) {
// 获取旧表的所有字段名称
Cursor columnC =
db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null);
StringBuilder params = new StringBuilder();
// 获取新表的所有字段名称
List<String> newTabColumns = mDelegate.getColumns(clazz);
// 获取旧表的所有字段名称
List<String> oldTabColumns = new ArrayList<>();
while (columnC.moveToNext()) {
String columnName = columnC.getString(columnC.getColumnIndex("name"));
if (delColumns != null && delColumns.get(tableName) != null) {
List<String> delColumn = delColumns.get(tableName);
if (delColumn != null && !delColumn.isEmpty()) {
if (delColumn.contains(columnName)) {
continue;
}
}
}
params.append(columnName).append(",");
oldTabColumns.add(columnName);
}
columnC.close();
// 旧表需要删除的字段,删除旧表有而新表没的字段
List<String> diffTab = getDiffColumn(newTabColumns, oldTabColumns);
StringBuilder params = new StringBuilder();
// 需要修改的列名映射表
Map<String, String> modifyMap = null;
if (modifyColumns != null) {
modifyMap = modifyColumns.get(tableName);
}
for (String column : oldTabColumns) {
if (!diffTab.isEmpty() && diffTab.contains(column)
&& (modifyMap != null && !modifyMap.containsKey(column))) { // 如果旧表字段有修改,忽略这个删除
continue;
}
params.append(column).append(",");
}
String oldParamStr = params.toString();
oldParamStr = oldParamStr.substring(0, oldParamStr.length() - 1);
String newParamStr = oldParamStr;
// 处理字段名称改变
if (modifyColumns != null) {
Map<String, String> columnMap = modifyColumns.get(tableName);
if (columnMap != null && !columnMap.isEmpty()) {
Set<String> keys = columnMap.keySet();
for (String key : keys) {
if (newParamStr.contains(key)) {
newParamStr = newParamStr.replace(key, columnMap.get(key));
}
if (modifyMap != null && !modifyMap.isEmpty()) {
Set<String> keys = modifyMap.keySet();
for (String key : keys) {
if (newParamStr.contains(key)) {
newParamStr = newParamStr.replace(key, modifyMap.get(key));
}
}
}
//恢复数据
String insertSql =
String.format("INSERT INTO %s (%s) SELECT %s FROM %s_temp", tableName, newParamStr,
oldParamStr, tableName);
ALog.d(TAG, "insertSql = " + insertSql);
db.execSQL(insertSql);
}
//删除中介表
@@ -234,6 +243,19 @@ final class SqlHelper extends SQLiteOpenHelper {
}
}
/**
* 取新表差值(需要删除的字段):旧表有而新表没的字段
*
* @param newTab 新表字段
* @param oldTab 旧表字段
* @return 旧表有而新表没的字段
*/
private List<String> getDiffColumn(List<String> newTab, List<String> oldTab) {
List<String> temp = new ArrayList<>(oldTab); // 拷贝旧表字段
temp.removeAll(newTab);
return temp;
}
/**
* 删除重复的repeat数据
*/
@@ -256,7 +278,7 @@ final class SqlHelper extends SQLiteOpenHelper {
modifyMap.put("ThreadRecord", threadRecordModify);
// 执行升级操作
handleDbUpdate(db, modifyMap, null);
handleDbUpdate(db, modifyMap);
delRepeatThreadRecord(db);
}
@@ -273,7 +295,7 @@ final class SqlHelper extends SQLiteOpenHelper {
modifyMap.put("ThreadRecord", threadRecordModify);
// 执行升级操作
handleDbUpdate(db, modifyMap, null);
handleDbUpdate(db, modifyMap);
delRepeatThreadRecord(db);
}
@@ -307,7 +329,7 @@ final class SqlHelper extends SQLiteOpenHelper {
modifyMap.put("ThreadRecord", threadRecordModify);
// 执行升级操作
handleDbUpdate(db, modifyMap, null);
handleDbUpdate(db, modifyMap);
delRepeatThreadRecord(db);
}
@@ -360,15 +382,6 @@ final class SqlHelper extends SQLiteOpenHelper {
dGEntityModifyMap.put("groupName", "groupHash");
modifyMap.put("DownloadGroupEntity", dGEntityModifyMap);
// 删除字段
Map<String, List<String>> delColumnMap = new HashMap<>();
List<String> dEntityDel = new ArrayList<>();
dEntityDel.add("taskKey");
delColumnMap.put("DownloadEntity", dEntityDel);
List<String> dgEntityDel = new ArrayList<>();
dgEntityDel.add("subtask");
delColumnMap.put("DownloadGroupEntity", dgEntityDel);
handleDbUpdate(db, modifyMap, delColumnMap);
handleDbUpdate(db, modifyMap);
}
}

View File

@@ -62,7 +62,7 @@ public class CheckUtil {
public static boolean checkUploadPathConflicts(boolean isForceUpload, String filePath) {
if (DbEntity.checkDataExist(UploadEntity.class, "filePath=?", filePath)) {
if (!isForceUpload) {
ALog.e(TAG, String.format("上传失败,文件路径【%s】已经被其它任务占用请设置其它保存路径", filePath));
ALog.e(TAG, String.format("上传失败,文件路径【%s】已经被其它任务占用请设置其它文件路径", filePath));
return false;
} else {
ALog.w(TAG, String.format("文件路径【%s】已经被其它任务占用当前任务将覆盖该路径的文件", filePath));

View File

@@ -38,6 +38,8 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.SequenceInputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
@@ -61,6 +63,21 @@ public class FileUtil {
private static final String EXTERNAL_STORAGE_PATH =
Environment.getExternalStorageDirectory().getPath();
/**
* 获取m3u8 ts文件的缓存目录。
* 缓存文件夹格式:父文件夹/.文件名_码率
*
* @param path m3u8 文件下载路径
* @return m3u8 ts文件的缓存目录
*/
public static String getTsCacheDir(String path, int bandWidth) {
if (TextUtils.isEmpty(path)) {
throw new NullPointerException("m3u8文保存路径为空");
}
File file = new File(path);
return String.format("%s/.%s_%s", file.getParent(), file.getName(), bandWidth);
}
/**
* 创建目录 当目录不存在的时候创建文件否则返回false
*/
@@ -409,9 +426,19 @@ public class FileUtil {
* 获取SD卡目录列表
*/
public static List<String> getSDPathList(Context context) {
List<String> paths;
List<String> paths = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
paths = getVolumeList(context);
try {
paths = getVolumeList(context);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
List<String> mounts = readMountsFile();
List<String> volds = readVoldFile();
@@ -471,16 +498,26 @@ public class FileUtil {
/**
* getSDPathList
*/
private static List<String> getVolumeList(final Context context) {
private static List<String> getVolumeList(final Context context)
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
IllegalAccessException {
List<String> pathList = new ArrayList<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
StorageManager manager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
List<StorageVolume> volumes = manager.getStorageVolumes();
Class<?> volumeClass = StorageVolume.class;
Method getPath = volumeClass.getDeclaredMethod("getPath");
//Method isRemovable = volumeClass.getDeclaredMethod("isRemovable");
getPath.setAccessible(true);
//isRemovable.setAccessible(true);
for (StorageVolume volume : volumes) {
String state = volume.getState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
pathList.add(volume.toString());
pathList.add((String) getPath.invoke(volume));
}
}
} else {