laoyuyu 6 years ago
parent 6d06458df7
commit ce43e48097
  1. 19
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/AbsFtpInfoThread.java
  2. 4
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/AbsFtpThreadTask.java
  3. 12
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/FtpInterceptHandler.java
  4. 13
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/FtpTaskDelegate.java
  5. 13
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  6. 21
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
  7. 30
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  8. 13
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  9. 1
      DEV_LOG.md
  10. 14
      app/src/main/AndroidManifest.xml
  11. 64
      app/src/main/java/com/arialyy/simple/common/ModifyUrlDialog.java
  12. 2
      app/src/main/java/com/arialyy/simple/core/download/FtpDownloadActivity.java
  13. 94
      app/src/main/java/com/arialyy/simple/core/upload/FtpUploadActivity.java
  14. 84
      app/src/main/java/com/arialyy/simple/widget/SvgTextView.java
  15. 6
      app/src/main/res/drawable/ic_choose_file.xml
  16. 9
      app/src/main/res/drawable/ic_modify.xml
  17. 41
      app/src/main/res/layout/activity_ftp_upload.xml
  18. 77
      app/src/main/res/layout/dialog_modify_url.xml
  19. 107
      app/src/main/res/layout/layout_content_single.xml
  20. 29
      app/src/main/res/layout/layout_svg_text.xml
  21. 21
      app/src/main/res/values/attr.xml
  22. 14
      app/src/main/res/values/strings.xml
  23. 25
      app/src/main/res/xml/aria_fileprovider_paths.xml

@ -37,6 +37,7 @@ import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.FileNotFoundException; import com.arialyy.aria.exception.FileNotFoundException;
import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.Regular; import com.arialyy.aria.util.Regular;
import com.arialyy.aria.util.SSLContextUtil; import com.arialyy.aria.util.SSLContextUtil;
@ -96,8 +97,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
ALog.e(TAG, String.format("任务【%s】失败", mTaskDelegate.getUrlEntity().url)); ALog.e(TAG, String.format("任务【%s】失败", mTaskDelegate.getUrlEntity().url));
return; return;
} }
String remotePath = String remotePath = CommonUtil.convertFtpChar(charSet, getRemotePath());
new String(getRemotePath().getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
if (mTaskDelegate.getUrlEntity().isFtps) { if (mTaskDelegate.getUrlEntity().isFtps) {
((FTPSClient) client).execPROT("P"); ((FTPSClient) client).execPROT("P");
//((FTPSClient) client).enterLocalActiveMode(); //((FTPSClient) client).enterLocalActiveMode();
@ -123,7 +123,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
} else { } else {
ALog.w(TAG, String.format("获取文件列表失败,msg:%s", client.getReplyString())); ALog.w(TAG, String.format("获取文件列表失败,msg:%s", client.getReplyString()));
} }
client.disconnect(); closeClient(client);
failDownload(new FileNotFoundException(TAG, failDownload(new FileNotFoundException(TAG,
String.format("文件不存在,url: %s, remotePath:%s", mTaskDelegate.getUrlEntity().url, String.format("文件不存在,url: %s, remotePath:%s", mTaskDelegate.getUrlEntity().url,
@ -133,8 +133,8 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
// 处理拦截功能 // 处理拦截功能
if (!onInterceptor(client, files)) { if (!onInterceptor(client, files)) {
client.disconnect(); closeClient(client);
failDownload(new AriaIOException(TAG, "拦截器处理任务失败"), false); ALog.d(TAG, "拦截器处理完成任务,任务将不再执行");
return; return;
} }
@ -146,7 +146,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
//服务器上没有该文件路径,表示该任务为新的上传任务 //服务器上没有该文件路径,表示该任务为新的上传任务
mTaskWrapper.setNewTask(true); mTaskWrapper.setNewTask(true);
} else { } else {
client.disconnect(); closeClient(client);
failDownload(new AriaIOException(TAG, failDownload(new AriaIOException(TAG,
String.format("获取文件信息错误,url: %s, errorCode:%s, errorMsg:%s", String.format("获取文件信息错误,url: %s, errorCode:%s, errorMsg:%s",
mTaskDelegate.getUrlEntity().url, reply, client.getReplyString())), true); mTaskDelegate.getUrlEntity().url, reply, client.getReplyString())), true);
@ -172,7 +172,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
* 处理拦截 * 处理拦截
* *
* @param ftpFiles remotePath路径下的所有文件 * @param ftpFiles remotePath路径下的所有文件
* @return {@code false} 拦截器处理任务失败{@code} 拦截器处理任务成功 * @return {@code false} 拦截器处理完成任务任务将不再执行{@code true} 拦截器处理任务完成任务任务继续执行
*/ */
protected boolean onInterceptor(FTPClient client, FTPFile[] ftpFiles) { protected boolean onInterceptor(FTPClient client, FTPFile[] ftpFiles) {
return true; return true;
@ -293,7 +293,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
return client; return client;
} }
private void closeClient(FTPClient client) { protected void closeClient(FTPClient client) {
try { try {
if (client != null && client.isConnected()) { if (client != null && client.isConnected()) {
client.disconnect(); client.disconnect();
@ -372,8 +372,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
ALog.d(TAG, "isValid = " + file.isValid()); ALog.d(TAG, "isValid = " + file.isValid());
handleFile(path + file.getName(), file); handleFile(path + file.getName(), file);
} else { } else {
String remotePath = String remotePath = CommonUtil.convertFtpChar(charSet, path + file.getName());
new String((path + file.getName()).getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
size += getFileSize(client.listFiles(remotePath), client, path + file.getName()); size += getFileSize(client.listFiles(remotePath), client, path + file.getName());
} }
} }

@ -42,10 +42,6 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
extends AbsThreadTask<ENTITY, TASK_ENTITY> { extends AbsThreadTask<ENTITY, TASK_ENTITY> {
private final String TAG = "AbsFtpThreadTask"; private final String TAG = "AbsFtpThreadTask";
protected String charSet; protected String charSet;
/**
* D_FTP 服务器编码
*/
public static String SERVER_CHARSET = "ISO-8859-1";
protected AbsFtpThreadTask(StateConstance constance, IEventListener listener, protected AbsFtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<TASK_ENTITY> info) { SubThreadConfig<TASK_ENTITY> info) {

@ -18,7 +18,7 @@ package com.arialyy.aria.core.common.ftp;
import android.text.TextUtils; import android.text.TextUtils;
/** /**
* Ftp上传拦截器处理 * Ftp上传拦截器处理只针对新任务有效
* *
* 如果使用者同时实现{@link Builder#resetFileName(String)}{@link Builder#coverServerFile} * 如果使用者同时实现{@link Builder#resetFileName(String)}{@link Builder#coverServerFile}
* 将默认使用{@link Builder#coverServerFile} * 将默认使用{@link Builder#coverServerFile}
@ -29,8 +29,6 @@ public class FtpInterceptHandler {
private String newFileName; private String newFileName;
private boolean stopUpload;
private FtpInterceptHandler() { private FtpInterceptHandler() {
} }
@ -42,10 +40,6 @@ public class FtpInterceptHandler {
return newFileName; return newFileName;
} }
public boolean isStopUpload() {
return stopUpload;
}
public static final class Builder { public static final class Builder {
private boolean coverServerFile = false; private boolean coverServerFile = false;
@ -87,9 +81,7 @@ public class FtpInterceptHandler {
*/ */
public FtpInterceptHandler build() { public FtpInterceptHandler build() {
FtpInterceptHandler handler = new FtpInterceptHandler(); FtpInterceptHandler handler = new FtpInterceptHandler();
if (stopUpload) { if (coverServerFile) {
handler.stopUpload = true;
} else if (coverServerFile) {
handler.coverServerFile = true; handler.coverServerFile = true;
} else if (!TextUtils.isEmpty(newFileName)) { } else if (!TextUtils.isEmpty(newFileName)) {
handler.newFileName = newFileName; handler.newFileName = newFileName;

@ -41,6 +41,19 @@ public class FtpTaskDelegate implements ITargetHeadDelegate {
*/ */
private IFtpUploadInterceptor uploadInterceptor; private IFtpUploadInterceptor uploadInterceptor;
/**
* 上传到服务器文件的新文件名{@link FtpInterceptHandler#getNewFileName()}
*/
private String newFileName;
public String getNewFileName() {
return newFileName;
}
public void setNewFileName(String newFileName) {
this.newFileName = newFileName;
}
public IFtpUploadInterceptor getUploadInterceptor() { public IFtpUploadInterceptor getUploadInterceptor() {
return uploadInterceptor; return uploadInterceptor;
} }

@ -29,6 +29,7 @@ import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -84,8 +85,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
return this; return this;
} }
String remotePath = String remotePath =
new String(getTaskWrapper().asFtp().getUrlEntity().remotePath.getBytes(charSet), CommonUtil.convertFtpChar(charSet, getTaskWrapper().asFtp().getUrlEntity().remotePath);
SERVER_CHARSET);
ALog.i(TAG, String.format("remotePath【%s】", remotePath)); ALog.i(TAG, String.format("remotePath【%s】", remotePath));
is = client.retrieveFileStream(remotePath); is = client.retrieveFileStream(remotePath);
reply = client.getReplyCode(); reply = client.getReplyCode();
@ -135,7 +135,8 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
return; return;
} }
ALog.i(TAG, ALog.i(TAG,
String.format("任务【%s】线程__%s__下载完毕", getConfig().TEMP_FILE.getName(), getConfig().THREAD_ID)); String.format("任务【%s】线程__%s__下载完毕", getConfig().TEMP_FILE.getName(),
getConfig().THREAD_ID));
writeConfig(true, getConfig().END_LOCATION); writeConfig(true, getConfig().END_LOCATION);
getState().COMPLETE_THREAD_NUM++; getState().COMPLETE_THREAD_NUM++;
if (getState().isComplete()) { if (getState().isComplete()) {
@ -143,7 +144,8 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
boolean success = mergeFile(); boolean success = mergeFile();
if (!success) { if (!success) {
mListener.onFail(false, mListener.onFail(false,
new TaskException(TAG, String.format("任务【%s】分块文件合并失败", getConfig().TEMP_FILE.getName()))); new TaskException(TAG,
String.format("任务【%s】分块文件合并失败", getConfig().TEMP_FILE.getName())));
return; return;
} }
} }
@ -216,7 +218,8 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
private void readNormal(InputStream is) { private void readNormal(InputStream is) {
BufferedRandomAccessFile file = null; BufferedRandomAccessFile file = null;
try { try {
file = new BufferedRandomAccessFile(getConfig().TEMP_FILE, "rwd", getTaskConfig().getBuffSize()); file =
new BufferedRandomAccessFile(getConfig().TEMP_FILE, "rwd", getTaskConfig().getBuffSize());
file.seek(getConfig().START_LOCATION); file.seek(getConfig().START_LOCATION);
byte[] buffer = new byte[getTaskConfig().getBuffSize()]; byte[] buffer = new byte[getTaskConfig().getBuffSize()];
int len; int len;

@ -23,13 +23,12 @@ import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.common.TaskRecord; import com.arialyy.aria.core.common.TaskRecord;
import com.arialyy.aria.core.common.ThreadRecord; import com.arialyy.aria.core.common.ThreadRecord;
import com.arialyy.aria.core.common.ftp.AbsFtpThreadTask;
import com.arialyy.aria.core.common.ftp.FtpInterceptHandler; import com.arialyy.aria.core.common.ftp.FtpInterceptHandler;
import com.arialyy.aria.core.common.ftp.IFtpUploadInterceptor; import com.arialyy.aria.core.common.ftp.IFtpUploadInterceptor;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UTaskWrapper; import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.DbDataHelper; import com.arialyy.aria.util.DbDataHelper;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -59,6 +58,10 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UTaskWrapper> {
} }
@Override protected boolean onInterceptor(FTPClient client, FTPFile[] ftpFiles) { @Override protected boolean onInterceptor(FTPClient client, FTPFile[] ftpFiles) {
// 旧任务将不做处理,否则断点续传上传将失效
if (!mTaskWrapper.isNewTask()) {
return true;
}
try { try {
IFtpUploadInterceptor interceptor = mTaskWrapper.asFtp().getUploadInterceptor(); IFtpUploadInterceptor interceptor = mTaskWrapper.asFtp().getUploadInterceptor();
if (interceptor != null) { if (interceptor != null) {
@ -73,30 +76,26 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UTaskWrapper> {
FtpInterceptHandler interceptHandler = interceptor.onIntercept(mEntity, files); FtpInterceptHandler interceptHandler = interceptor.onIntercept(mEntity, files);
if (interceptHandler.isStopUpload()) {
// TODO: 2019-05-22 操作任务停止
return true;
}
/* /*
处理远端有同名文件的情况 处理远端有同名文件的情况
*/ */
if (files.contains(mEntity.getFileName())) { if (files.contains(mEntity.getFileName())) {
if (interceptHandler.isCoverServerFile()) { if (interceptHandler.isCoverServerFile()) {
ALog.i(TAG, String.format("远端已拥有同名文件,将覆盖该文件,文件名:%s", mEntity.getFileName())); ALog.i(TAG, String.format("远端已拥有同名文件,将覆盖该文件,文件名:%s", mEntity.getFileName()));
boolean b = client.deleteFile( boolean b = client.deleteFile(CommonUtil.convertFtpChar(charSet, getRemotePath()));
new String(getRemotePath().getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET));
ALog.d(TAG, ALog.d(TAG,
String.format("删除文件%s,code: %s, msg: %s", b ? "成功" : "失败", client.getReplyCode(), String.format("删除文件%s,code: %s, msg: %s", b ? "成功" : "失败", client.getReplyCode(),
client.getReplyString())); client.getReplyString()));
} else if (!TextUtils.isEmpty(interceptHandler.getNewFileName())) { } else if (!TextUtils.isEmpty(interceptHandler.getNewFileName())) {
ALog.i(TAG, String.format("远端已拥有同名文件,将修改remotePath,文件名:%s,remotePath:%s", ALog.i(TAG, String.format("远端已拥有同名文件,将修改remotePath,原文件名:%s,新文件名:%s",
mEntity.getFileName(), interceptHandler.getNewFileName())); mEntity.getFileName(), interceptHandler.getNewFileName()));
remotePath = mTaskWrapper.asFtp().getUrlEntity().remotePath remotePath = mTaskWrapper.asFtp().getUrlEntity().remotePath
+ "/" + "/"
+ interceptHandler.getNewFileName(); + interceptHandler.getNewFileName();
client.disconnect(); mTaskWrapper.asFtp().setNewFileName(interceptHandler.getNewFileName());
closeClient(client);
run(); run();
return false;
} }
} }
} }

@ -15,12 +15,14 @@
*/ */
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import android.text.TextUtils;
import aria.apache.commons.net.ftp.FTPClient; import aria.apache.commons.net.ftp.FTPClient;
import aria.apache.commons.net.ftp.FTPReply; import aria.apache.commons.net.ftp.FTPReply;
import aria.apache.commons.net.ftp.OnFtpInputStreamListener; import aria.apache.commons.net.ftp.OnFtpInputStreamListener;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.common.ftp.AbsFtpThreadTask; import com.arialyy.aria.core.common.ftp.AbsFtpThreadTask;
import com.arialyy.aria.core.common.ftp.FtpTaskDelegate;
import com.arialyy.aria.core.config.BaseTaskConfig; import com.arialyy.aria.core.config.BaseTaskConfig;
import com.arialyy.aria.core.config.DownloadConfig; import com.arialyy.aria.core.config.DownloadConfig;
import com.arialyy.aria.core.config.UploadConfig; import com.arialyy.aria.core.config.UploadConfig;
@ -31,6 +33,7 @@ import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -82,7 +85,8 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UTaskWrapper> {
return this; return this;
} }
file = new BufferedRandomAccessFile(getConfig().TEMP_FILE, "rwd", getTaskConfig().getBuffSize()); file =
new BufferedRandomAccessFile(getConfig().TEMP_FILE, "rwd", getTaskConfig().getBuffSize());
if (getConfig().START_LOCATION != 0) { if (getConfig().START_LOCATION != 0) {
//file.skipBytes((int) getConfig().START_LOCATION); //file.skipBytes((int) getConfig().START_LOCATION);
file.seek(getConfig().START_LOCATION); file.seek(getConfig().START_LOCATION);
@ -92,7 +96,8 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UTaskWrapper> {
return this; return this;
} }
ALog.i(TAG, ALog.i(TAG,
String.format("任务【%s】线程__%s__上传完毕", getConfig().TEMP_FILE.getName(), getConfig().THREAD_ID)); String.format("任务【%s】线程__%s__上传完毕", getConfig().TEMP_FILE.getName(),
getConfig().THREAD_ID));
writeConfig(true, getConfig().END_LOCATION); writeConfig(true, getConfig().END_LOCATION);
getState().COMPLETE_THREAD_NUM++; getState().COMPLETE_THREAD_NUM++;
if (getState().isComplete()) { if (getState().isComplete()) {
@ -100,11 +105,13 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UTaskWrapper> {
} }
if (getState().isFail()) { if (getState().isFail()) {
mListener.onFail(false, new TaskException(TAG, mListener.onFail(false, new TaskException(TAG,
String.format("上传失败,filePath: %s, uploadUrl: %s", getEntity().getFilePath(), getConfig().URL))); String.format("上传失败,filePath: %s, uploadUrl: %s", getEntity().getFilePath(),
getConfig().URL)));
} }
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, new AriaIOException(TAG, fail(mChildCurrentLocation, new AriaIOException(TAG,
String.format("上传失败,filePath: %s, uploadUrl: %s", getEntity().getFilePath(), getConfig().URL))); String.format("上传失败,filePath: %s, uploadUrl: %s", getEntity().getFilePath(),
getConfig().URL)));
} catch (Exception e) { } catch (Exception e) {
fail(mChildCurrentLocation, new AriaIOException(TAG, null, e)); fail(mChildCurrentLocation, new AriaIOException(TAG, null, e));
} finally { } finally {
@ -123,10 +130,17 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UTaskWrapper> {
} }
private void initPath() throws UnsupportedEncodingException { private void initPath() throws UnsupportedEncodingException {
dir = new String(getTaskWrapper().asFtp().getUrlEntity().remotePath.getBytes(charSet), FtpTaskDelegate delegate = getTaskWrapper().asFtp();
SERVER_CHARSET); dir = CommonUtil.convertFtpChar(charSet, delegate.getUrlEntity().remotePath);
remotePath = new String(String.format("%s/%s", getTaskWrapper().asFtp().getUrlEntity().remotePath,
getEntity().getFileName()).getBytes(charSet), SERVER_CHARSET); String fileName =
TextUtils.isEmpty(delegate.getNewFileName()) ? CommonUtil.convertFtpChar(charSet,
getEntity().getFileName())
: CommonUtil.convertFtpChar(charSet, delegate.getNewFileName());
remotePath =
CommonUtil.convertFtpChar(charSet,
String.format("%s/%s", delegate.getUrlEntity().remotePath, fileName));
} }
/** /**

@ -78,6 +78,19 @@ import java.util.regex.Pattern;
*/ */
public class CommonUtil { public class CommonUtil {
private static final String TAG = "CommonUtil"; private static final String TAG = "CommonUtil";
public static final String SERVER_CHARSET = "ISO-8859-1";
/**
* 将字符串转换为Ftp服务器默认的ISO-8859-1编码
*
* @param charSet 原字符串编码s
* @param str 需要转换的字符串
* @return 转换后的字符串
*/
public static String convertFtpChar(String charSet, String str)
throws UnsupportedEncodingException {
return new String(str.getBytes(charSet), SERVER_CHARSET);
}
/** /**
* 检查分块任务是否存在 * 检查分块任务是否存在

@ -1,6 +1,7 @@
## 开发日志 ## 开发日志
+ v_3.6.5 + v_3.6.5
- fix bug https://github.com/AriaLyy/Aria/issues/403 - fix bug https://github.com/AriaLyy/Aria/issues/403
- 新增ftp上传拦截器 https://github.com/AriaLyy/Aria/issues/402
+ v_3.6.4 (2019/5/16) + v_3.6.4 (2019/5/16)
- 优化任务接收器的代码结构 - 优化任务接收器的代码结构
- 修复`DbEntity.saveAll()`失败的问题 - 修复`DbEntity.saveAll()`失败的问题

@ -18,9 +18,9 @@
<!--android:name=".test.TestFTPDirActivity"--> <!--android:name=".test.TestFTPDirActivity"-->
<!--android:name=".test.TestFTPActivity"--> <!--android:name=".test.TestFTPActivity"-->
<!--android:name=".download.group.DownloadGroupActivity"--> <!--android:name=".download.group.DownloadGroupActivity"-->
<!--android:name=".MainActivity"--> <!--android:name=".MainActivity"-->
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:label="@string/app_name"> android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
@ -44,6 +44,16 @@
<activity android:name=".core.download.KotlinDownloadActivity"/> <activity android:name=".core.download.KotlinDownloadActivity"/>
<service android:name=".core.download.service_download.DownloadService"/> <service android:name=".core.download.service_download.DownloadService"/>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/aria_fileprovider_paths"/>
</provider>
</application> </application>
</manifest> </manifest>

@ -0,0 +1,64 @@
/*
* 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.common;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseDialog;
import com.arialyy.simple.databinding.DialogModifyUrlBinding;
/**
* Created by AriaL on 2017/6/3.
*/
@SuppressLint("ValidFragment") public class ModifyUrlDialog
extends BaseDialog<DialogModifyUrlBinding> {
public static final int MODIFY_URL_DIALOG_RESULT = 0xA1;
private String mTitle, mText;
public ModifyUrlDialog(Object obj, String title, String defaultText) {
super(obj);
mTitle = title;
mText = defaultText;
}
@Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
getBinding().setTitle(mTitle);
getBinding().setText(mText);
getBinding().cancel.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
dismiss();
}
});
getBinding().enter.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
getSimplerModule().onDialog(MODIFY_URL_DIALOG_RESULT, mText);
}
});
getBinding().edit.post(new Runnable() {
@Override public void run() {
getBinding().edit.setSelection(mText.length());
}
});
}
@Override protected int setLayoutId() {
return R.layout.dialog_modify_url;
}
}

@ -35,7 +35,7 @@ import java.io.File;
* Ftp下载测试 * Ftp下载测试
*/ */
public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding> { public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding> {
private final String URL = "sftp://9.9.9.205:2222/Cyberduck-6.9.4.30164.zip"; private final String URL = "ftp://9.9.9.205:2121/Cyberduck-6.9.4.30164.zip";
//private final String URL = "ftp://182.92.180.213:21/video/572fed5c2ad48_1024.jpg"; //private final String URL = "ftp://182.92.180.213:21/video/572fed5c2ad48_1024.jpg";
//private final String URL = "ftp://182.92.180.213:21/DATA/20180205/rar/1111.rar"; //private final String URL = "ftp://182.92.180.213:21/DATA/20180205/rar/1111.rar";
//private final String URL = "ftp://d:d@dygodj8.com:12311/咖啡风暴HD大陆公映意语中字[飘花www.piaohua.com].mp4"; //private final String URL = "ftp://d:d@dygodj8.com:12311/咖啡风暴HD大陆公映意语中字[飘花www.piaohua.com].mp4";

@ -15,7 +15,11 @@
*/ */
package com.arialyy.simple.core.upload; package com.arialyy.simple.core.upload;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.content.FileProvider;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import com.arialyy.annotations.Upload; import com.arialyy.annotations.Upload;
@ -27,8 +31,10 @@ import com.arialyy.aria.core.upload.UploadTask;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.frame.util.FileUtil; import com.arialyy.frame.util.FileUtil;
import com.arialyy.frame.util.show.T; import com.arialyy.frame.util.show.T;
import com.arialyy.simple.BuildConfig;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.common.ModifyUrlDialog;
import com.arialyy.simple.databinding.ActivityFtpUploadBinding; import com.arialyy.simple.databinding.ActivityFtpUploadBinding;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
@ -37,45 +43,81 @@ import java.util.List;
* Created by lyy on 2017/7/28. Ftp 文件上传demo * Created by lyy on 2017/7/28. Ftp 文件上传demo
*/ */
public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> { public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> {
private final String FILE_PATH = "/mnt/sdcard/AriaPrj.rar"; private final int OPEN_FILE_MANAGER_CODE = 0xB1;
private final String URL = "ftp://9.9.9.205:2121/aa/你好"; private String mFilePath = "/mnt/sdcard/AriaPrj.rar";
private String mUrl = "ftp://9.9.9.205:2121/aa/你好";
@Override protected void init(Bundle savedInstanceState) { @Override protected void init(Bundle savedInstanceState) {
setTile("D_FTP 文件上传"); setTile("D_FTP 文件上传");
super.init(savedInstanceState); super.init(savedInstanceState);
Aria.upload(this).register(); Aria.upload(this).register();
UploadEntity entity = Aria.upload(this).getUploadEntity(FILE_PATH); UploadEntity entity = Aria.upload(this).getUploadEntity(mFilePath);
if (entity != null) { if (entity != null) {
getBinding().setFileSize(CommonUtil.formatFileSize(entity.getFileSize())); getBinding().setFileSize(CommonUtil.formatFileSize(entity.getFileSize()));
getBinding().setProgress(entity.isComplete() ? 100 getBinding().setProgress(entity.isComplete() ? 100
: (int) (entity.getCurrentProgress() * 100 / entity.getFileSize())); : (int) (entity.getCurrentProgress() * 100 / entity.getFileSize()));
} }
getBinding().setUrl(mUrl);
getBinding().setFilePath(mFilePath);
getBinding().setViewModel(this);
} }
@Override protected int setLayoutId() { @Override protected int setLayoutId() {
return R.layout.activity_ftp_upload; return R.layout.activity_ftp_upload;
} }
public void chooseUrl() {
ModifyUrlDialog dialog =
new ModifyUrlDialog(this, getString(R.string.modify_url_dialog_title), mUrl);
dialog.show(getSupportFragmentManager(), "ModifyUrlDialog");
}
public void chooseFilePath() {
File parentFile = new File(mFilePath);
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".provider",
parentFile.getParentFile());
} else {
uri = Uri.fromFile(parentFile.getParentFile());
}
intent.setDataAndType(uri, "*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(intent, OPEN_FILE_MANAGER_CODE);
}
public void onClick(View view) { public void onClick(View view) {
switch (view.getId()) { switch (view.getId()) {
case R.id.start: case R.id.start:
Aria.upload(this).loadFtp(FILE_PATH).setUploadUrl(URL).setUploadInterceptor( if (Aria.upload(this).load(mFilePath).isRunning()) {
new IFtpUploadInterceptor() { Aria.upload(this).loadFtp(mFilePath).stop();
getBinding().setStateStr(getString(R.string.resume));
@Override } else {
public FtpInterceptHandler onIntercept(UploadEntity entity, List<String> fileList) { getBinding().setStateStr(getString(R.string.stop));
FtpInterceptHandler.Builder builder = new FtpInterceptHandler.Builder(); Aria.upload(this).loadFtp(mFilePath).setUploadUrl(mUrl).setUploadInterceptor(
builder.coverServerFile(); new IFtpUploadInterceptor() {
//builder.resetFileName("test");
return builder.build(); @Override
} public FtpInterceptHandler onIntercept(UploadEntity entity, List<String> fileList) {
}).login("lao", "123456").start(); FtpInterceptHandler.Builder builder = new FtpInterceptHandler.Builder();
break; //builder.coverServerFile();
case R.id.stop: builder.resetFileName("test.zip");
Aria.upload(this).loadFtp(FILE_PATH).stop(); return builder.build();
}
})
//.login("lao", "123456")
.login("N0rI", "0qcK")
.start();
}
break; break;
case R.id.cancel: case R.id.cancel:
Aria.upload(this).loadFtp(FILE_PATH).cancel(); Aria.upload(this).loadFtp(mFilePath).cancel();
break; break;
} }
} }
@ -123,4 +165,20 @@ public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> {
getBinding().setSpeed(""); getBinding().setSpeed("");
T.showShort(this, "文件:" + task.getEntity().getFileName() + ",上传完成"); T.showShort(this, "文件:" + task.getEntity().getFileName() + ",上传完成");
} }
@Override protected void dataCallback(int result, Object data) {
super.dataCallback(result, data);
if (result == ModifyUrlDialog.MODIFY_URL_DIALOG_RESULT) {
mUrl = String.valueOf(data);
getBinding().setUrl(mUrl);
}
}
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == OPEN_FILE_MANAGER_CODE && resultCode == RESULT_OK) {
Uri uri = data.getData();
//Toast.makeText(this, "文件路径:" + uri.getPath(), Toast.LENGTH_SHORT).show();
}
}
} }

@ -0,0 +1,84 @@
/*
* 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.content.res.TypedArray;
import android.databinding.BindingAdapter;
import android.graphics.drawable.Drawable;
import android.support.annotation.DrawableRes;
import android.support.v7.widget.AppCompatImageView;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.arialyy.simple.R;
public class SvgTextView extends RelativeLayout {
private TextView textView;
private AppCompatImageView icon;
public SvgTextView(Context context) {
this(context, null);
}
public SvgTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
private void init(AttributeSet attrs) {
LayoutInflater.from(getContext()).inflate(R.layout.layout_svg_text, this, true);
textView = findViewById(R.id.text);
icon = findViewById(R.id.image);
// init values from custom attributes
final TypedArray attributes =
getContext().obtainStyledAttributes(attrs, R.styleable.SvgTextView);
Drawable drawable = attributes.getDrawable(R.styleable.SvgTextView_svg_text_view_icon);
if (drawable != null) {
icon.setImageDrawable(drawable);
}
String str = attributes.getString(R.styleable.SvgTextView_text);
if (!TextUtils.isEmpty(str)) {
textView.setText(str);
}
attributes.recycle();
}
public void setIconClickListener(View.OnClickListener listener){
icon.setOnClickListener(listener);
}
@BindingAdapter(value = {"svg_text_view_icon"})
public static void bindAttr(SvgTextView svgTextView, @DrawableRes int drawable) {
svgTextView.icon.setImageResource(drawable);
}
public void setIcon(@DrawableRes int drawable) {
icon.setImageResource(drawable);
}
public void setText(CharSequence text) {
textView.setText(text);
}
}

@ -0,0 +1,6 @@
<vector android:height="24dp" android:viewportHeight="1024"
android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#2b2b2b" android:pathData="M895.65,672.81c14.3,0 23.74,-9.54 23.74,-23.74L919.39,269.29a30.46,30.46 0,0 0,-8.66 -21.29L738.23,71.19A30.46,30.46 0,0 0,716.42 62L199.21,62c-52.29,0 -95.07,42.78 -95.07,95.07v654h-0.1v51.85h0.1c0,52.25 42.81,95.07 95.07,95.07h625.11c52.25,0 95.07,-42.81 95.07,-95.07v-71.31c0,-14.31 -9.54,-23.74 -23.74,-23.74s-23.74,9.54 -23.74,23.74v71.32a47.69,47.69 0,0 1,-47.48 47.58L199.21,910.51a47.72,47.72 0,0 1,-47.58 -47.58v-28.11h0.1L151.73,157.06a47.63,47.63 0,0 1,47.58 -47.48h482.47v123.57a71.32,71.32 0,0 0,71.32 71.32h118.8v344.6c-0.09,14.2 9.44,23.74 23.75,23.74zM847.19,256.81L753,256.81v0.1c-14.3,0 -23.74,-11.92 -23.74,-23.74v-98.75a2.4,2.4 0,0 1,4.13 -1.67l115.52,120a2.4,2.4 0,0 1,-1.73 4.04z"/>
<path android:fillColor="#2b2b2b" android:pathData="M318.91,394.59c-14.78,0 -26.81,-12.25 -26.81,-27.3s12,-27.3 26.81,-27.3h300.47c14.78,0 26.81,12.25 26.81,27.3s-12,27.3 -26.81,27.3zM318.91,569.8c-14.78,0 -26.81,-12.25 -26.81,-27.3s12,-27.3 26.81,-27.3h384.85c14.78,0 26.81,12.25 26.81,27.3s-12,27.3 -26.81,27.3zM318.91,742c-14.78,0 -26.81,-12.25 -26.81,-27.3s12,-27.3 26.81,-27.3h261.3c14.78,0 26.81,12.25 26.81,27.3S595,742 580.21,742z"/>
<path android:fillColor="#2b2b2b" android:pathData="M704.01,367.3m-27.3,0a27.3,27.3 0,1 0,54.6 0,27.3 27.3,0 1,0 -54.6,0Z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="1024"
android:viewportWidth="1024"
android:width="24dp">
<path
android:fillColor="#2b2b2b"
android:pathData="M768.49,388.36L590.76,215.07 210.93,594.49l-66.2,242.16v0.4L386.48,769.8zM739.52,66.62l-95.2,95.04 178.3,172.65 92.38,-92.3c48.49,-48.41 48.49,-126.99 0,-175.39 -48.4,-48.41 -127.07,-48.41 -175.47,-0zM79.03,878.71h872.33v114.98H79.03z"/>
</vector>

@ -15,6 +15,22 @@
name="progress" name="progress"
type="int" type="int"
/> />
<variable
name="url"
type="String"
/>
<variable
name="filePath"
type="String"
/>
<variable
name="viewModel"
type="com.arialyy.simple.core.upload.FtpUploadActivity"
/>
<variable
name="stateStr"
type="String"
/>
</data> </data>
<LinearLayout <LinearLayout
@ -25,11 +41,34 @@
<include layout="@layout/layout_bar"/> <include layout="@layout/layout_bar"/>
<com.arialyy.simple.widget.SvgTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
bind:iconClickListener="@{() -> viewModel.chooseUrl()}"
bind:svg_text_view_icon="@drawable/ic_modify"
bind:text="@{@string/url(url)}"
/>
<com.arialyy.simple.widget.SvgTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
bind:iconClickListener="@{() -> viewModel.chooseFilePath()}"
bind:svg_text_view_icon="@drawable/ic_choose_file"
bind:text="@{@string/file_path(filePath)}"
/>
<include <include
layout="@layout/content_single" layout="@layout/layout_content_single"
bind:fileSize="@{fileSize}" bind:fileSize="@{fileSize}"
bind:progress="@{progress}" bind:progress="@{progress}"
bind:speed="@{speed}" bind:speed="@{speed}"
bind:stateStr="@{stateStr}"
/> />
</LinearLayout> </LinearLayout>

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="title"
type="java.lang.String"
/>
<variable
name="text"
type="java.lang.String"
/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background_color"
android:gravity="center|left"
android:maxHeight="400dp"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp"
android:text="@{title}"
android:textColor="@android:color/black"
android:textSize="22sp"
/>
<EditText
android:id="@+id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:background="@android:color/transparent"
android:lineSpacingMultiplier="1.2"
android:text="@{text}"
android:textColor="#000"
android:textSize="16sp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/cancel"
style="?buttonBarButtonStyle"
/>
<Button
android:id="@+id/enter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/enter"
style="?buttonBarButtonStyle"
/>
</LinearLayout>
</LinearLayout>
</layout>

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
>
<data>
<variable
name="fileSize"
type="String"
/>
<variable
name="speed"
type="String"
/>
<variable
name="progress"
type="int"
/>
<variable
name="stateStr"
type="String"
/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".core.download.SingleTaskActivity"
tools:showIn="@layout/activity_single"
>
<com.arialyy.simple.widget.HorizontalProgressBarWithNumber
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
android:layout_toLeftOf="@+id/size"
android:max="100"
android:progress="@{progress}"
style="?android:attr/progressBarStyleHorizontal"
/>
<TextView
android:id="@+id/size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignTop="@+id/progressBar"
android:layout_marginRight="16dp"
android:text="@{fileSize}"
android:textSize="16sp"
/>
<LinearLayout
android:id="@+id/handle_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/progressBar"
android:orientation="horizontal"
>
<TextView
android:id="@+id/speed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_weight="1"
android:text="@{speed}"
android:textColor="@color/black"
/>
<Button
android:id="@+id/start"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="@{stateStr ?? @string/start}"
style="?buttonBarButtonStyle"
/>
<Button
android:id="@+id/cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="@string/delete"
style="?buttonBarButtonStyle"
/>
</LinearLayout>
<TextView
android:id="@+id/speed_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/handle_bar"
/>
</RelativeLayout>
</layout>

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/image"
android:ellipsize="end"
android:singleLine="true"
android:textSize="@dimen/text_size_normal"
/>
<android.support.v7.widget.AppCompatImageView
android:id="@+id/image"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="8dp"
android:clickable="true"
/>
</RelativeLayout>

@ -1,16 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<declare-styleable name="HorizontalProgressBarWithNumber"> <declare-styleable name="HorizontalProgressBarWithNumber">
<attr name="progress_unreached_color" format="color"/> <attr format="color" name="progress_unreached_color"/>
<attr name="progress_reached_color" format="color"/> <attr format="color" name="progress_reached_color"/>
<attr name="progress_reached_bar_height" format="dimension"/> <attr format="dimension" name="progress_reached_bar_height"/>
<attr name="progress_unreached_bar_height" format="dimension"/> <attr format="dimension" name="progress_unreached_bar_height"/>
<attr name="progress_text_size" format="dimension"/> <attr format="dimension" name="progress_text_size"/>
<attr name="progress_text_color" format="color"/> <attr format="color" name="progress_text_color"/>
<attr name="progress_text_offset" format="dimension"/> <attr format="dimension" name="progress_text_offset"/>
<attr name="progress_text_visibility" format="enum"> <attr format="enum" name="progress_text_visibility">
<enum name="visible" value="0"/> <enum name="visible" value="0"/>
<enum name="invisible" value="1"/> <enum name="invisible" value="1"/>
</attr> </attr>
</declare-styleable> </declare-styleable>
<declare-styleable name="SvgTextView">
<attr format="reference" name="svg_text_view_icon"/>
<attr name="text"/>
</declare-styleable>
</resources> </resources>

@ -2,6 +2,17 @@
<string name="app_name">Aria</string> <string name="app_name">Aria</string>
<string name="action_settings">Settings</string> <string name="action_settings">Settings</string>
<string name="url">URL: %1$s</string>
<string name="file_name">文件名: %1$s</string>
<string name="file_path">文件路径: %1$s</string>
<string name="enter">确认</string>
<string name="cancel">取消</string>
<string name="modify_url_dialog_title">修改URL</string>
<string name="stop">停止</string>
<string name="start">开始</string>
<string name="resume">恢复</string>
<string name="delete">删除</string>
<string-array name="main_items"> <string-array name="main_items">
<item>http 下载</item> <item>http 下载</item>
<item>http 上传</item> <item>http 上传</item>
@ -29,9 +40,6 @@
<item>组件中使用</item> <item>组件中使用</item>
</string-array> </string-array>
<string name="file_name">文件名: %1$s</string>
<string name="file_path">保存路径: %1$s</string>
<string-array name="test_apk_download_url"> <string-array name="test_apk_download_url">
<item>http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk</item> <!--300M的文件--> <item>http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk</item> <!--300M的文件-->

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<root-path
name="root"
path="" />
<files-path
name="files"
path="." />
<cache-path
name="cache"
path="." />
<external-path
name="external"
path="." />
<external-files-path
name="external_file_path"
path="." />
<external-cache-path
name="external_cache_path"
path="." />
</paths>
Loading…
Cancel
Save