Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
G
g4proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
g4proxy
Commits
5b994bca
Commit
5b994bca
authored
May 16, 2019
by
liuzhaoce
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
DownloadManager
parent
34c772a9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
1750 additions
and
87 deletions
+1750
-87
build.gradle
app/build.gradle
+15
-3
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+5
-2
MainActivity.java
app/src/main/java/com/virjar/g4proxy/MainActivity.java
+5
-13
DownLoadFileInfo.java
...in/java/com/virjar/g4proxy/download/DownLoadFileInfo.java
+56
-0
DownLoadListener.java
...in/java/com/virjar/g4proxy/download/DownLoadListener.java
+48
-0
DownLoadManager.java
...ain/java/com/virjar/g4proxy/download/DownLoadManager.java
+436
-0
DownLoadService.java
...ain/java/com/virjar/g4proxy/download/DownLoadService.java
+55
-0
DownLoader.java
...src/main/java/com/virjar/g4proxy/download/DownLoader.java
+464
-0
TaskInfo.java
app/src/main/java/com/virjar/g4proxy/download/TaskInfo.java
+68
-0
DataKeeper.java
...ava/com/virjar/g4proxy/download/dbcontrol/DataKeeper.java
+154
-0
FileHelper.java
...ava/com/virjar/g4proxy/download/dbcontrol/FileHelper.java
+168
-0
SQLiteHelper.java
...a/com/virjar/g4proxy/download/dbcontrol/SQLiteHelper.java
+66
-0
SQLDownLoadInfo.java
...rjar/g4proxy/download/dbcontrol/bean/SQLDownLoadInfo.java
+66
-0
SchedulerTaskService.java
...java/com/virjar/g4proxy/service/SchedulerTaskService.java
+5
-5
DeviceInfoHolder.java
.../main/java/com/virjar/g4proxy/utils/DeviceInfoHolder.java
+3
-3
DeviceMessageUtils.java
...ain/java/com/virjar/g4proxy/utils/DeviceMessageUtils.java
+3
-3
AutoInstaller.java
...ain/java/top/wuhaojie/installerlibrary/AutoInstaller.java
+133
-58
No files found.
app/build.gradle
View file @
5b994bca
...
...
@@ -6,8 +6,8 @@ android {
applicationId
"com.tencent.mm"
minSdkVersion
19
targetSdkVersion
26
versionCode
23
versionName
"1.
23
"
versionCode
6
versionName
"1.
6
"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled
true
...
...
@@ -44,6 +44,17 @@ android {
jniLibs
.
srcDir
'libs'
}
}
//在apk文件后边生成版本号信息
android
.
applicationVariants
.
all
{
variant
->
variant
.
outputs
.
all
{
outputFileName
=
"g4proxy_${defaultConfig.versionName}_${releaseTime()}.apk"
}
}
}
def
releaseTime
()
{
return
new
Date
().
format
(
"yyyyMMdd"
,
TimeZone
.
getTimeZone
(
"UTC"
))
}
dependencies
{
...
...
@@ -55,6 +66,7 @@ dependencies {
api
'com.squareup.okhttp3:okhttp:3.10.0'
implementation
'commons-io:commons-io:2.6'
implementation
'com.alibaba:fastjson:1.2.10'
implementation
'net.dongliu:apk-parser:2.6.2'
//短信收发
api
'ir.mtajik.android:advancedsmsmanager:1.1.0'
api
'com.google.dagger:dagger:2.7'
...
...
@@ -66,7 +78,7 @@ dependencies {
compile
files
(
'libs/BaiduLBS_Android.jar'
)
api
'com.github.tony19:logback-android:1.3.0-2'
// compileOnly
'org.projectlombok:lombok:1.18.2'
// implementation
'org.projectlombok:lombok:1.18.2'
//引入netty之后,class直接就爆炸了。考虑实现API精简
implementation
'com.android.support:multidex:1.0.3'
...
...
app/src/main/AndroidManifest.xml
View file @
5b994bca
...
...
@@ -28,11 +28,12 @@
<uses-permission
android:name=
"android.permission.SEND_SMS"
/>
<!-- 辅助功能权限 -->
<uses-permission
android:name=
"android.permission.BIND_ACCESSIBILITY_SERVICE"
/>
<uses-permission
android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"
/>
<uses-permission
android:name=
"android.permission.BIND_ACCESSIBILITY_SERVICE"
/>
<uses-permission
android:name=
"android.permission.READ_EXTERNAL_STORAGE"
/>
<uses-permission
android:name=
"android.permission.REQUEST_INSTALL_PACKAGES"
/>
<uses-permission
android:name=
"android.permission.REQUEST_INSTALL_PACKAGES"
/>
<uses-permission
android:name=
"android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"
/>
<uses-permission
android:name=
"android.permission.ACCESS_DOWNLOAD_MANAGER"
/>
<application
android:allowBackup=
"true"
...
...
@@ -71,6 +72,8 @@
<category
android:name=
"android.intent.category.DEFAULT"
/>
</intent-filter>
</service>
<!--利用DownloadManager 断点续传-->
<service
android:name=
"com.virjar.g4proxy.download.DownLoadService"
/>
<!--开机自启服务-->
<receiver
...
...
app/src/main/java/com/virjar/g4proxy/MainActivity.java
View file @
5b994bca
...
...
@@ -2,30 +2,21 @@ package com.virjar.g4proxy;
import
android.content.Intent
;
import
android.os.Bundle
;
import
android.provider.Settings
;
import
android.support.annotation.NonNull
;
import
android.support.v7.app.AppCompatActivity
;
import
android.util.Log
;
import
android.view.View
;
import
android.widget.Button
;
import
android.widget.TextView
;
import
com.tencent.mm.R
;
import
com.virjar.g4proxy.download.DownLoadService
;
import
com.virjar.g4proxy.service.SchedulerTaskService
;
import
com.virjar.g4proxy.utils.BDLocationUtils
;
import
com.virjar.g4proxy.utils.DeviceInfoHolder
;
import
com.virjar.g4proxy.utils.DeviceMessageUtil
;
import
com.virjar.g4proxy.utils.HttpClientUtils
;
import
com.virjar.g4proxy.utils.DeviceMessageUtils
;
import
org.json.JSONObject
;
import
java.io.IOException
;
import
okhttp3.Call
;
import
okhttp3.Callback
;
import
okhttp3.Request
;
import
okhttp3.Response
;
import
okhttp3.ResponseBody
;
import
top.wuhaojie.installerlibrary.AutoInstaller
;
public
class
MainActivity
extends
AppCompatActivity
implements
View
.
OnClickListener
{
...
...
@@ -52,6 +43,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
startService
(
new
Intent
(
this
,
SchedulerTaskService
.
class
));
startService
(
new
Intent
(
this
,
HttpProxyService
.
class
));
startService
(
new
Intent
(
this
,
DownLoadService
.
class
));
AutoInstaller
.
getDefault
(
this
).
autoConfigAccessibilitySetting
(
this
);
}
...
...
@@ -74,9 +66,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
public
void
onClick
(
View
v
)
{
if
(
v
.
getId
()
==
R
.
id
.
btn_report
)
{
//待上传的设备信息:devicesMsg
JSONObject
deviceMsg
=
DeviceMessageUtil
.
getDeviceMessage
(
this
);
JSONObject
deviceMsg
=
DeviceMessageUtil
s
.
getDeviceMessage
(
this
);
textView
.
setText
(
deviceMsg
.
toString
());
//
textView.setText(deviceMsg.toString());
textView
.
setText
(
SchedulerTaskService
.
msgReportlUrl
);
textView
.
append
(
"\r\n"
+
deviceMsg
);
...
...
app/src/main/java/com/virjar/g4proxy/download/DownLoadFileInfo.java
0 → 100644
View file @
5b994bca
package
com
.
virjar
.
g4proxy
.
download
;
/**
* 类功能描述:</br>
*
* @author zhuiji7
* @email 470508081@qq.com
* @version 1.0
* </p>
*/
public
class
DownLoadFileInfo
{
private
String
url
;
private
String
fileID
;
private
String
fileName
;
private
String
filePath
;
private
long
fileSize
;
private
String
fileType
;
public
String
getUrl
()
{
return
url
;
}
public
void
setUrl
(
String
url
)
{
this
.
url
=
url
;
}
public
String
getFileID
()
{
return
fileID
;
}
public
void
setFileID
(
String
fileID
)
{
this
.
fileID
=
fileID
;
}
public
String
getFileName
()
{
return
fileName
;
}
public
void
setFileName
(
String
fileName
)
{
this
.
fileName
=
fileName
;
}
public
String
getFilePath
()
{
return
filePath
;
}
public
void
setFilePath
(
String
filePath
)
{
this
.
filePath
=
filePath
;
}
public
long
getFileSize
()
{
return
fileSize
;
}
public
void
setFileSize
(
long
fileSize
)
{
this
.
fileSize
=
fileSize
;
}
public
String
getFileType
()
{
return
fileType
;
}
public
void
setFileType
(
String
fileType
)
{
this
.
fileType
=
fileType
;
}
}
app/src/main/java/com/virjar/g4proxy/download/DownLoadListener.java
0 → 100644
View file @
5b994bca
package
com
.
virjar
.
g4proxy
.
download
;
import
com.virjar.g4proxy.download.dbcontrol.bean.SQLDownLoadInfo
;
/**
* 类功能描述:</br>
*
* @author zhuiji7
* @email 470508081@qq.com
* @version 1.0
* </p>
*/
public
interface
DownLoadListener
{
/**
* (开始下载文件)
* @param sqlDownLoadInfo 下载任务对象
*/
public
void
onStart
(
SQLDownLoadInfo
sqlDownLoadInfo
);
/**
* (文件下载进度情况)
* @param sqlDownLoadInfo 下载任务对象
* @param isSupportBreakpoint 服务器是否支持断点续传
*/
public
void
onProgress
(
SQLDownLoadInfo
sqlDownLoadInfo
,
boolean
isSupportBreakpoint
);
/**
* (停止下载完毕)
* @param sqlDownLoadInfo 下载任务对象
* @param isSupportBreakpoint 服务器是否支持断点续传
*/
public
void
onStop
(
SQLDownLoadInfo
sqlDownLoadInfo
,
boolean
isSupportBreakpoint
);
/**
* (文件下载失败)
* @param sqlDownLoadInfo 下载任务对象
*/
public
void
onError
(
SQLDownLoadInfo
sqlDownLoadInfo
);
/**
* (文件下载成功)
* @param sqlDownLoadInfo 下载任务对象
*/
public
void
onSuccess
(
SQLDownLoadInfo
sqlDownLoadInfo
);
}
app/src/main/java/com/virjar/g4proxy/download/DownLoadManager.java
0 → 100644
View file @
5b994bca
This diff is collapsed.
Click to expand it.
app/src/main/java/com/virjar/g4proxy/download/DownLoadService.java
0 → 100644
View file @
5b994bca
package
com
.
virjar
.
g4proxy
.
download
;
import
android.app.Service
;
import
android.content.Intent
;
import
android.os.IBinder
;
/**
* 类功能描述:下载器后台服务</br>
*
* @author zhuiji7 (470508081@qq.com)
* @version 1.0
* </p>
*/
public
class
DownLoadService
extends
Service
{
private
static
DownLoadManager
downLoadManager
;
@Override
public
IBinder
onBind
(
Intent
intent
)
{
// TODO Auto-generated method stub
return
null
;
}
public
static
DownLoadManager
getDownLoadManager
(){
return
downLoadManager
;
}
@Override
public
void
onCreate
()
{
super
.
onCreate
();
downLoadManager
=
new
DownLoadManager
(
DownLoadService
.
this
);
}
@Override
public
void
onDestroy
()
{
super
.
onDestroy
();
//释放downLoadManager
downLoadManager
.
stopAllTask
();
downLoadManager
=
null
;
}
@Override
public
void
onStart
(
Intent
intent
,
int
startId
)
{
super
.
onStart
(
intent
,
startId
);
if
(
downLoadManager
==
null
){
downLoadManager
=
new
DownLoadManager
(
DownLoadService
.
this
);
}
}
}
app/src/main/java/com/virjar/g4proxy/download/DownLoader.java
0 → 100644
View file @
5b994bca
This diff is collapsed.
Click to expand it.
app/src/main/java/com/virjar/g4proxy/download/TaskInfo.java
0 → 100644
View file @
5b994bca
package
com
.
virjar
.
g4proxy
.
download
;
/**
* 类功能描述:</br>
*
* @author zhuiji7
* @email 470508081@qq.com
* @version 1.0
* </p>
*/
public
class
TaskInfo
{
private
boolean
isOnDownloading
;
private
String
taskID
;
private
String
fileName
;
private
long
fileSize
=
0
;
private
long
downFileSize
=
0
;
public
boolean
isOnDownloading
()
{
return
isOnDownloading
;
}
public
void
setOnDownloading
(
boolean
isOnDownloading
)
{
this
.
isOnDownloading
=
isOnDownloading
;
}
public
int
getProgress
()
{
if
(
fileSize
==
0
){
return
0
;
}
else
{
return
((
int
)(
100
*
downFileSize
/
fileSize
));
}
}
public
String
getTaskID
()
{
return
taskID
;
}
public
void
setTaskID
(
String
taskID
)
{
this
.
taskID
=
taskID
;
}
public
String
getFileName
()
{
return
fileName
;
}
public
void
setFileName
(
String
fileName
)
{
this
.
fileName
=
fileName
;
}
public
String
getType
(){
String
type
=
null
;
if
(
fileName
!=
null
){
String
name
=
fileName
.
toLowerCase
();
if
(
name
.
contains
(
"."
))
{
type
=
name
.
substring
(
name
.
lastIndexOf
(
"."
),
name
.
length
());
}
}
return
type
;
}
public
long
getFileSize
()
{
return
fileSize
;
}
public
void
setFileSize
(
long
fileSize
)
{
this
.
fileSize
=
fileSize
;
}
public
long
getDownFileSize
()
{
return
downFileSize
;
}
public
void
setDownFileSize
(
long
downFileSize
)
{
this
.
downFileSize
=
downFileSize
;
}
}
app/src/main/java/com/virjar/g4proxy/download/dbcontrol/DataKeeper.java
0 → 100644
View file @
5b994bca
package
com
.
virjar
.
g4proxy
.
download
.
dbcontrol
;
import
android.content.ContentValues
;
import
android.content.Context
;
import
android.database.Cursor
;
import
android.database.sqlite.SQLiteDatabase
;
import
com.virjar.g4proxy.download.dbcontrol.bean.SQLDownLoadInfo
;
import
java.util.ArrayList
;
/**
* 类功能描述:信息存储类,主要在任务下载各个环节执行数据的存储</br>
*
* @author zhuiji7
* @email 470508081@qq.com
* @version 1.0
* </p>
*/
public
class
DataKeeper
{
private
SQLiteHelper
dbhelper
;
private
SQLiteDatabase
db
;
private
int
doSaveTimes
=
0
;
public
DataKeeper
(
Context
context
){
this
.
dbhelper
=
new
SQLiteHelper
(
context
);
}
/**
* (保存一个任务的下载信息到数据库)
* @param downloadInfo
*/
public
void
saveDownLoadInfo
(
SQLDownLoadInfo
downloadInfo
){
ContentValues
cv
=
new
ContentValues
();
cv
.
put
(
"userID"
,
downloadInfo
.
getUserID
());
cv
.
put
(
"taskID"
,
downloadInfo
.
getTaskID
());
cv
.
put
(
"downLoadSize"
,
downloadInfo
.
getDownloadSize
());
cv
.
put
(
"fileName"
,
downloadInfo
.
getFileName
());
cv
.
put
(
"filePath"
,
downloadInfo
.
getFilePath
());
cv
.
put
(
"fileSize"
,
downloadInfo
.
getFileSize
());
cv
.
put
(
"url"
,
downloadInfo
.
getUrl
());
Cursor
cursor
=
null
;
try
{
db
=
dbhelper
.
getWritableDatabase
();
cursor
=
db
.
rawQuery
(
"SELECT * from "
+
SQLiteHelper
.
TABLE_NAME
+
" WHERE userID = ? AND taskID = ? "
,
new
String
[]{
downloadInfo
.
getUserID
(),
downloadInfo
.
getTaskID
()});
if
(
cursor
.
moveToNext
()){
db
.
update
(
SQLiteHelper
.
TABLE_NAME
,
cv
,
"userID = ? AND taskID = ? "
,
new
String
[]{
downloadInfo
.
getUserID
(),
downloadInfo
.
getTaskID
()});
}
else
{
db
.
insert
(
SQLiteHelper
.
TABLE_NAME
,
null
,
cv
);
}
cursor
.
close
();
db
.
close
();
}
catch
(
Exception
e
){
doSaveTimes
++;
if
(
doSaveTimes
<
5
){
//最多只做5次数据保存,降低数据保存失败率
saveDownLoadInfo
(
downloadInfo
);
}
else
{
doSaveTimes
=
0
;
}
if
(
cursor
!=
null
){
cursor
.
close
();
}
if
(
db
!=
null
){
db
.
close
();
}
}
doSaveTimes
=
0
;
}
public
SQLDownLoadInfo
getDownLoadInfo
(
String
userID
,
String
taskID
){
SQLDownLoadInfo
downloadinfo
=
null
;
db
=
dbhelper
.
getWritableDatabase
();
Cursor
cursor
=
db
.
rawQuery
(
"SELECT * from "
+
SQLiteHelper
.
TABLE_NAME
+
"WHERE userID = ? AND taskID = ? "
,
new
String
[]{
userID
,
taskID
});
if
(
cursor
.
moveToNext
()){
downloadinfo
=
new
SQLDownLoadInfo
();
downloadinfo
.
setDownloadSize
(
cursor
.
getLong
(
cursor
.
getColumnIndex
(
"downLoadSize"
)));
downloadinfo
.
setFileName
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"fileName"
)));
downloadinfo
.
setFilePath
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"filePath"
)));
downloadinfo
.
setFileSize
(
cursor
.
getLong
(
cursor
.
getColumnIndex
(
"fileSize"
)));
downloadinfo
.
setUrl
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"url"
)));
downloadinfo
.
setTaskID
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"taskID"
)));
downloadinfo
.
setUserID
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"userID"
)));
}
cursor
.
close
();
db
.
close
();
return
downloadinfo
;
}
public
ArrayList
<
SQLDownLoadInfo
>
getAllDownLoadInfo
(){
ArrayList
<
SQLDownLoadInfo
>
downloadinfoList
=
new
ArrayList
<
SQLDownLoadInfo
>();
db
=
dbhelper
.
getWritableDatabase
();
Cursor
cursor
=
db
.
rawQuery
(
"SELECT * from "
+
SQLiteHelper
.
TABLE_NAME
,
null
);
while
(
cursor
.
moveToNext
()){
SQLDownLoadInfo
downloadinfo
=
new
SQLDownLoadInfo
();
downloadinfo
.
setDownloadSize
(
cursor
.
getLong
(
cursor
.
getColumnIndex
(
"downLoadSize"
)));
downloadinfo
.
setFileName
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"fileName"
)));
downloadinfo
.
setFilePath
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"filePath"
)));
downloadinfo
.
setFileSize
(
cursor
.
getLong
(
cursor
.
getColumnIndex
(
"fileSize"
)));
downloadinfo
.
setUrl
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"url"
)));
downloadinfo
.
setTaskID
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"taskID"
)));
downloadinfo
.
setUserID
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"userID"
)));
downloadinfoList
.
add
(
downloadinfo
);
}
cursor
.
close
();
db
.
close
();
return
downloadinfoList
;
}
public
ArrayList
<
SQLDownLoadInfo
>
getUserDownLoadInfo
(
String
userID
){
ArrayList
<
SQLDownLoadInfo
>
downloadinfoList
=
new
ArrayList
<
SQLDownLoadInfo
>();
db
=
dbhelper
.
getWritableDatabase
();
try
{
Cursor
cursor
=
null
;
cursor
=
db
.
rawQuery
(
"SELECT * from "
+
SQLiteHelper
.
TABLE_NAME
+
" WHERE userID = '"
+
userID
+
"'"
,
null
);
while
(
cursor
.
moveToNext
()){
SQLDownLoadInfo
downloadinfo
=
new
SQLDownLoadInfo
();
downloadinfo
.
setDownloadSize
(
cursor
.
getLong
(
cursor
.
getColumnIndex
(
"downLoadSize"
)));
downloadinfo
.
setFileName
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"fileName"
)));
downloadinfo
.
setFilePath
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"filePath"
)));
downloadinfo
.
setFileSize
(
cursor
.
getLong
(
cursor
.
getColumnIndex
(
"fileSize"
)));
downloadinfo
.
setUrl
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"url"
)));
downloadinfo
.
setTaskID
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"taskID"
)));
downloadinfo
.
setUserID
(
cursor
.
getString
(
cursor
.
getColumnIndex
(
"userID"
)));
downloadinfoList
.
add
(
downloadinfo
);
}
cursor
.
close
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
db
.
close
();
return
downloadinfoList
;
}
public
void
deleteDownLoadInfo
(
String
userID
,
String
taskID
){
db
=
dbhelper
.
getWritableDatabase
();
db
.
delete
(
SQLiteHelper
.
TABLE_NAME
,
"userID = ? AND taskID = ? "
,
new
String
[]{
userID
,
taskID
});
db
.
close
();
}
public
void
deleteUserDownLoadInfo
(
String
userID
){
db
=
dbhelper
.
getWritableDatabase
();
db
.
delete
(
SQLiteHelper
.
TABLE_NAME
,
"userID = ? "
,
new
String
[]{
userID
});
db
.
close
();
}
public
void
deleteAllDownLoadInfo
(){
db
=
dbhelper
.
getWritableDatabase
();
db
.
delete
(
SQLiteHelper
.
TABLE_NAME
,
null
,
null
);
db
.
close
();
}
}
app/src/main/java/com/virjar/g4proxy/download/dbcontrol/FileHelper.java
0 → 100644
View file @
5b994bca
package
com
.
virjar
.
g4proxy
.
download
.
dbcontrol
;
import
android.os.Environment
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.List
;
/**
* 类功能描述:文件操作辅助类</br>
*
* @author zhuiji7
* @email 470508081@qq.com
* @version 1.0
* </p>
*/
public
class
FileHelper
{
private
static
String
baseFilePath
=
Environment
.
getExternalStorageDirectory
().
getAbsolutePath
()
+
File
.
separator
;
private
static
String
dowloadFilePath
=
baseFilePath
+
"Download"
;
/**下载文件的临时路径*/
private
static
String
tempDirPath
=
baseFilePath
+
"/TempDir"
;
private
static
String
[]
wrongChars
=
{
"/"
,
"\\\\"
,
"\\*"
,
"\\?"
,
"<"
,
">"
,
"\""
,
"|"
};
// 创建文件
public
void
newFile
(
File
f
)
{
if
(!
f
.
exists
())
{
try
{
f
.
createNewFile
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
/**创建目录
* @param
* */
public
static
void
newDirFile
(
File
f
)
{
if
(!
f
.
exists
())
{
f
.
mkdirs
();
}
}
// 获取一个文件列表的里的总文件大小
public
static
double
getSize
(
List
<
String
>
willupload
)
{
return
(
double
)
getSizeUnitByte
(
willupload
)
/
(
1024
*
1024
);
};
/**
* 计算文件的大小,单位是字节
* @param willupload
* @return
*/
public
static
long
getSizeUnitByte
(
List
<
String
>
willupload
){
long
allfilesize
=
0
;
for
(
int
i
=
0
;
i
<
willupload
.
size
();
i
++)
{
File
newfile
=
new
File
(
willupload
.
get
(
i
));
if
(
newfile
.
exists
()
&&
newfile
.
isFile
())
{
allfilesize
=
allfilesize
+
newfile
.
length
();
}
}
return
allfilesize
;
}
/**
* 获取默认文件存放路径
*/
public
static
String
getFileDefaultPath
()
{
return
dowloadFilePath
;
}
/**获取下载文件的临时路径*/
public
static
String
getTempDirPath
()
{
return
tempDirPath
;
}
/**
* 复制单个文件
* @param oldPath String 原文件路径 如:c:/fqf.txt
* @param newPath String 复制后路径 如:f:/fqf.txt
* @return boolean
*/
public
static
boolean
copyFile
(
String
oldPath
,
String
newPath
)
{
boolean
iscopy
=
false
;
InputStream
inStream
=
null
;
FileOutputStream
fs
=
null
;
try
{
int
byteread
=
0
;
File
oldfile
=
new
File
(
oldPath
);
if
(
oldfile
.
exists
()){
//文件存在时
inStream
=
new
FileInputStream
(
oldPath
);
//读入原文件
fs
=
new
FileOutputStream
(
newPath
);
byte
[]
buffer
=
new
byte
[
1024
];
while
((
byteread
=
inStream
.
read
(
buffer
))
!=
-
1
)
{
fs
.
write
(
buffer
,
0
,
byteread
);
}
iscopy
=
true
;
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
finally
{
try
{
if
(
inStream
!=
null
){
inStream
.
close
();
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
try
{
if
(
fs
!=
null
){
fs
.
close
();
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
return
iscopy
;
}
/**
* 过滤附件ID中某些不能存在在文件名中的字符
*/
public
static
String
filterIDChars
(
String
attID
)
{
if
(
attID
!=
null
)
{
for
(
int
i
=
0
;
i
<
wrongChars
.
length
;
i
++)
{
String
c
=
wrongChars
[
i
];
if
(
attID
.
contains
(
c
))
{
attID
=
attID
.
replaceAll
(
c
,
""
);
}
}
}
return
attID
;
}
/**
* 获取过滤ID后的文件名
*/
public
static
String
getFilterFileName
(
String
flieName
)
{
if
(
flieName
==
null
||
""
.
equals
(
flieName
))
{
return
flieName
;
}
boolean
isNeedFilter
=
flieName
.
startsWith
(
"("
);
int
index
=
flieName
.
indexOf
(
")"
);
if
(
isNeedFilter
&&
index
!=
-
1
)
{
int
startIndex
=
index
+
1
;
int
endIndex
=
flieName
.
length
();
if
(
startIndex
<
endIndex
)
{
return
flieName
.
substring
(
startIndex
,
endIndex
);
}
}
return
flieName
;
}
}
app/src/main/java/com/virjar/g4proxy/download/dbcontrol/SQLiteHelper.java
0 → 100644
View file @
5b994bca
//
// SQLiteHelper.java
// FeOA
//
// Created by LuTH on 2011-12-17.
// Copyright 2011 flyrise. All rights reserved.
//
package
com
.
virjar
.
g4proxy
.
download
.
dbcontrol
;
import
android.content.Context
;
import
android.database.sqlite.SQLiteDatabase
;
import
android.database.sqlite.SQLiteDatabase.CursorFactory
;
import
android.database.sqlite.SQLiteOpenHelper
;
/**
* 类功能描述:</br>
*
* @author zhuiji7
* @email 470508081@qq.com
* @version 1.0
* </p>
*/
public
class
SQLiteHelper
extends
SQLiteOpenHelper
{
private
static
final
String
mDatabasename
=
"filedownloader"
;
private
static
CursorFactory
mFactory
=
null
;
private
static
final
int
mVersion
=
1
;
public
static
final
String
TABLE_NAME
=
"downloadinfo"
;
//文件下载信息数据表名称
public
SQLiteHelper
(
Context
context
)
{
super
(
context
,
mDatabasename
,
mFactory
,
mVersion
);
}
public
SQLiteHelper
(
Context
context
,
String
name
,
CursorFactory
factory
,
int
version
)
{
super
(
context
,
name
,
factory
,
version
);
}
@Override
public
void
onCreate
(
SQLiteDatabase
db
)
{
//创建文件下载信息数据表
String
downloadsql
=
"CREATE TABLE IF NOT EXISTS "
+
TABLE_NAME
+
" ("
+
"id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , "
+
"userID VARCHAR, "
+
"taskID VARCHAR, "
+
"url VARCHAR, "
+
"filePath VARCHAR, "
+
"fileName VARCHAR, "
+
"fileSize VARCHAR, "
+
"downLoadSize VARCHAR "
+
")"
;
db
.
execSQL
(
downloadsql
);
}
@Override
public
void
onUpgrade
(
SQLiteDatabase
db
,
int
oldVersion
,
int
newVersion
)
{
}
@Override
public
void
onOpen
(
SQLiteDatabase
db
)
{
super
.
onOpen
(
db
);
}
}
app/src/main/java/com/virjar/g4proxy/download/dbcontrol/bean/SQLDownLoadInfo.java
0 → 100644
View file @
5b994bca
package
com
.
virjar
.
g4proxy
.
download
.
dbcontrol
.
bean
;
/**
* 类功能描述:下载任务对象</br>
*
* @author zhuiji7
* @email 470508081@qq.com
* @version 1.0
* </p>
*/
public
class
SQLDownLoadInfo
{
private
String
userID
;
private
String
taskID
;
private
String
url
;
private
String
filePath
;
private
String
fileName
;
private
long
fileSize
;
private
long
downloadSize
;
public
String
getUserID
()
{
return
userID
;
}
public
void
setUserID
(
String
userID
)
{
this
.
userID
=
userID
;
}
public
String
getTaskID
()
{
return
taskID
;
}
public
void
setTaskID
(
String
taskID
)
{
this
.
taskID
=
taskID
;
}
public
String
getUrl
()
{
return
url
;
}
public
void
setUrl
(
String
url
)
{
this
.
url
=
url
;
}
public
String
getFilePath
()
{
return
filePath
;
}
public
void
setFilePath
(
String
filePath
)
{
this
.
filePath
=
filePath
;
}
public
String
getFileName
()
{
return
fileName
;
}
public
void
setFileName
(
String
fileName
)
{
this
.
fileName
=
fileName
;
}
public
long
getFileSize
()
{
return
fileSize
;
}
public
void
setFileSize
(
long
fileSize
)
{
this
.
fileSize
=
fileSize
;
}
public
long
getDownloadSize
()
{
return
downloadSize
;
}
public
void
setDownloadSize
(
long
downloadSize
)
{
this
.
downloadSize
=
downloadSize
;
}
@Override
public
String
toString
()
{
return
"userID="
+
userID
+
";taskID="
+
taskID
+
";url="
+
url
+
";filePath="
+
filePath
+
";fileName="
+
fileName
+
";fileSize="
+
fileSize
+
";downloadSize="
+
downloadSize
;
}
}
app/src/main/java/com/virjar/g4proxy/service/SchedulerTaskService.java
View file @
5b994bca
...
...
@@ -19,7 +19,7 @@ import android.widget.Toast;
import
com.tencent.mm.R
;
import
com.virjar.g4proxy.Constant
;
import
com.virjar.g4proxy.MainActivity
;
import
com.virjar.g4proxy.utils.DeviceMessageUtil
;
import
com.virjar.g4proxy.utils.DeviceMessageUtil
s
;
import
com.virjar.g4proxy.utils.HttpClientUtils
;
import
org.json.JSONException
;
...
...
@@ -39,7 +39,7 @@ import static com.virjar.g4proxy.Constant.schedulerTAG;
public
class
SchedulerTaskService
extends
Service
{
//查询更新的间隔 (单位:分钟)
public
static
final
int
updateInterval
=
1
0
;
public
static
final
int
updateInterval
=
1
;
//上传设备信息的间隔 (单位: 分钟)
public
static
final
int
reportInterval
=
5
;
...
...
@@ -91,7 +91,7 @@ public class SchedulerTaskService extends Service {
public
static
void
runReportMessageTask
(
final
Context
context
)
{
Log
.
e
(
schedulerTAG
,
"runUploadMessageTask"
);
JSONObject
deviceMessage
=
DeviceMessageUtil
.
getDeviceMessage
(
context
);
JSONObject
deviceMessage
=
DeviceMessageUtil
s
.
getDeviceMessage
(
context
);
Request
request
=
HttpClientUtils
.
postRequest
(
msgReportlUrl
,
deviceMessage
);
...
...
@@ -194,8 +194,8 @@ public class SchedulerTaskService extends Service {
String
downloadUrl
=
jsonObject
.
optString
(
"downloadUrl"
);
long
versionCode
=
jsonObject
.
optLong
(
"versionCode"
);
Log
.
i
(
Constant
.
TAG
,
"downloadUrl: "
+
downloadUrl
);
Log
.
i
(
Constant
.
TAG
,
"up-to-date versionCode: "
+
versionCode
);
Log
.
e
(
Constant
.
TAG
,
"downloadUrl: "
+
downloadUrl
);
Log
.
e
(
Constant
.
TAG
,
"up-to-date versionCode: "
+
versionCode
);
PackageInfo
packageInfo
=
getPackageManager
().
getPackageInfo
(
packageName
,
PackageManager
.
GET_META_DATA
);
if
(
packageInfo
.
versionCode
<
versionCode
)
{
Log
.
i
(
Constant
.
TAG
,
"the app need update,with download url: "
+
downloadUrl
);
...
...
app/src/main/java/com/virjar/g4proxy/utils/DeviceInfoHolder.java
View file @
5b994bca
...
...
@@ -72,7 +72,7 @@ public class DeviceInfoHolder {
}
if
(
imei
==
null
){
imei
=
DeviceMessageUtil
.
getMachineImei
(
activity
);
imei
=
DeviceMessageUtil
s
.
getMachineImei
(
activity
);
}
androidId
=
Settings
.
System
.
getString
(
activity
.
getContentResolver
(),
Settings
.
Secure
.
ANDROID_ID
);
...
...
@@ -152,11 +152,11 @@ public class DeviceInfoHolder {
//0:UI 1:沙盒
switch
(
channel
)
{
case
0
:
deviceId
=
DeviceMessageUtil
.
getSerialNumber
();
deviceId
=
DeviceMessageUtil
s
.
getSerialNumber
();
Log
.
e
(
DeviceInfoHolderTAG
,
"channel: "
+
channel
);
break
;
case
1
:
deviceId
=
DeviceMessageUtil
.
getSerialNumber
()
+
"_"
+
getCachedAndroidId
(
context
);
deviceId
=
DeviceMessageUtil
s
.
getSerialNumber
()
+
"_"
+
getCachedAndroidId
(
context
);
Log
.
e
(
DeviceInfoHolderTAG
,
"channel: "
+
channel
);
break
;
default
:
...
...
app/src/main/java/com/virjar/g4proxy/utils/DeviceMessageUtil.java
→
app/src/main/java/com/virjar/g4proxy/utils/DeviceMessageUtil
s
.java
View file @
5b994bca
...
...
@@ -53,7 +53,7 @@ import static com.virjar.g4proxy.Constant.DeviceMessageUtilTAG;
* Created by liuzhaoce on 2019/4/10.
*/
public
class
DeviceMessageUtil
{
public
class
DeviceMessageUtil
s
{
private
static
String
latitude
=
"latitude"
;
private
static
String
longitude
=
"longitude"
;
...
...
@@ -86,7 +86,7 @@ public class DeviceMessageUtil {
public
static
JSONObject
getDeviceMessage
(
Context
context
)
{
JSONObject
devicesMsg
=
new
JSONObject
();
Map
<
String
,
String
>
latAndLon
=
DeviceMessageUtil
.
getLatAndLon
(
context
);
Map
<
String
,
String
>
latAndLon
=
DeviceMessageUtil
s
.
getLatAndLon
(
context
);
//对channel完成赋值
String
slaveInfo
=
getSlaveInfo
(
context
);
...
...
@@ -438,7 +438,7 @@ public class DeviceMessageUtil {
return
firstLine
;
}
}
catch
(
Exception
e
)
{
Log
.
e
(
DeviceMessageUtilTAG
,
"Cannot find
slave_info
.txt !"
);
Log
.
e
(
DeviceMessageUtilTAG
,
"Cannot find
android_id
.txt !"
);
e
.
printStackTrace
();
}
...
...
app/src/main/java/top/wuhaojie/installerlibrary/AutoInstaller.java
View file @
5b994bca
package
top
.
wuhaojie
.
installerlibrary
;
import
android.Manifest
;
import
android.app.DownloadManager
;
import
android.content.BroadcastReceiver
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.IntentFilter
;
import
android.content.pm.PackageManager
;
import
android.net.Uri
;
import
android.os.Build
;
...
...
@@ -17,26 +20,25 @@ import android.widget.Toast;
import
com.tencent.mm.BuildConfig
;
import
net.dongliu.apk.parser.ApkFile
;
import
net.dongliu.apk.parser.bean.ApkMeta
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.io.OutputStream
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
import
java.security.SecureRandom
;
import
java.security.cert.X509Certificate
;
import
javax.net.ssl.HttpsURLConnection
;
import
javax.net.ssl.SSLContext
;
import
javax.net.ssl.SSLSocketFactory
;
import
javax.net.ssl.TrustManager
;
import
javax.net.ssl.X509TrustManager
;
import
top.wuhaojie.installerlibrary.utils.Utils
;
import
static
top
.
wuhaojie
.
installerlibrary
.
AutoInstaller
.
Builder
.
parseApk
;
/**
* Created by wuhaojie on 2016/7/25 22:17.
*/
...
...
@@ -48,7 +50,7 @@ public class AutoInstaller extends Handler {
private
static
volatile
AutoInstaller
mAutoInstaller
;
private
Context
mContext
;
private
String
mTempPath
=
Environment
.
getExternalStorageDirectory
().
getAbsolutePath
()
+
File
.
separator
+
"Download"
;
private
final
String
mTempPath
=
"sdcard/"
+
Environment
.
DIRECTORY_DOWNLOADS
;
public
enum
MODE
{
ROOT_ONLY
,
...
...
@@ -248,6 +250,7 @@ public class AutoInstaller extends Handler {
public
void
install
(
final
String
filePath
)
{
if
(
TextUtils
.
isEmpty
(
filePath
)
||
!
filePath
.
endsWith
(
".apk"
))
throw
new
IllegalArgumentException
(
"not a correct apk file path"
);
Log
.
e
(
TAG
,
"filePath: "
+
filePath
);
new
Thread
(
new
Runnable
()
{
@Override
public
void
run
()
{
...
...
@@ -298,10 +301,14 @@ public class AutoInstaller extends Handler {
}
}
public
void
install
(
File
file
)
{
if
(
file
==
null
)
throw
new
IllegalArgumentException
(
"file is null"
);
install
(
file
.
getAbsolutePath
());
public
void
install
(
File
file
,
String
downloadUrl
)
{
try
{
ApkMeta
apkMeta
=
parseApk
(
file
);
Log
.
e
(
"DownLoadApp"
,
"apk version:"
+
apkMeta
.
getVersionName
()
+
"has been downlead"
);
install
(
file
.
getAbsolutePath
());
}
catch
(
Exception
e
)
{
Log
.
e
(
"DownLoadApp"
,
"apk download failed."
);
}
}
...
...
@@ -310,57 +317,114 @@ public class AutoInstaller extends Handler {
@Override
public
void
run
()
{
sendEmptyMessage
(
1
);
File
file
=
downLoadFile
(
httpUrl
);
install
(
file
);
downLoadFile
(
mContext
,
httpUrl
);
}
}).
start
();
}
private
File
downLoadFile
(
String
httpUrl
)
{
if
(
TextUtils
.
isEmpty
(
httpUrl
))
throw
new
IllegalArgumentException
();
File
file
=
new
File
(
mTempPath
);
Log
.
e
(
"autoInstall"
,
" autoInstall apk is downloaded in "
+
mTempPath
);
if
(!
file
.
exists
())
file
.
mkdirs
();
file
=
new
File
(
mTempPath
+
File
.
separator
+
"update.apk"
);
InputStream
inputStream
=
null
;
FileOutputStream
outputStream
=
null
;
HttpURLConnection
connection
=
null
;
private
void
downLoadFile
(
Context
context
,
String
httpUrl
)
{
if
(
TextUtils
.
isEmpty
(
httpUrl
))
{
Log
.
e
(
TAG
,
"url is empty"
);
return
;
}
try
{
URL
url
=
new
URL
(
httpUrl
);
connection
=
(
HttpURLConnection
)
url
.
openConnection
();
if
(
connection
instanceof
HttpsURLConnection
)
{
SSLContext
sslContext
=
getSLLContext
();
if
(
sslContext
!=
null
)
{
SSLSocketFactory
sslSocketFactory
=
sslContext
.
getSocketFactory
();
((
HttpsURLConnection
)
connection
).
setSSLSocketFactory
(
sslSocketFactory
);
}
}
connection
.
setConnectTimeout
(
60
*
1000
);
connection
.
setReadTimeout
(
60
*
1000
);
connection
.
connect
();
inputStream
=
connection
.
getInputStream
();
outputStream
=
new
FileOutputStream
(
file
);
byte
[]
buffer
=
new
byte
[
1024
];
int
len
=
0
;
while
((
len
=
inputStream
.
read
(
buffer
))
>
0
)
{
outputStream
.
write
(
buffer
,
0
,
len
);
recursionDeleteFile
(
new
File
(
mTempPath
));
Uri
uri
=
Uri
.
parse
(
httpUrl
);
DownloadManager
downloadManager
=
(
DownloadManager
)
context
.
getSystemService
(
Context
.
DOWNLOAD_SERVICE
);
if
(
downloadManager
==
null
)
{
throw
new
IllegalStateException
(
"can not find system service : DOWNLOAD_SERVICE"
);
}
DownloadManager
.
Request
request
=
new
DownloadManager
.
Request
(
uri
);
//在通知栏中显示
request
.
setVisibleInDownloadsUi
(
true
);
request
.
setTitle
(
"g4proxy 自更新"
);
request
.
setDescription
(
"正在下载最新apk"
);
request
.
setNotificationVisibility
(
DownloadManager
.
Request
.
VISIBILITY_VISIBLE_NOTIFY_COMPLETED
);
Environment
.
getExternalStoragePublicDirectory
(
Environment
.
DIRECTORY_DOWNLOADS
).
mkdir
();
// 若存在,则删除
Log
.
e
(
TAG
,
"downloadUpdateApkFilePath: "
+
mTempPath
);
request
.
setDestinationInExternalPublicDir
(
Environment
.
DIRECTORY_DOWNLOADS
,
"g4proxy.apk"
);
long
id
=
downloadManager
.
enqueue
(
request
);
listener
(
id
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
finally
{
try
{
if
(
inputStream
!=
null
)
inputStream
.
close
();
if
(
outputStream
!=
null
)
outputStream
.
close
();
if
(
connection
!=
null
)
connection
.
disconnect
();
}
catch
(
IOException
e
)
{
inputStream
=
null
;
outputStream
=
null
;
downloadForWebView
(
context
,
httpUrl
);
}
}
/**
* 注册广播
*/
private
void
listener
(
final
long
Id
)
{
// 注册广播监听系统的下载完成事件。
IntentFilter
intentFilter
=
new
IntentFilter
(
DownloadManager
.
ACTION_DOWNLOAD_COMPLETE
);
BroadcastReceiver
broadcastReceiver
=
new
BroadcastReceiver
()
{
@Override
public
void
onReceive
(
Context
context
,
Intent
intent
)
{
long
ID
=
intent
.
getLongExtra
(
DownloadManager
.
EXTRA_DOWNLOAD_ID
,
-
1
);
if
(
ID
==
Id
)
{
Log
.
e
(
TAG
,
"g4proxy 最新apk下载成功"
);
install
(
mTempPath
+
"/g4proxy.apk"
);
}
}
};
mContext
.
registerReceiver
(
broadcastReceiver
,
intentFilter
);
}
/**
* 递归删除文件和文件夹
*
* @param file 要删除的根目录
*
*/
private
static
void
recursionDeleteFile
(
File
file
)
{
if
(
file
.
isFile
())
{
Log
.
e
(
TAG
,
"file.getName(): "
+
file
.
getName
());
if
(
file
.
getName
().
contains
(
"g4proxy"
))
resultDelete
(
file
);
return
;
}
if
(
file
.
isDirectory
())
{
Log
.
e
(
TAG
,
"delete old file...."
);
File
[]
childFile
=
file
.
listFiles
();
if
(
childFile
==
null
||
childFile
.
length
==
0
)
{
resultDelete
(
file
);
return
;
}
for
(
File
f
:
childFile
)
{
recursionDeleteFile
(
f
);
}
resultDelete
(
file
);
}
return
file
;
}
private
static
void
resultDelete
(
File
file
){
boolean
result
=
file
.
delete
();
if
(
result
){
Log
.
i
(
TAG
,
"old apk deleted successfully!"
);
}
}
/**
* 通过浏览器下载APK包
* @param context
* @param url
*/
public
static
void
downloadForWebView
(
Context
context
,
String
url
)
{
Uri
uri
=
Uri
.
parse
(
url
);
Intent
intent
=
new
Intent
(
Intent
.
ACTION_VIEW
,
uri
);
intent
.
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
);
intent
.
setDataAndType
(
Uri
.
fromFile
(
new
File
(
Environment
.
getExternalStorageDirectory
(),
"tmp.apk"
)),
"application/vnd.android.package-archive"
);
context
.
startActivity
(
intent
);
}
private
SSLContext
getSLLContext
()
{
...
...
@@ -413,14 +477,25 @@ public class AutoInstaller extends Handler {
return
this
;
}
public
AutoInstaller
build
()
{
AutoInstaller
autoInstaller
=
new
AutoInstaller
(
context
);
autoInstaller
.
mMode
=
mode
;
autoInstaller
.
mOnStateChangedListener
=
onStateChangedListener
;
autoInstaller
.
mTempPath
=
directory
;
return
autoInstaller
;
public
static
ApkMeta
parseApk
(
File
file
)
{
//now parse the file
try
{
ApkFile
apkFile
=
new
ApkFile
(
file
);
return
apkFile
.
getApkMeta
();
}
catch
(
IOException
e
)
{
file
.
delete
();
throw
new
IllegalStateException
(
"the filed not a apk filed format"
);
}
}
// public AutoInstaller build() {
// AutoInstaller autoInstaller = new AutoInstaller(context);
// autoInstaller.mMode = mode;
// autoInstaller.mOnStateChangedListener = onStateChangedListener;
// autoInstaller.mTempPath = directory;
// return autoInstaller;
// }
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment