commit
a117eb8c14
@ -1,6 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||||
<project version="4"> |
|
||||||
<component name="VcsDirectoryMappings"> |
|
||||||
<mapping directory="" vcs="Git" /> |
|
||||||
</component> |
|
||||||
</project> |
|
@ -0,0 +1,8 @@ |
|||||||
|
package com.arialyy.aria.core; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Aria.Lao on 2017/1/18. |
||||||
|
* AM 上传文件接收器 |
||||||
|
*/ |
||||||
|
public class AMUplodReceiver { |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
package com.arialyy.aria.core; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Aria.Lao on 2017/1/23. |
||||||
|
*/ |
||||||
|
|
||||||
|
public enum RequestEnum { |
||||||
|
GET("GET"), POST("POST"); |
||||||
|
|
||||||
|
String name; |
||||||
|
|
||||||
|
RequestEnum(String name) { |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
package com.arialyy.aria.core; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Aria.Lao on 2017/1/23. |
||||||
|
* 任务实体 |
||||||
|
*/ |
||||||
|
public class TaskEntity { |
||||||
|
public DownloadEntity downloadEntity; |
||||||
|
public RequestEnum requestEnum = RequestEnum.GET; |
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
/* |
||||||
|
* 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.task; |
||||||
|
|
||||||
|
import com.arialyy.aria.util.CAConfiguration; |
||||||
|
import com.arialyy.aria.util.SSLContextUtil; |
||||||
|
import java.io.IOException; |
||||||
|
import java.net.HttpURLConnection; |
||||||
|
import java.net.ProtocolException; |
||||||
|
import java.net.URL; |
||||||
|
import java.net.URLConnection; |
||||||
|
import javax.net.ssl.HttpsURLConnection; |
||||||
|
import javax.net.ssl.SSLContext; |
||||||
|
import javax.net.ssl.SSLSocketFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by lyy on 2017/1/18. |
||||||
|
* 链接帮助类 |
||||||
|
*/ |
||||||
|
class ConnectionHelp { |
||||||
|
/** |
||||||
|
* 处理链接 |
||||||
|
* |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
static HttpURLConnection handleConnection(URL url) throws IOException { |
||||||
|
HttpURLConnection conn; |
||||||
|
URLConnection urlConn = url.openConnection(); |
||||||
|
if (urlConn instanceof HttpsURLConnection) { |
||||||
|
conn = (HttpsURLConnection) urlConn; |
||||||
|
SSLContext sslContext = |
||||||
|
SSLContextUtil.getSSLContext(CAConfiguration.CA_ALIAS, CAConfiguration.CA_ALIAS); |
||||||
|
if (sslContext == null) { |
||||||
|
sslContext = SSLContextUtil.getDefaultSLLContext(); |
||||||
|
} |
||||||
|
SSLSocketFactory ssf = sslContext.getSocketFactory(); |
||||||
|
((HttpsURLConnection) conn).setSSLSocketFactory(ssf); |
||||||
|
((HttpsURLConnection) conn).setHostnameVerifier(SSLContextUtil.HOSTNAME_VERIFIER); |
||||||
|
} else { |
||||||
|
conn = (HttpURLConnection) urlConn; |
||||||
|
} |
||||||
|
return conn; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 设置头部参数 |
||||||
|
* |
||||||
|
* @throws ProtocolException |
||||||
|
*/ |
||||||
|
static HttpURLConnection setConnectParam(HttpURLConnection conn) throws ProtocolException { |
||||||
|
conn.setRequestMethod("GET"); |
||||||
|
conn.setRequestProperty("Charset", "UTF-8"); |
||||||
|
conn.setRequestProperty("User-Agent", |
||||||
|
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); |
||||||
|
conn.setRequestProperty("Accept", |
||||||
|
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"); |
||||||
|
////用于处理Disconnect 不起作用问题
|
||||||
|
//conn.setRequestProperty("Connection", "close");
|
||||||
|
conn.setRequestProperty("Connection", "Keep-Alive"); |
||||||
|
return conn; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
/* |
||||||
|
* 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.task; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by lyy on 2017/1/18. |
||||||
|
* 下载状态常量 |
||||||
|
*/ |
||||||
|
final class DownloadStateConstance { |
||||||
|
int CANCEL_NUM = 0; |
||||||
|
int STOP_NUM = 0; |
||||||
|
int FAIL_NUM = 0; |
||||||
|
int CONNECT_TIME_OUT = 5000 * 4; //连接超时时间
|
||||||
|
int READ_TIME_OUT = 1000 * 20; //流读取的超时时间
|
||||||
|
int COMPLETE_THREAD_NUM = 0; |
||||||
|
int THREAD_NUM = 3; |
||||||
|
long CURRENT_LOCATION = 0; |
||||||
|
boolean isDownloading = false; |
||||||
|
boolean isCancel = false; |
||||||
|
boolean isStop = false; |
||||||
|
|
||||||
|
DownloadStateConstance(int num) { |
||||||
|
THREAD_NUM = num; |
||||||
|
} |
||||||
|
|
||||||
|
void cleanState() { |
||||||
|
isCancel = false; |
||||||
|
isStop = false; |
||||||
|
isDownloading = true; |
||||||
|
CURRENT_LOCATION = 0; |
||||||
|
CANCEL_NUM = 0; |
||||||
|
STOP_NUM = 0; |
||||||
|
FAIL_NUM = 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 所有子线程是否都已经停止下载 |
||||||
|
*/ |
||||||
|
boolean isStop() { |
||||||
|
return STOP_NUM == THREAD_NUM; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 所有子线程是否都已经下载失败 |
||||||
|
*/ |
||||||
|
boolean isFail() { |
||||||
|
return FAIL_NUM == THREAD_NUM; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 所有子线程是否都已经完成下载 |
||||||
|
*/ |
||||||
|
boolean isComplete() { |
||||||
|
return COMPLETE_THREAD_NUM == THREAD_NUM; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 所有子线程是否都已经取消下载 |
||||||
|
*/ |
||||||
|
boolean isCancel() { |
||||||
|
return CANCEL_NUM == THREAD_NUM; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,283 @@ |
|||||||
|
/* |
||||||
|
* 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.task; |
||||||
|
|
||||||
|
import android.os.Handler; |
||||||
|
import android.os.Looper; |
||||||
|
import android.os.Message; |
||||||
|
import android.util.Log; |
||||||
|
import com.arialyy.aria.util.BufferedRandomAccessFile; |
||||||
|
import com.arialyy.aria.util.CommonUtil; |
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.io.RandomAccessFile; |
||||||
|
import java.net.HttpURLConnection; |
||||||
|
import java.net.MalformedURLException; |
||||||
|
import java.net.URL; |
||||||
|
import java.util.Properties; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by lyy on 2017/1/18. |
||||||
|
* 下载线程 |
||||||
|
*/ |
||||||
|
final class SingleThreadTask implements Runnable { |
||||||
|
private static final String TAG = "SingleThreadTask"; |
||||||
|
// TODO: 2017/2/22 不能使用1024 否则最大速度不能超过3m
|
||||||
|
private static final int BUF_SIZE = 8192; |
||||||
|
private DownloadUtil.ConfigEntity mConfigEntity; |
||||||
|
private String mConfigFPath; |
||||||
|
private long mChildCurrentLocation = 0; |
||||||
|
private static final Object LOCK = new Object(); |
||||||
|
private IDownloadListener mListener; |
||||||
|
private DownloadStateConstance mConstance; |
||||||
|
|
||||||
|
SingleThreadTask(DownloadStateConstance constance, IDownloadListener listener, |
||||||
|
DownloadUtil.ConfigEntity downloadInfo) { |
||||||
|
mConstance = constance; |
||||||
|
mListener = listener; |
||||||
|
this.mConfigEntity = downloadInfo; |
||||||
|
if (mConfigEntity.isSupportBreakpoint) { |
||||||
|
mConfigFPath = downloadInfo.CONFIG_FILE_PATH; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void run() { |
||||||
|
HttpURLConnection conn = null; |
||||||
|
InputStream is = null; |
||||||
|
try { |
||||||
|
URL url = new URL(mConfigEntity.DOWNLOAD_URL); |
||||||
|
//conn = (HttpURLConnection) url.openConnection();
|
||||||
|
conn = ConnectionHelp.handleConnection(url); |
||||||
|
if (mConfigEntity.isSupportBreakpoint) { |
||||||
|
Log.d(TAG, "线程_" |
||||||
|
+ mConfigEntity.THREAD_ID |
||||||
|
+ "_正在下载【开始位置 : " |
||||||
|
+ mConfigEntity.START_LOCATION |
||||||
|
+ ",结束位置:" |
||||||
|
+ mConfigEntity.END_LOCATION |
||||||
|
+ "】"); |
||||||
|
//在头里面请求下载开始位置和结束位置
|
||||||
|
conn.setRequestProperty("Range", |
||||||
|
"bytes=" + mConfigEntity.START_LOCATION + "-" + mConfigEntity.END_LOCATION); |
||||||
|
} else { |
||||||
|
Log.w(TAG, "该下载不支持断点,即将重新下载"); |
||||||
|
} |
||||||
|
conn = ConnectionHelp.setConnectParam(conn); |
||||||
|
conn.setConnectTimeout(mConstance.CONNECT_TIME_OUT); |
||||||
|
conn.setReadTimeout(mConstance.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数
|
||||||
|
is = conn.getInputStream(); |
||||||
|
//创建可设置位置的文件
|
||||||
|
BufferedRandomAccessFile file = |
||||||
|
new BufferedRandomAccessFile(mConfigEntity.TEMP_FILE, "rwd", BUF_SIZE); |
||||||
|
//设置文件长度
|
||||||
|
file.seek(mConfigEntity.START_LOCATION); |
||||||
|
|
||||||
|
byte[] buffer = new byte[BUF_SIZE]; |
||||||
|
int len; |
||||||
|
//当前子线程的下载位置
|
||||||
|
mChildCurrentLocation = mConfigEntity.START_LOCATION; |
||||||
|
while ((len = is.read(buffer)) != -1) { |
||||||
|
if (mConstance.isCancel) { |
||||||
|
break; |
||||||
|
} |
||||||
|
if (mConstance.isStop) { |
||||||
|
Log.i(TAG, "stop"); |
||||||
|
break; |
||||||
|
} |
||||||
|
//把下载数据数据写入文件
|
||||||
|
file.write(buffer, 0, len); |
||||||
|
progress(len); |
||||||
|
} |
||||||
|
file.close(); |
||||||
|
//close 为阻塞的,需要使用线程池来处理
|
||||||
|
is.close(); |
||||||
|
conn.disconnect(); |
||||||
|
if (mConstance.isCancel) { |
||||||
|
return; |
||||||
|
} |
||||||
|
//停止状态不需要删除记录文件
|
||||||
|
if (mConstance.isStop) { |
||||||
|
return; |
||||||
|
} |
||||||
|
//支持断点的处理
|
||||||
|
if (mConfigEntity.isSupportBreakpoint) { |
||||||
|
Log.i(TAG, "线程【" + mConfigEntity.THREAD_ID + "】下载完毕"); |
||||||
|
writeConfig(mConfigEntity.TEMP_FILE.getName() + "_state_" + mConfigEntity.THREAD_ID, |
||||||
|
1 + ""); |
||||||
|
mListener.onChildComplete(mConfigEntity.END_LOCATION); |
||||||
|
mConstance.COMPLETE_THREAD_NUM++; |
||||||
|
if (mConstance.isComplete()) { |
||||||
|
File configFile = new File(mConfigFPath); |
||||||
|
if (configFile.exists()) { |
||||||
|
configFile.delete(); |
||||||
|
} |
||||||
|
mConstance.isDownloading = false; |
||||||
|
mListener.onComplete(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
Log.i(TAG, "下载任务完成"); |
||||||
|
mConstance.isDownloading = false; |
||||||
|
mListener.onComplete(); |
||||||
|
} |
||||||
|
} catch (MalformedURLException e) { |
||||||
|
mConstance.FAIL_NUM++; |
||||||
|
failDownload(mConfigEntity, mChildCurrentLocation, "下载链接异常", e); |
||||||
|
} catch (IOException e) { |
||||||
|
mConstance.FAIL_NUM++; |
||||||
|
failDownload(mConfigEntity, mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】", |
||||||
|
e); |
||||||
|
} catch (Exception e) { |
||||||
|
mConstance.FAIL_NUM++; |
||||||
|
failDownload(mConfigEntity, mChildCurrentLocation, "获取流失败", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 停止下载 |
||||||
|
*/ |
||||||
|
protected void stop() { |
||||||
|
synchronized (LOCK) { |
||||||
|
try { |
||||||
|
if (mConfigEntity.isSupportBreakpoint) { |
||||||
|
mConstance.STOP_NUM++; |
||||||
|
String location = String.valueOf(mChildCurrentLocation); |
||||||
|
Log.d(TAG, "thread_" |
||||||
|
+ mConfigEntity.THREAD_ID |
||||||
|
+ "_stop, stop location ==> " |
||||||
|
+ mChildCurrentLocation); |
||||||
|
writeConfig(mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID, |
||||||
|
location); |
||||||
|
if (mConstance.isStop()) { |
||||||
|
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++"); |
||||||
|
mConstance.isDownloading = false; |
||||||
|
mListener.onStop(mConstance.CURRENT_LOCATION); |
||||||
|
} |
||||||
|
} else { |
||||||
|
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++"); |
||||||
|
mConstance.isDownloading = false; |
||||||
|
mListener.onStop(mConstance.CURRENT_LOCATION); |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 下载中 |
||||||
|
*/ |
||||||
|
private void progress(long len) { |
||||||
|
synchronized (LOCK) { |
||||||
|
mChildCurrentLocation += len; |
||||||
|
mConstance.CURRENT_LOCATION += len; |
||||||
|
mListener.onProgress(mConstance.CURRENT_LOCATION); |
||||||
|
//mHandler.sendEmptyMessage(1);
|
||||||
|
//mHandler.post(t);
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Handler mHandler = new Handler(Looper.getMainLooper()) { |
||||||
|
@Override public void handleMessage(Message msg) { |
||||||
|
super.handleMessage(msg); |
||||||
|
mListener.onProgress(mConstance.CURRENT_LOCATION); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
Thread t = new Thread(new Runnable() { |
||||||
|
@Override public void run() { |
||||||
|
mListener.onProgress(mConstance.CURRENT_LOCATION); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
//Handler handler = new Handler(){
|
||||||
|
// @Override public void handleMessage(Message msg) {
|
||||||
|
// super.handleMessage(msg);
|
||||||
|
// mListener.onProgress(mConstance.CURRENT_LOCATION);
|
||||||
|
// }
|
||||||
|
//};
|
||||||
|
|
||||||
|
Thread thread = new Thread(); |
||||||
|
|
||||||
|
/** |
||||||
|
* 取消下载 |
||||||
|
*/ |
||||||
|
protected void cancel() { |
||||||
|
synchronized (LOCK) { |
||||||
|
if (mConfigEntity.isSupportBreakpoint) { |
||||||
|
mConstance.CANCEL_NUM++; |
||||||
|
Log.d(TAG, "++++++++++ thread_" + mConfigEntity.THREAD_ID + "_cancel ++++++++++"); |
||||||
|
if (mConstance.isCancel()) { |
||||||
|
File configFile = new File(mConfigFPath); |
||||||
|
if (configFile.exists()) { |
||||||
|
configFile.delete(); |
||||||
|
} |
||||||
|
if (mConfigEntity.TEMP_FILE.exists()) { |
||||||
|
mConfigEntity.TEMP_FILE.delete(); |
||||||
|
} |
||||||
|
Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++"); |
||||||
|
mConstance.isDownloading = false; |
||||||
|
mListener.onCancel(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++"); |
||||||
|
mConstance.isDownloading = false; |
||||||
|
mListener.onCancel(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 下载失败 |
||||||
|
*/ |
||||||
|
private void failDownload(DownloadUtil.ConfigEntity dEntity, long currentLocation, String msg, |
||||||
|
Exception ex) { |
||||||
|
synchronized (LOCK) { |
||||||
|
try { |
||||||
|
mConstance.isDownloading = false; |
||||||
|
mConstance.isStop = true; |
||||||
|
if (ex != null) { |
||||||
|
Log.e(TAG, CommonUtil.getPrintException(ex)); |
||||||
|
} |
||||||
|
if (mConfigEntity.isSupportBreakpoint) { |
||||||
|
if (currentLocation != -1) { |
||||||
|
String location = String.valueOf(currentLocation); |
||||||
|
writeConfig(dEntity.TEMP_FILE.getName() + "_record_" + dEntity.THREAD_ID, location); |
||||||
|
} |
||||||
|
if (mConstance.isFail()) { |
||||||
|
Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++"); |
||||||
|
mListener.onFail(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++"); |
||||||
|
mListener.onFail(); |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将记录写入到配置文件 |
||||||
|
*/ |
||||||
|
private void writeConfig(String key, String record) throws IOException { |
||||||
|
File configFile = new File(mConfigFPath); |
||||||
|
Properties pro = CommonUtil.loadConfig(configFile); |
||||||
|
pro.setProperty(key, record); |
||||||
|
CommonUtil.saveConfig(configFile, pro); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
package com.arialyy.aria.exception; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Aria.Lao on 2017/1/18. |
||||||
|
* Aria 文件异常 |
||||||
|
*/ |
||||||
|
public class FileException extends NullPointerException { |
||||||
|
private static final String ARIA_FILE_EXCEPTION = "Aria Exception:"; |
||||||
|
|
||||||
|
public FileException(String detailMessage) { |
||||||
|
super(ARIA_FILE_EXCEPTION + detailMessage); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,328 @@ |
|||||||
|
/** |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one |
||||||
|
* or more contributor license agreements. See the NOTICE file |
||||||
|
* distributed with this work for additional information |
||||||
|
* regarding copyright ownership. The ASF licenses this file |
||||||
|
* to you under the Apache License, Version 2.0 (the |
||||||
|
* "License"); you may not use this file except in compliance |
||||||
|
* with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.arialyy.aria.util; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.util.Arrays; |
||||||
|
|
||||||
|
//import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/** |
||||||
|
* A <code>BufferedRandomAccessFile</code> is like a |
||||||
|
* <code>RandomAccessFile</code>, but it uses a private buffer so that most |
||||||
|
* operations do not require a disk access. |
||||||
|
* <P> |
||||||
|
* |
||||||
|
* Note: The operations on this class are unmonitored. Also, the correct |
||||||
|
* functioning of the <code>RandomAccessFile</code> methods that are not |
||||||
|
* overridden here relies on the implementation of those methods in the |
||||||
|
* superclass. |
||||||
|
* Author : Avinash Lakshman ( alakshman@facebook.com) Prashant Malik ( pmalik@facebook.com ) |
||||||
|
*/ |
||||||
|
|
||||||
|
public final class BufferedRandomAccessFile extends RandomAccessFile { |
||||||
|
//private static final Logger logger_ = Logger.getLogger(BufferedRandomAccessFile.class);
|
||||||
|
static final int LogBuffSz_ = 16; // 64K buffer
|
||||||
|
public static final int BuffSz_ = (1 << LogBuffSz_); |
||||||
|
static final long BuffMask_ = ~(((long) BuffSz_) - 1L); |
||||||
|
|
||||||
|
/* |
||||||
|
* This implementation is based on the buffer implementation in Modula-3's |
||||||
|
* "Rd", "Wr", "RdClass", and "WrClass" interfaces. |
||||||
|
*/ |
||||||
|
private boolean dirty_; // true iff unflushed bytes exist
|
||||||
|
private boolean closed_; // true iff the file is closed
|
||||||
|
private long curr_; // current position in file
|
||||||
|
private long lo_, hi_; // bounds on characters in "buff"
|
||||||
|
private byte[] buff_; // local buffer
|
||||||
|
private long maxHi_; // this.lo + this.buff.length
|
||||||
|
private boolean hitEOF_; // buffer contains last file block?
|
||||||
|
private long diskPos_; // disk position
|
||||||
|
|
||||||
|
/* |
||||||
|
* To describe the above fields, we introduce the following abstractions for |
||||||
|
* the file "f": |
||||||
|
* |
||||||
|
* len(f) the length of the file curr(f) the current position in the file |
||||||
|
* c(f) the abstract contents of the file disk(f) the contents of f's |
||||||
|
* backing disk file closed(f) true iff the file is closed |
||||||
|
* |
||||||
|
* "curr(f)" is an index in the closed interval [0, len(f)]. "c(f)" is a |
||||||
|
* character sequence of length "len(f)". "c(f)" and "disk(f)" may differ if |
||||||
|
* "c(f)" contains unflushed writes not reflected in "disk(f)". The flush |
||||||
|
* operation has the effect of making "disk(f)" identical to "c(f)". |
||||||
|
* |
||||||
|
* A file is said to be *valid* if the following conditions hold: |
||||||
|
* |
||||||
|
* V1. The "closed" and "curr" fields are correct: |
||||||
|
* |
||||||
|
* f.closed == closed(f) f.curr == curr(f) |
||||||
|
* |
||||||
|
* V2. The current position is either contained in the buffer, or just past |
||||||
|
* the buffer: |
||||||
|
* |
||||||
|
* f.lo <= f.curr <= f.hi |
||||||
|
* |
||||||
|
* V3. Any (possibly) unflushed characters are stored in "f.buff": |
||||||
|
* |
||||||
|
* (forall i in [f.lo, f.curr): c(f)[i] == f.buff[i - f.lo]) |
||||||
|
* |
||||||
|
* V4. For all characters not covered by V3, c(f) and disk(f) agree: |
||||||
|
* |
||||||
|
* (forall i in [f.lo, len(f)): i not in [f.lo, f.curr) => c(f)[i] == |
||||||
|
* disk(f)[i]) |
||||||
|
* |
||||||
|
* V5. "f.dirty" is true iff the buffer contains bytes that should be |
||||||
|
* flushed to the file; by V3 and V4, only part of the buffer can be dirty. |
||||||
|
* |
||||||
|
* f.dirty == (exists i in [f.lo, f.curr): c(f)[i] != f.buff[i - f.lo]) |
||||||
|
* |
||||||
|
* V6. this.maxHi == this.lo + this.buff.length |
||||||
|
* |
||||||
|
* Note that "f.buff" can be "null" in a valid file, since the range of |
||||||
|
* characters in V3 is empty when "f.lo == f.curr". |
||||||
|
* |
||||||
|
* A file is said to be *ready* if the buffer contains the current position, |
||||||
|
* i.e., when: |
||||||
|
* |
||||||
|
* R1. !f.closed && f.buff != null && f.lo <= f.curr && f.curr < f.hi |
||||||
|
* |
||||||
|
* When a file is ready, reading or writing a single byte can be performed |
||||||
|
* by reading or writing the in-memory buffer without performing a disk |
||||||
|
* operation. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Open a new <code>BufferedRandomAccessFile</code> on <code>file</code> |
||||||
|
* in mode <code>mode</code>, which should be "r" for reading only, or |
||||||
|
* "rw" for reading and writing. |
||||||
|
*/ |
||||||
|
public BufferedRandomAccessFile(File file, String mode) throws IOException { |
||||||
|
super(file, mode); |
||||||
|
this.init(0); |
||||||
|
} |
||||||
|
|
||||||
|
public BufferedRandomAccessFile(File file, String mode, int size) throws IOException { |
||||||
|
super(file, mode); |
||||||
|
this.init(size); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Open a new <code>BufferedRandomAccessFile</code> on the file named |
||||||
|
* <code>name</code> in mode <code>mode</code>, which should be "r" for |
||||||
|
* reading only, or "rw" for reading and writing. |
||||||
|
*/ |
||||||
|
public BufferedRandomAccessFile(String name, String mode) throws IOException { |
||||||
|
super(name, mode); |
||||||
|
this.init(0); |
||||||
|
} |
||||||
|
|
||||||
|
public BufferedRandomAccessFile(String name, String mode, int size) throws FileNotFoundException { |
||||||
|
super(name, mode); |
||||||
|
this.init(size); |
||||||
|
} |
||||||
|
|
||||||
|
private void init(int size) { |
||||||
|
this.dirty_ = this.closed_ = false; |
||||||
|
this.lo_ = this.curr_ = this.hi_ = 0; |
||||||
|
this.buff_ = (size > BuffSz_) ? new byte[size] : new byte[BuffSz_]; |
||||||
|
this.maxHi_ = (long) BuffSz_; |
||||||
|
this.hitEOF_ = false; |
||||||
|
this.diskPos_ = 0L; |
||||||
|
} |
||||||
|
|
||||||
|
public void close() throws IOException { |
||||||
|
this.flush(); |
||||||
|
this.closed_ = true; |
||||||
|
super.close(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Flush any bytes in the file's buffer that have not yet been written to |
||||||
|
* disk. If the file was created read-only, this method is a no-op. |
||||||
|
*/ |
||||||
|
public void flush() throws IOException { |
||||||
|
this.flushBuffer(); |
||||||
|
} |
||||||
|
|
||||||
|
/* Flush any dirty bytes in the buffer to disk. */ |
||||||
|
private void flushBuffer() throws IOException { |
||||||
|
if (this.dirty_) { |
||||||
|
if (this.diskPos_ != this.lo_) super.seek(this.lo_); |
||||||
|
int len = (int) (this.curr_ - this.lo_); |
||||||
|
super.write(this.buff_, 0, len); |
||||||
|
this.diskPos_ = this.curr_; |
||||||
|
this.dirty_ = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Read at most "this.buff.length" bytes into "this.buff", returning the |
||||||
|
* number of bytes read. If the return result is less than |
||||||
|
* "this.buff.length", then EOF was read. |
||||||
|
*/ |
||||||
|
private int fillBuffer() throws IOException { |
||||||
|
int cnt = 0; |
||||||
|
int rem = this.buff_.length; |
||||||
|
while (rem > 0) { |
||||||
|
int n = super.read(this.buff_, cnt, rem); |
||||||
|
if (n < 0) break; |
||||||
|
cnt += n; |
||||||
|
rem -= n; |
||||||
|
} |
||||||
|
if ((cnt < 0) && (this.hitEOF_ = (cnt < this.buff_.length))) { |
||||||
|
// make sure buffer that wasn't read is initialized with -1
|
||||||
|
Arrays.fill(this.buff_, cnt, this.buff_.length, (byte) 0xff); |
||||||
|
} |
||||||
|
this.diskPos_ += cnt; |
||||||
|
return cnt; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* This method positions <code>this.curr</code> at position <code>pos</code>. |
||||||
|
* If <code>pos</code> does not fall in the current buffer, it flushes the |
||||||
|
* current buffer and loads the correct one.<p> |
||||||
|
* |
||||||
|
* On exit from this routine <code>this.curr == this.hi</code> iff <code>pos</code> |
||||||
|
* is at or past the end-of-file, which can only happen if the file was |
||||||
|
* opened in read-only mode. |
||||||
|
*/ |
||||||
|
public void seek(long pos) throws IOException { |
||||||
|
if (pos >= this.hi_ || pos < this.lo_) { |
||||||
|
// seeking outside of current buffer -- flush and read
|
||||||
|
this.flushBuffer(); |
||||||
|
this.lo_ = pos & BuffMask_; // start at BuffSz boundary
|
||||||
|
this.maxHi_ = this.lo_ + (long) this.buff_.length; |
||||||
|
if (this.diskPos_ != this.lo_) { |
||||||
|
super.seek(this.lo_); |
||||||
|
this.diskPos_ = this.lo_; |
||||||
|
} |
||||||
|
int n = this.fillBuffer(); |
||||||
|
this.hi_ = this.lo_ + (long) n; |
||||||
|
} else { |
||||||
|
// seeking inside current buffer -- no read required
|
||||||
|
if (pos < this.curr_) { |
||||||
|
// if seeking backwards, we must flush to maintain V4
|
||||||
|
this.flushBuffer(); |
||||||
|
} |
||||||
|
} |
||||||
|
this.curr_ = pos; |
||||||
|
} |
||||||
|
|
||||||
|
public long getFilePointer() { |
||||||
|
return this.curr_; |
||||||
|
} |
||||||
|
|
||||||
|
public long length() throws IOException { |
||||||
|
return Math.max(this.curr_, super.length()); |
||||||
|
} |
||||||
|
|
||||||
|
public int read() throws IOException { |
||||||
|
if (this.curr_ >= this.hi_) { |
||||||
|
// test for EOF
|
||||||
|
// if (this.hi < this.maxHi) return -1;
|
||||||
|
if (this.hitEOF_) return -1; |
||||||
|
|
||||||
|
// slow path -- read another buffer
|
||||||
|
this.seek(this.curr_); |
||||||
|
if (this.curr_ == this.hi_) return -1; |
||||||
|
} |
||||||
|
byte res = this.buff_[(int) (this.curr_ - this.lo_)]; |
||||||
|
this.curr_++; |
||||||
|
return ((int) res) & 0xFF; // convert byte -> int
|
||||||
|
} |
||||||
|
|
||||||
|
public int read(byte[] b) throws IOException { |
||||||
|
return this.read(b, 0, b.length); |
||||||
|
} |
||||||
|
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException { |
||||||
|
if (this.curr_ >= this.hi_) { |
||||||
|
// test for EOF
|
||||||
|
// if (this.hi < this.maxHi) return -1;
|
||||||
|
if (this.hitEOF_) return -1; |
||||||
|
|
||||||
|
// slow path -- read another buffer
|
||||||
|
this.seek(this.curr_); |
||||||
|
if (this.curr_ == this.hi_) return -1; |
||||||
|
} |
||||||
|
len = Math.min(len, (int) (this.hi_ - this.curr_)); |
||||||
|
int buffOff = (int) (this.curr_ - this.lo_); |
||||||
|
System.arraycopy(this.buff_, buffOff, b, off, len); |
||||||
|
this.curr_ += len; |
||||||
|
return len; |
||||||
|
} |
||||||
|
|
||||||
|
public void write(int b) throws IOException { |
||||||
|
if (this.curr_ >= this.hi_) { |
||||||
|
if (this.hitEOF_ && this.hi_ < this.maxHi_) { |
||||||
|
// at EOF -- bump "hi"
|
||||||
|
this.hi_++; |
||||||
|
} else { |
||||||
|
// slow path -- write current buffer; read next one
|
||||||
|
this.seek(this.curr_); |
||||||
|
if (this.curr_ == this.hi_) { |
||||||
|
// appending to EOF -- bump "hi"
|
||||||
|
this.hi_++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
this.buff_[(int) (this.curr_ - this.lo_)] = (byte) b; |
||||||
|
this.curr_++; |
||||||
|
this.dirty_ = true; |
||||||
|
} |
||||||
|
|
||||||
|
public void write(byte[] b) throws IOException { |
||||||
|
this.write(b, 0, b.length); |
||||||
|
} |
||||||
|
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException { |
||||||
|
while (len > 0) { |
||||||
|
int n = this.writeAtMost(b, off, len); |
||||||
|
off += n; |
||||||
|
len -= n; |
||||||
|
this.dirty_ = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Write at most "len" bytes to "b" starting at position "off", and return |
||||||
|
* the number of bytes written. |
||||||
|
*/ |
||||||
|
private int writeAtMost(byte[] b, int off, int len) throws IOException { |
||||||
|
if (this.curr_ >= this.hi_) { |
||||||
|
if (this.hitEOF_ && this.hi_ < this.maxHi_) { |
||||||
|
// at EOF -- bump "hi"
|
||||||
|
this.hi_ = this.maxHi_; |
||||||
|
} else { |
||||||
|
// slow path -- write current buffer; read next one
|
||||||
|
this.seek(this.curr_); |
||||||
|
if (this.curr_ == this.hi_) { |
||||||
|
// appending to EOF -- bump "hi"
|
||||||
|
this.hi_ = this.maxHi_; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
len = Math.min(len, (int) (this.hi_ - this.curr_)); |
||||||
|
int buffOff = (int) (this.curr_ - this.lo_); |
||||||
|
System.arraycopy(b, off, this.buff_, buffOff, len); |
||||||
|
this.curr_ += len; |
||||||
|
return len; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
/* |
||||||
|
* 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.util; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Aria.Lao on 2017/1/11. |
||||||
|
*/ |
||||||
|
|
||||||
|
public class CAConfiguration { |
||||||
|
public static String CA_PATH, CA_ALIAS; |
||||||
|
} |
@ -0,0 +1,131 @@ |
|||||||
|
/* |
||||||
|
* 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.util; |
||||||
|
|
||||||
|
import android.text.TextUtils; |
||||||
|
import com.arialyy.aria.core.DownloadManager; |
||||||
|
import java.io.BufferedInputStream; |
||||||
|
import java.io.FileInputStream; |
||||||
|
import java.io.FileNotFoundException; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.security.KeyManagementException; |
||||||
|
import java.security.KeyStore; |
||||||
|
import java.security.KeyStoreException; |
||||||
|
import java.security.NoSuchAlgorithmException; |
||||||
|
import java.security.SecureRandom; |
||||||
|
import java.security.UnrecoverableKeyException; |
||||||
|
import java.security.cert.Certificate; |
||||||
|
import java.security.cert.CertificateException; |
||||||
|
import java.security.cert.CertificateFactory; |
||||||
|
import java.security.cert.X509Certificate; |
||||||
|
import javax.net.ssl.HostnameVerifier; |
||||||
|
import javax.net.ssl.KeyManagerFactory; |
||||||
|
import javax.net.ssl.SSLContext; |
||||||
|
import javax.net.ssl.SSLSession; |
||||||
|
import javax.net.ssl.TrustManager; |
||||||
|
import javax.net.ssl.TrustManagerFactory; |
||||||
|
import javax.net.ssl.X509TrustManager; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Aria.Lao on 2017/1/11. |
||||||
|
*/ |
||||||
|
|
||||||
|
public class SSLContextUtil { |
||||||
|
|
||||||
|
/** |
||||||
|
* 颁发服务器证书的 CA 未知 |
||||||
|
* |
||||||
|
* @param caAlias CA证书别名 |
||||||
|
* @param caPath 保存在assets目录下的CA证书完整路径 |
||||||
|
*/ |
||||||
|
public static SSLContext getSSLContext(String caAlias, String caPath) { |
||||||
|
if (TextUtils.isEmpty(caAlias) || TextUtils.isEmpty(caPath)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
// Load CAs from an InputStream
|
||||||
|
// (could be from a resource or ByteArrayInputStream or ...)
|
||||||
|
CertificateFactory cf = null; |
||||||
|
try { |
||||||
|
cf = CertificateFactory.getInstance("X.509"); |
||||||
|
InputStream caInput = DownloadManager.APP.getAssets().open(caPath); |
||||||
|
Certificate ca; |
||||||
|
ca = cf.generateCertificate(caInput); |
||||||
|
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); |
||||||
|
|
||||||
|
// Create a KeyStore containing our trusted CAs
|
||||||
|
String keyStoreType = KeyStore.getDefaultType(); |
||||||
|
KeyStore keyStore = KeyStore.getInstance(keyStoreType); |
||||||
|
keyStore.load(null, null); |
||||||
|
keyStore.setCertificateEntry(caAlias, ca); |
||||||
|
|
||||||
|
// Create a TrustManager that trusts the CAs in our KeyStore
|
||||||
|
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); |
||||||
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); |
||||||
|
tmf.init(keyStore); |
||||||
|
KeyManagerFactory kmf = |
||||||
|
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); |
||||||
|
kmf.init(keyStore, null); |
||||||
|
|
||||||
|
// Create an SSLContext that uses our TrustManager
|
||||||
|
SSLContext context = SSLContext.getInstance("TLS"); |
||||||
|
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); |
||||||
|
return context; |
||||||
|
} catch (CertificateException | NoSuchAlgorithmException | IOException | KeyStoreException | KeyManagementException | UnrecoverableKeyException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 服务器证书不是由 CA 签署的,而是自签署时,获取默认的SSL |
||||||
|
*/ |
||||||
|
public static SSLContext getDefaultSLLContext() { |
||||||
|
SSLContext sslContext = null; |
||||||
|
try { |
||||||
|
sslContext = SSLContext.getInstance("TLS"); |
||||||
|
sslContext.init(null, new TrustManager[] { trustManagers }, new SecureRandom()); |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
return sslContext; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 创建自己的 TrustManager,这次直接信任服务器证书。这种方法具有前面所述的将应用与证书直接关联的所有弊端,但可以安全地操作。 |
||||||
|
*/ |
||||||
|
private static TrustManager trustManagers = new X509TrustManager() { |
||||||
|
|
||||||
|
@Override public void checkClientTrusted(X509Certificate[] chain, String authType) |
||||||
|
throws CertificateException { |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void checkServerTrusted(X509Certificate[] chain, String authType) |
||||||
|
throws CertificateException { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override public X509Certificate[] getAcceptedIssuers() { |
||||||
|
return new X509Certificate[0]; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public static final HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() { |
||||||
|
public boolean verify(String hostname, SSLSession session) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,98 @@ |
|||||||
|
package com.arialyy.simple.notification; |
||||||
|
|
||||||
|
import android.app.NotificationManager; |
||||||
|
import android.content.Context; |
||||||
|
import android.os.Environment; |
||||||
|
import android.support.v4.app.NotificationCompat; |
||||||
|
import com.arialyy.aria.core.Aria; |
||||||
|
import com.arialyy.aria.core.task.Task; |
||||||
|
import com.arialyy.frame.util.show.L; |
||||||
|
import com.arialyy.frame.util.show.T; |
||||||
|
import com.arialyy.simple.R; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Aria.Lao on 2017/1/18. |
||||||
|
*/ |
||||||
|
|
||||||
|
public class SimpleNotification { |
||||||
|
private static final String DOWNLOAD_URL = |
||||||
|
"http://static.gaoshouyou.com/d/6e/e5/ff6ecaaf45e532e6d07747af82357472.apk"; |
||||||
|
|
||||||
|
private NotificationManager mManager; |
||||||
|
private Context mContext; |
||||||
|
private NotificationCompat.Builder mBuilder; |
||||||
|
private static final int mNotifiyId = 0; |
||||||
|
|
||||||
|
public SimpleNotification(Context context) { |
||||||
|
mContext = context; |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
private void init() { |
||||||
|
mManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); |
||||||
|
mBuilder = new NotificationCompat.Builder(mContext); |
||||||
|
mBuilder.setContentTitle("Aria Download Test") |
||||||
|
.setContentText("进度条") |
||||||
|
.setProgress(100, 0, false) |
||||||
|
.setSmallIcon(R.mipmap.ic_launcher); |
||||||
|
mManager.notify(mNotifiyId, mBuilder.build()); |
||||||
|
Aria.whit(mContext).addSchedulerListener(new DownloadCallback(mBuilder, mManager)); |
||||||
|
} |
||||||
|
|
||||||
|
public void start() { |
||||||
|
Aria.whit(mContext) |
||||||
|
.load(DOWNLOAD_URL) |
||||||
|
.setDownloadName("notification_test.apk") |
||||||
|
.setDownloadPath( |
||||||
|
Environment.getExternalStorageDirectory() + "/Download/notification_test.apk") |
||||||
|
.start(); |
||||||
|
} |
||||||
|
|
||||||
|
public void stop() { |
||||||
|
Aria.whit(mContext).load(DOWNLOAD_URL).stop(); |
||||||
|
} |
||||||
|
|
||||||
|
private static class DownloadCallback extends Aria.SimpleSchedulerListener { |
||||||
|
NotificationCompat.Builder mBuilder; |
||||||
|
NotificationManager mManager; |
||||||
|
|
||||||
|
private DownloadCallback(NotificationCompat.Builder builder, NotificationManager manager) { |
||||||
|
mBuilder = builder; |
||||||
|
mManager = manager; |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void onTaskStart(Task task) { |
||||||
|
super.onTaskStart(task); |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void onTaskPre(Task task) { |
||||||
|
super.onTaskPre(task); |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void onTaskStop(Task task) { |
||||||
|
super.onTaskStop(task); |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void onTaskRunning(Task task) { |
||||||
|
super.onTaskRunning(task); |
||||||
|
long len = task.getFileSize(); |
||||||
|
int p = (int) (task.getCurrentProgress() * 100 / len); |
||||||
|
if (mBuilder != null) { |
||||||
|
mBuilder.setProgress(100, p, false); |
||||||
|
mManager.notify(mNotifiyId, mBuilder.build()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void onTaskComplete(Task task) { |
||||||
|
super.onTaskComplete(task); |
||||||
|
if (mBuilder != null) { |
||||||
|
mBuilder.setProgress(100, 100, false); |
||||||
|
mManager.notify(mNotifiyId, mBuilder.build()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void onTaskCancel(Task task) { |
||||||
|
super.onTaskCancel(task); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue