Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
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
Magisk
Commits
0241a50c
Commit
0241a50c
authored
Dec 02, 2018
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Stop using platform provided DownloadManager
parent
2a2e1236
Show whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
536 additions
and
525 deletions
+536
-525
build.gradle
app/build.gradle
+2
-1
proguard-rules.pro
app/proguard-rules.pro
+3
-0
g.java
app/src/full/java/a/g.java
+0
-0
Const.java
app/src/full/java/com/topjohnwu/magisk/Const.java
+3
-2
CheckSafetyNet.java
...full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java
+1
-1
CheckUpdates.java
...c/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java
+7
-7
InstallMagisk.java
.../full/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java
+1
-1
MarkDownWindow.java
...full/java/com/topjohnwu/magisk/asyncs/MarkDownWindow.java
+2
-2
ProcessRepoZip.java
...full/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java
+2
-2
UpdateRepos.java
...rc/full/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java
+42
-39
BaseActivity.java
...ll/java/com/topjohnwu/magisk/components/BaseActivity.java
+70
-11
BaseFragment.java
...ll/java/com/topjohnwu/magisk/components/BaseFragment.java
+1
-1
InstallMethodDialog.java
.../com/topjohnwu/magisk/components/InstallMethodDialog.java
+62
-37
ManagerInstallDialog.java
...com/topjohnwu/magisk/components/ManagerInstallDialog.java
+5
-14
NotificationProgress.java
...com/topjohnwu/magisk/components/NotificationProgress.java
+52
-0
UninstallDialog.java
...java/com/topjohnwu/magisk/components/UninstallDialog.java
+22
-12
Repo.java
app/src/full/java/com/topjohnwu/magisk/container/Repo.java
+2
-3
ModulesFragment.java
.../java/com/topjohnwu/magisk/fragments/ModulesFragment.java
+1
-1
SettingsFragment.java
...java/com/topjohnwu/magisk/fragments/SettingsFragment.java
+2
-22
ManagerUpdate.java
...ll/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java
+4
-35
OnBootService.java
...ull/java/com/topjohnwu/magisk/services/OnBootService.java
+2
-2
DlInstallManager.java
...ull/java/com/topjohnwu/magisk/utils/DlInstallManager.java
+101
-0
Notifications.java
...c/full/java/com/topjohnwu/magisk/utils/Notifications.java
+19
-14
Utils.java
app/src/full/java/com/topjohnwu/magisk/utils/Utils.java
+6
-0
BaseActivity.java
...in/java/com/topjohnwu/magisk/components/BaseActivity.java
+0
-75
DownloadReceiver.java
...java/com/topjohnwu/magisk/receivers/DownloadReceiver.java
+0
-58
APKInstall.java
app/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java
+7
-9
Download.java
app/src/main/java/com/topjohnwu/magisk/utils/Download.java
+0
-36
WebService.java
app/src/main/java/com/topjohnwu/magisk/utils/WebService.java
+3
-58
file_paths.xml
app/src/main/res/xml/file_paths.xml
+1
-0
AndroidManifest.xml
app/src/stub/AndroidManifest.xml
+6
-3
BootLauncher.java
app/src/stub/java/com/topjohnwu/magisk/BootLauncher.java
+2
-4
MainActivity.java
app/src/stub/java/com/topjohnwu/magisk/MainActivity.java
+105
-0
NoUIActivity.java
app/src/stub/java/com/topjohnwu/magisk/NoUIActivity.java
+0
-70
FlavorActivity.java
.../java/com/topjohnwu/magisk/components/FlavorActivity.java
+0
-5
No files found.
app/build.gradle
View file @
0241a50c
...
...
@@ -70,8 +70,9 @@ android {
dependencies
{
implementation
fileTree
(
include:
[
'*.jar'
],
dir:
'libs'
)
fullImplementation
project
(
':utils'
)
implementation
'androidx.core:core:1.0.1'
fullImplementation
project
(
':utils'
)
fullImplementation
'com.amitshekhar.android:android-networking:1.0.2'
fullImplementation
'androidx.appcompat:appcompat:1.0.2'
fullImplementation
"androidx.preference:preference:${rootProject.ext.androidXVersion}"
fullImplementation
"androidx.recyclerview:recyclerview:${rootProject.ext.androidXVersion}"
...
...
app/proguard-rules.pro
View file @
0241a50c
...
...
@@ -25,6 +25,9 @@
# Snet extention
-
keepclassmembers
class
com
.
topjohnwu
.
magisk
.
utils
.
ISafetyNetHelper
{
*
;
}
# Fast Android Networking Library
-
dontwarn
okhttp3
.
**
# Strip logging
-
assumenosideeffects
class
com
.
topjohnwu
.
magisk
.
utils
.
Logger
{
public
***
debug
(...);
...
...
app/src/
main
/java/a/g.java
→
app/src/
full
/java/a/g.java
View file @
0241a50c
File moved
app/src/full/java/com/topjohnwu/magisk/Const.java
View file @
0241a50c
...
...
@@ -61,13 +61,14 @@ public class Const {
public
static
final
int
MAGISK_UPDATE_NOTIFICATION_ID
=
4
;
public
static
final
int
APK_UPDATE_NOTIFICATION_ID
=
5
;
public
static
final
int
DTBO_NOTIFICATION_ID
=
7
;
public
static
final
int
DOWNLOAD_PROGRESS_ID
=
8
;
public
static
final
String
NOTIFICATION_CHANNEL
=
"magisk_notification"
;
}
public
static
class
Url
{
public
static
final
String
STABLE_URL
=
"https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json"
;
public
static
final
String
BETA_URL
=
"https://raw.githubusercontent.com/topjohnwu/magisk_files/master/beta.json"
;
public
static
final
String
REPO_URL
=
"https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed
&page=%d
"
;
public
static
final
String
REPO_URL
=
"https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed"
;
public
static
final
String
FILE_URL
=
"https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s"
;
public
static
final
String
ZIP_URL
=
"https://github.com/Magisk-Modules-Repo/%s/archive/master.zip"
;
public
static
final
String
PAYPAL_URL
=
"https://www.paypal.me/topjohnwu"
;
...
...
@@ -92,7 +93,7 @@ public class Const {
// intents
public
static
final
String
OPEN_SECTION
=
"section"
;
public
static
final
String
INTENT_SET_
FILE
NAME
=
"filename"
;
public
static
final
String
INTENT_SET_NAME
=
"filename"
;
public
static
final
String
INTENT_SET_LINK
=
"link"
;
public
static
final
String
FLASH_ACTION
=
"action"
;
public
static
final
String
FLASH_SET_BOOT
=
"boot"
;
...
...
app/src/full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java
View file @
0241a50c
...
...
@@ -32,7 +32,7 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Void> {
private
void
dlSnet
()
throws
Exception
{
Shell
.
sh
(
"rm -rf "
+
dexPath
.
getParent
()).
exec
();
dexPath
.
getParentFile
().
mkdir
();
HttpURLConnection
conn
=
WebService
.
mustRequest
(
Data
.
snetLink
,
null
);
HttpURLConnection
conn
=
WebService
.
mustRequest
(
Data
.
snetLink
);
try
(
OutputStream
out
=
new
BufferedOutputStream
(
new
FileOutputStream
(
dexPath
));
InputStream
in
=
new
BufferedInputStream
(
conn
.
getInputStream
()))
{
...
...
app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java
View file @
0241a50c
...
...
@@ -5,9 +5,9 @@ import android.os.AsyncTask;
import
com.topjohnwu.magisk.BuildConfig
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.utils.Notification
Mgr
;
import
com.topjohnwu.magisk.utils.Notification
s
;
import
com.topjohnwu.magisk.utils.Topic
;
import
com.topjohnwu.magisk.utils.
WebService
;
import
com.topjohnwu.magisk.utils.
Utils
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
...
...
@@ -46,13 +46,13 @@ public class CheckUpdates {
String
jsonStr
=
""
;
switch
(
Data
.
updateChannel
)
{
case
Const
.
Value
.
STABLE_CHANNEL
:
jsonStr
=
WebService
.
get
String
(
Const
.
Url
.
STABLE_URL
);
jsonStr
=
Utils
.
dl
String
(
Const
.
Url
.
STABLE_URL
);
break
;
case
Const
.
Value
.
BETA_CHANNEL
:
jsonStr
=
WebService
.
get
String
(
Const
.
Url
.
BETA_URL
);
jsonStr
=
Utils
.
dl
String
(
Const
.
Url
.
BETA_URL
);
break
;
case
Const
.
Value
.
CUSTOM_CHANNEL
:
jsonStr
=
WebService
.
get
String
(
Data
.
MM
().
prefs
.
getString
(
Const
.
Key
.
CUSTOM_CHANNEL
,
""
));
jsonStr
=
Utils
.
dl
String
(
Data
.
MM
().
prefs
.
getString
(
Const
.
Key
.
CUSTOM_CHANNEL
,
""
));
break
;
}
...
...
@@ -89,9 +89,9 @@ public class CheckUpdates {
fetchUpdates
();
if
(
cb
!=
null
)
{
if
(
BuildConfig
.
VERSION_CODE
<
Data
.
remoteManagerVersionCode
)
{
Notification
Mgr
.
managerUpdate
();
Notification
s
.
managerUpdate
();
}
else
if
(
Data
.
magiskVersionCode
<
Data
.
remoteMagiskVersionCode
)
{
Notification
Mgr
.
magiskUpdate
();
Notification
s
.
magiskUpdate
();
}
cb
.
run
();
}
...
...
app/src/full/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java
View file @
0241a50c
...
...
@@ -136,7 +136,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
if
(!
ShellUtils
.
checkSum
(
"MD5"
,
zip
,
Data
.
magiskMD5
))
{
console
.
add
(
"- Downloading zip"
);
HttpURLConnection
conn
=
WebService
.
mustRequest
(
Data
.
magiskLink
,
null
);
HttpURLConnection
conn
=
WebService
.
mustRequest
(
Data
.
magiskLink
);
buf
=
new
BufferedInputStream
(
new
ProgressStream
(
conn
),
conn
.
getContentLength
());
buf
.
mark
(
conn
.
getContentLength
()
+
1
);
try
(
OutputStream
out
=
new
FileOutputStream
(
zip
))
{
...
...
app/src/full/java/com/topjohnwu/magisk/asyncs/MarkDownWindow.java
View file @
0241a50c
...
...
@@ -6,7 +6,7 @@ import android.webkit.WebView;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.utils.
WebService
;
import
com.topjohnwu.magisk.utils.
Utils
;
import
com.topjohnwu.superuser.ShellUtils
;
import
org.commonmark.node.Node
;
...
...
@@ -43,7 +43,7 @@ public class MarkDownWindow extends ParallelTask<Void, Void, String> {
MagiskManager
mm
=
Data
.
MM
();
String
md
;
if
(
mUrl
!=
null
)
{
md
=
WebService
.
get
String
(
mUrl
);
md
=
Utils
.
dl
String
(
mUrl
);
}
else
{
try
(
ByteArrayOutputStream
out
=
new
ByteArrayOutputStream
())
{
ShellUtils
.
pump
(
is
,
out
);
...
...
app/src/full/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java
View file @
0241a50c
...
...
@@ -93,7 +93,7 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
if
(
activity
==
null
)
return
null
;
try
{
// Request zip from Internet
HttpURLConnection
conn
=
WebService
.
mustRequest
(
mRepo
.
getZipUrl
()
,
null
);
HttpURLConnection
conn
=
WebService
.
mustRequest
(
mRepo
.
getZipUrl
());
total
=
conn
.
getContentLength
();
// Temp files
...
...
@@ -101,7 +101,7 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
File
temp2
=
new
File
(
temp1
.
getParentFile
(),
"2.zip"
);
temp1
.
getParentFile
().
mkdir
();
// First
download
the zip, Web -> temp1
// First
upgrade
the zip, Web -> temp1
try
(
InputStream
in
=
new
BufferedInputStream
(
new
ProgressInputStream
(
conn
.
getInputStream
()));
OutputStream
out
=
new
BufferedOutputStream
(
new
FileOutputStream
(
temp1
))
...
...
app/src/full/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java
View file @
0241a50c
...
...
@@ -3,14 +3,15 @@ package com.topjohnwu.magisk.asyncs;
import
android.database.Cursor
;
import
android.os.AsyncTask
;
import
com.androidnetworking.AndroidNetworking
;
import
com.androidnetworking.common.ANRequest
;
import
com.androidnetworking.common.ANResponse
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.container.Repo
;
import
com.topjohnwu.magisk.utils.Logger
;
import
com.topjohnwu.magisk.utils.Topic
;
import
com.topjohnwu.magisk.utils.Utils
;
import
com.topjohnwu.magisk.utils.WebService
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
...
...
@@ -22,9 +23,7 @@ import java.text.ParseException;
import
java.text.SimpleDateFormat
;
import
java.util.Collections
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.Locale
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.TimeZone
;
import
java.util.concurrent.ExecutorService
;
...
...
@@ -32,40 +31,36 @@ import java.util.concurrent.Executors;
import
java.util.concurrent.TimeUnit
;
public
class
UpdateRepos
{
private
static
final
int
CPU_COUNT
=
Runtime
.
getRuntime
().
availableProcessors
();
private
static
final
int
CORE_POOL_SIZE
=
Math
.
max
(
2
,
CPU_COUNT
-
1
);
private
static
final
DateFormat
dateFormat
;
private
MagiskManager
mm
;
private
Set
<
String
>
cached
;
private
ExecutorService
threadPool
;
static
{
dateFormat
=
new
SimpleDateFormat
(
"yyyy-MM-dd'T'HH:mm:ss'Z'"
,
Locale
.
US
);
dateFormat
.
setTimeZone
(
TimeZone
.
getTimeZone
(
"UTC"
));
}
private
MagiskManager
mm
;
private
Set
<
String
>
cached
;
private
ExecutorService
threadPool
;
public
UpdateRepos
()
{
mm
=
Data
.
MM
();
}
private
void
waitTasks
()
{
threadPool
.
shutdown
();
while
(
true
)
{
try
{
threadPool
.
awaitTermination
(
Long
.
MAX_VALUE
,
TimeUnit
.
MILLISECONDS
);
if
(
threadPool
.
awaitTermination
(
Long
.
MAX_VALUE
,
TimeUnit
.
NANOSECONDS
))
break
;
}
catch
(
InterruptedException
ignored
)
{}
}
}
private
boolean
loadJSON
(
String
jsonString
)
throws
JSONException
,
ParseException
{
JSONArray
jsonArray
=
new
JSONArray
(
jsonString
);
// Empty page, halt
if
(
jsonArray
.
length
()
==
0
)
return
false
;
for
(
int
i
=
0
;
i
<
jsonArray
.
length
();
i
++)
{
JSONObject
rawRepo
=
jsonArray
.
getJSONObject
(
i
);
private
void
loadJSON
(
JSONArray
array
)
throws
JSONException
,
ParseException
{
for
(
int
i
=
0
;
i
<
array
.
length
();
i
++)
{
JSONObject
rawRepo
=
array
.
getJSONObject
(
i
);
String
id
=
rawRepo
.
getString
(
"name"
);
Date
date
=
dateFormat
.
parse
(
rawRepo
.
getString
(
"pushed_at"
));
threadPool
.
execute
(()
->
{
...
...
@@ -83,42 +78,50 @@ public class UpdateRepos {
}
});
}
return
true
;
}
/* We sort repos by last push, which means that we only need to check whether the
* first page is updated to determine whether the online repo database is changed
*/
private
boolean
loadPage
(
int
page
)
{
Map
<
String
,
String
>
header
=
new
HashMap
<>();
if
(
page
==
0
)
header
.
put
(
Const
.
Key
.
IF_NONE_MATCH
,
mm
.
prefs
.
getString
(
Const
.
Key
.
ETAG_KEY
,
""
));
String
url
=
Utils
.
fmt
(
Const
.
Url
.
REPO_URL
,
page
+
1
);
try
{
HttpURLConnection
conn
=
WebService
.
request
(
url
,
header
);
// No updates
if
(
conn
.
getResponseC
ode
()
==
HttpURLConnection
.
HTTP_NOT_MODIFIED
)
ANRequest
.
GetRequestBuilder
req
=
AndroidNetworking
.
get
(
Const
.
Url
.
REPO_URL
)
.
addQueryParameter
(
"page"
,
String
.
valueOf
(
page
+
1
));
if
(
page
==
0
)
{
String
etag
=
mm
.
prefs
.
getString
(
Const
.
Key
.
ETAG_KEY
,
null
);
if
(
etag
!=
null
)
req
.
addHeaders
(
Const
.
Key
.
IF_NONE_MATCH
,
etag
);
}
ANResponse
<
JSONArray
>
res
=
req
.
build
().
executeForJSONArray
();
if
(
res
.
getOkHttpResponse
().
c
ode
()
==
HttpURLConnection
.
HTTP_NOT_MODIFIED
)
return
false
;
// Current page is the last page
if
(!
loadJSON
(
WebService
.
getString
(
conn
))
)
if
(
res
.
getResult
()
==
null
||
res
.
getResult
().
length
()
==
0
)
return
true
;
}
catch
(
Exception
e
)
{
try
{
loadJSON
(
res
.
getResult
());
}
catch
(
JSONException
|
ParseException
e
)
{
// Should not happen, but if exception occurs, page load fails
return
false
;
}
// Update ETAG
if
(
page
==
0
)
{
String
etag
=
header
.
get
(
Const
.
Key
.
ETAG_KEY
);
String
etag
=
res
.
getOkHttpResponse
().
header
(
Const
.
Key
.
ETAG_KEY
);
if
(
etag
!=
null
)
{
etag
=
etag
.
substring
(
etag
.
indexOf
(
'\"'
),
etag
.
lastIndexOf
(
'\"'
)
+
1
);
mm
.
prefs
.
edit
().
putString
(
Const
.
Key
.
ETAG_KEY
,
etag
).
apply
();
}
}
String
links
=
header
.
get
(
Const
.
Key
.
LINK_KEY
);
String
links
=
res
.
getOkHttpResponse
().
header
(
Const
.
Key
.
LINK_KEY
);
return
links
==
null
||
!
links
.
contains
(
"next"
)
||
loadPage
(
page
+
1
);
}
private
boolean
loadPages
()
{
return
loadPage
(
0
);
}
private
void
fullReload
()
{
Cursor
c
=
mm
.
repoDB
.
getRawCursor
();
while
(
c
.
moveToNext
())
{
...
...
@@ -142,7 +145,7 @@ public class UpdateRepos {
cached
=
Collections
.
synchronizedSet
(
mm
.
repoDB
.
getRepoIDSet
());
threadPool
=
Executors
.
newFixedThreadPool
(
CORE_POOL_SIZE
);
if
(
loadPage
(
0
))
{
if
(
loadPage
s
(
))
{
waitTasks
();
// The leftover cached means they are removed from online repo
mm
.
repoDB
.
removeRepo
(
cached
);
...
...
app/src/full/java/com/topjohnwu/magisk/components/
Flavor
Activity.java
→
app/src/full/java/com/topjohnwu/magisk/components/
Base
Activity.java
View file @
0241a50c
...
...
@@ -2,34 +2,36 @@ package com.topjohnwu.magisk.components;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.pm.PackageManager
;
import
android.content.res.Configuration
;
import
android.os.Bundle
;
import
android.view.WindowManager
;
import
android.widget.Toast
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.NoUIActivity
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.utils.Download
;
import
com.topjohnwu.magisk.utils.LocaleManager
;
import
com.topjohnwu.magisk.utils.Topic
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.StyleRes
;
import
androidx.appcompat.app.AppCompatActivity
;
import
androidx.core.app.ActivityCompat
;
import
androidx.core.content.ContextCompat
;
public
abstract
class
Flavor
Activity
extends
AppCompatActivity
implements
Topic
.
AutoSubscriber
{
public
abstract
class
Base
Activity
extends
AppCompatActivity
implements
Topic
.
AutoSubscriber
{
private
ActivityResultListener
activityResultListener
;
public
static
final
String
INTENT_PERM
=
"perm_dialog"
;
protected
static
Runnable
permissionGrantCallback
;
static
int
[]
EMPTY_INT_ARRAY
=
new
int
[
0
];
public
MagiskManager
mm
;
@Override
protected
void
attachBaseContext
(
Context
base
)
{
super
.
attachBaseContext
(
base
);
Configuration
config
=
base
.
getResources
().
getConfiguration
();
config
.
setLocale
(
LocaleManager
.
locale
);
applyOverrideConfiguration
(
config
);
mm
=
Data
.
MM
();
}
private
ActivityResultListener
activityResultListener
;
public
MagiskManager
mm
;
@Override
public
int
[]
getSubscribedTopics
()
{
...
...
@@ -41,6 +43,15 @@ public abstract class FlavorActivity extends AppCompatActivity implements Topic.
return
-
1
;
}
@Override
protected
void
attachBaseContext
(
Context
base
)
{
super
.
attachBaseContext
(
base
);
Configuration
config
=
base
.
getResources
().
getConfiguration
();
config
.
setLocale
(
LocaleManager
.
locale
);
applyOverrideConfiguration
(
config
);
mm
=
Data
.
MM
();
}
@Override
protected
void
onCreate
(
@Nullable
Bundle
savedInstanceState
)
{
Topic
.
subscribe
(
this
);
...
...
@@ -48,6 +59,9 @@ public abstract class FlavorActivity extends AppCompatActivity implements Topic.
setTheme
(
getDarkTheme
());
}
super
.
onCreate
(
savedInstanceState
);
String
[]
perms
=
getIntent
().
getStringArrayExtra
(
INTENT_PERM
);
if
(
perms
!=
null
)
ActivityCompat
.
requestPermissions
(
this
,
perms
,
0
);
}
@Override
...
...
@@ -70,6 +84,34 @@ public abstract class FlavorActivity extends AppCompatActivity implements Topic.
}
}
public
static
void
runWithPermission
(
Context
context
,
String
[]
permissions
,
Runnable
callback
)
{
boolean
granted
=
true
;
for
(
String
perm
:
permissions
)
{
if
(
ContextCompat
.
checkSelfPermission
(
context
,
perm
)
!=
PackageManager
.
PERMISSION_GRANTED
)
granted
=
false
;
}
if
(
granted
)
{
Download
.
EXTERNAL_PATH
.
mkdirs
();
callback
.
run
();
}
else
{
// Passed in context should be an activity if not granted, need to show dialog!
permissionGrantCallback
=
callback
;
if
(!(
context
instanceof
BaseActivity
))
{
// Start NoUIActivity to show dialog
Intent
intent
=
new
Intent
(
context
,
Data
.
classMap
.
get
(
NoUIActivity
.
class
));
intent
.
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
);
intent
.
putExtra
(
INTENT_PERM
,
permissions
);
context
.
startActivity
(
intent
);
}
else
{
ActivityCompat
.
requestPermissions
((
BaseActivity
)
context
,
permissions
,
0
);
}
}
}
public
void
runWithPermission
(
String
[]
permissions
,
Runnable
callback
)
{
runWithPermission
(
this
,
permissions
,
callback
);
}
@Override
protected
void
onActivityResult
(
int
requestCode
,
int
resultCode
,
Intent
data
)
{
if
(
activityResultListener
!=
null
)
...
...
@@ -82,6 +124,23 @@ public abstract class FlavorActivity extends AppCompatActivity implements Topic.
super
.
startActivityForResult
(
intent
,
requestCode
);
}
@Override
public
void
onRequestPermissionsResult
(
int
requestCode
,
@NonNull
String
[]
permissions
,
@NonNull
int
[]
grantResults
)
{
boolean
grant
=
true
;
for
(
int
result
:
grantResults
)
{
if
(
result
!=
PackageManager
.
PERMISSION_GRANTED
)
grant
=
false
;
}
if
(
grant
)
{
if
(
permissionGrantCallback
!=
null
)
{
permissionGrantCallback
.
run
();
}
}
else
{
Toast
.
makeText
(
this
,
R
.
string
.
no_rw_storage
,
Toast
.
LENGTH_LONG
).
show
();
}
permissionGrantCallback
=
null
;
}
public
interface
ActivityResultListener
{
void
onActivityResult
(
int
requestCode
,
int
resultCode
,
Intent
data
);
}
...
...
app/src/full/java/com/topjohnwu/magisk/components/BaseFragment.java
View file @
0241a50c
...
...
@@ -52,6 +52,6 @@ public class BaseFragment extends Fragment implements Topic.AutoSubscriber {
@Override
public
int
[]
getSubscribedTopics
()
{
return
Flavor
Activity
.
EMPTY_INT_ARRAY
;
return
Base
Activity
.
EMPTY_INT_ARRAY
;
}
}
app/src/full/java/com/topjohnwu/magisk/components/InstallMethodDialog.java
View file @
0241a50c
...
...
@@ -2,16 +2,17 @@ package com.topjohnwu.magisk.components;
import
android.Manifest
;
import
android.app.Activity
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.net.Uri
;
import
android.widget.Toast
;
import
com.androidnetworking.AndroidNetworking
;
import
com.androidnetworking.error.ANError
;
import
com.androidnetworking.interfaces.DownloadListener
;
import
com.google.android.material.snackbar.Snackbar
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.FlashActivity
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.receivers.DownloadReceiver
;
import
com.topjohnwu.magisk.utils.Download
;
import
com.topjohnwu.magisk.utils.Utils
;
...
...
@@ -28,52 +29,76 @@ class InstallMethodDialog extends AlertDialog.Builder {
Intent
intent
;
switch
(
idx
)
{
case
1
:
patchBoot
(
activity
);
break
;
case
0
:
downloadOnly
(
activity
);
break
;
case
2
:
intent
=
new
Intent
(
activity
,
Data
.
classMap
.
get
(
FlashActivity
.
class
))
.
putExtra
(
Const
.
Key
.
FLASH_ACTION
,
Const
.
Value
.
FLASH_MAGISK
);
activity
.
startActivity
(
intent
);
break
;
case
3
:
installInactiveSlot
(
activity
);
break
;
default
:
}
});
}
private
void
patchBoot
(
BaseActivity
a
)
{
Utils
.
toast
(
R
.
string
.
boot_file_patch_msg
,
Toast
.
LENGTH_LONG
);
intent
=
new
Intent
(
Intent
.
ACTION_GET_CONTENT
).
setType
(
"*/*"
);
activity
.
runWithPermission
(
new
String
[]{
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
},
()
->
activity
.
startActivityForResult
(
intent
,
Const
.
ID
.
SELECT_BOOT
,
Intent
intent
=
new
Intent
(
Intent
.
ACTION_GET_CONTENT
).
setType
(
"*/*"
);
a
.
runWithPermission
(
new
String
[]{
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
},
()
->
a
.
startActivityForResult
(
intent
,
Const
.
ID
.
SELECT_BOOT
,
(
requestCode
,
resultCode
,
data
)
->
{
if
(
requestCode
==
Const
.
ID
.
SELECT_BOOT
&&
resultCode
==
Activity
.
RESULT_OK
&&
data
!=
null
)
{
Intent
i
=
new
Intent
(
a
ctivity
,
Data
.
classMap
.
get
(
FlashActivity
.
class
))
Intent
i
=
new
Intent
(
a
,
Data
.
classMap
.
get
(
FlashActivity
.
class
))
.
putExtra
(
Const
.
Key
.
FLASH_SET_BOOT
,
data
.
getData
())
.
putExtra
(
Const
.
Key
.
FLASH_ACTION
,
Const
.
Value
.
PATCH_BOOT
);
a
ctivity
.
startActivity
(
i
);
a
.
startActivity
(
i
);
}
})
);
}
break
;
case
0
:
private
void
downloadOnly
(
BaseActivity
a
)
{
a
.
runWithPermission
(
new
String
[]
{
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
},
()
->
{
String
filename
=
Utils
.
fmt
(
"Magisk-v%s(%d).zip"
,
Data
.
remoteMagiskVersionString
,
Data
.
remoteMagiskVersionCode
);
Download
.
receive
(
activity
,
new
DownloadReceiver
()
{
NotificationProgress
progress
=
new
NotificationProgress
(
filename
);
AndroidNetworking
.
download
(
Data
.
magiskLink
,
Download
.
EXTERNAL_PATH
.
getPath
(),
filename
)
.
build
()
.
setDownloadProgressListener
(
progress
)
.
startDownload
(
new
DownloadListener
()
{
@Override
public
void
onDownloadDone
(
Context
context
,
Uri
uri
)
{
SnackbarMaker
.
showUri
(
activity
,
uri
);
public
void
onDownloadComplete
()
{
progress
.
defaultDone
();
SnackbarMaker
.
make
(
a
,
a
.
getString
(
R
.
string
.
internal_storage
,
"/Download/"
+
filename
),
Snackbar
.
LENGTH_LONG
).
show
();
}
},
Data
.
magiskLink
,
filename
);
break
;
case
2
:
intent
=
new
Intent
(
activity
,
Data
.
classMap
.
get
(
FlashActivity
.
class
))
.
putExtra
(
Const
.
Key
.
FLASH_ACTION
,
Const
.
Value
.
FLASH_MAGISK
);
activity
.
startActivity
(
intent
);
break
;
case
3
:
@Override
public
void
onError
(
ANError
anError
)
{}
});
}
);
}
private
void
installInactiveSlot
(
BaseActivity
activity
)
{
new
CustomAlertDialog
(
activity
)
.
setTitle
(
R
.
string
.
warning
)
.
setMessage
(
R
.
string
.
install_inactive_slot_msg
)
.
setCancelable
(
true
)
.
setPositiveButton
(
R
.
string
.
yes
,
(
d
,
i
)
->
{
Intent
i
t
=
new
Intent
(
activity
,
Data
.
classMap
.
get
(
FlashActivity
.
class
))
Intent
inten
t
=
new
Intent
(
activity
,
Data
.
classMap
.
get
(
FlashActivity
.
class
))
.
putExtra
(
Const
.
Key
.
FLASH_ACTION
,
Const
.
Value
.
FLASH_INACTIVE_SLOT
);
activity
.
startActivity
(
i
t
);
activity
.
startActivity
(
inten
t
);
})
.
setNegativeButton
(
R
.
string
.
no_thanks
,
null
)
.
show
();
break
;
default
:
}
});
}
}
app/src/full/java/com/topjohnwu/magisk/components/ManagerInstallDialog.java
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
.
components
;
import
android.Manifest
;
import
android.content.Intent
;
import
android.text.TextUtils
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.asyncs.MarkDownWindow
;
import
com.topjohnwu.magisk.
receivers.ManagerUpdate
;
import
com.topjohnwu.magisk.
utils.DlInstallManager
;
import
com.topjohnwu.magisk.utils.Utils
;
import
androidx.annotation.NonNull
;
...
...
@@ -19,19 +16,13 @@ public class ManagerInstallDialog extends CustomAlertDialog {
public
ManagerInstallDialog
(
@NonNull
BaseActivity
activity
)
{
super
(
activity
);
MagiskManager
mm
=
Data
.
MM
();
String
filename
=
Utils
.
fmt
(
"MagiskManager-v%s(%d).apk
"
,
String
name
=
Utils
.
fmt
(
"MagiskManager v%s(%d)
"
,
Data
.
remoteManagerVersionString
,
Data
.
remoteManagerVersionCode
);
setTitle
(
mm
.
getString
(
R
.
string
.
repo_install_title
,
mm
.
getString
(
R
.
string
.
app_name
)));
setMessage
(
mm
.
getString
(
R
.
string
.
repo_install_msg
,
file
name
));
setMessage
(
mm
.
getString
(
R
.
string
.
repo_install_msg
,
name
));
setCancelable
(
true
);
setPositiveButton
(
R
.
string
.
install
,
(
d
,
i
)
->
activity
.
runWithPermission
(
new
String
[]
{
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
},
()
->
{
Intent
intent
=
new
Intent
(
mm
,
Data
.
classMap
.
get
(
ManagerUpdate
.
class
));
intent
.
putExtra
(
Const
.
Key
.
INTENT_SET_LINK
,
Data
.
managerLink
);
intent
.
putExtra
(
Const
.
Key
.
INTENT_SET_FILENAME
,
filename
);
mm
.
sendBroadcast
(
intent
);
}))
.
setNegativeButton
(
R
.
string
.
no_thanks
,
null
);
setPositiveButton
(
R
.
string
.
install
,
(
d
,
i
)
->
DlInstallManager
.
upgrade
(
name
));
setNegativeButton
(
R
.
string
.
no_thanks
,
null
);
if
(!
TextUtils
.
isEmpty
(
Data
.
managerNoteLink
))
{
setNeutralButton
(
R
.
string
.
app_changelog
,
(
d
,
i
)
->
new
MarkDownWindow
(
activity
,
null
,
Data
.
managerNoteLink
).
exec
());
...
...
app/src/full/java/com/topjohnwu/magisk/components/NotificationProgress.java
0 → 100644
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
.
components
;
import
android.widget.Toast
;
import
com.androidnetworking.interfaces.DownloadProgressListener
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.utils.Notifications
;
import
com.topjohnwu.magisk.utils.Utils
;
import
androidx.core.app.NotificationCompat
;
import
androidx.core.app.NotificationManagerCompat
;
public
class
NotificationProgress
implements
DownloadProgressListener
{
private
NotificationManagerCompat
mgr
;
private
NotificationCompat
.
Builder
builder
;
private
long
prevTime
;
public
NotificationProgress
(
String
title
)
{
mgr
=
NotificationManagerCompat
.
from
(
Data
.
MM
());
builder
=
Notifications
.
progress
(
title
);
mgr
.
notify
(
Const
.
ID
.
DOWNLOAD_PROGRESS_ID
,
builder
.
build
());
prevTime
=
System
.
currentTimeMillis
();
Utils
.
toast
(
"Downloading "
+
title
,
Toast
.
LENGTH_SHORT
);
}
@Override
public
void
onProgress
(
long
bytesDownloaded
,
long
totalBytes
)
{
long
cur
=
System
.
currentTimeMillis
();
if
(
cur
-
prevTime
>=
1000
)
{
prevTime
=
cur
;
builder
.
setProgress
((
int
)
totalBytes
,
(
int
)
bytesDownloaded
,
false
);
builder
.
setContentText
(
bytesDownloaded
*
100
/
totalBytes
+
"%"
);
update
();
}
}
public
NotificationCompat
.
Builder
getBuilder
()
{
return
builder
;
}
public
void
update
()
{
mgr
.
notify
(
Const
.
ID
.
DOWNLOAD_PROGRESS_ID
,
builder
.
build
());
}
public
void
defaultDone
()
{
builder
.
setProgress
(
0
,
0
,
false
);
builder
.
setContentText
(
"Download done"
);
update
();
}
}
app/src/full/java/com/topjohnwu/magisk/components/UninstallDialog.java
View file @
0241a50c
...
...
@@ -2,29 +2,29 @@ package com.topjohnwu.magisk.components;
import
android.app.Activity
;
import
android.app.ProgressDialog
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.net.Uri
;
import
android.text.TextUtils
;
import
android.widget.Toast
;
import
com.androidnetworking.AndroidNetworking
;
import
com.androidnetworking.error.ANError
;
import
com.androidnetworking.interfaces.DownloadListener
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.FlashActivity
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.receivers.DownloadReceiver
;
import
com.topjohnwu.magisk.utils.Download
;
import
com.topjohnwu.magisk.utils.Utils
;
import
com.topjohnwu.superuser.Shell
;
import
java.io.File
;
import
androidx.annotation.NonNull
;
public
class
UninstallDialog
extends
CustomAlertDialog
{
public
UninstallDialog
(
@NonNull
Activity
activity
)
{
super
(
activity
);
MagiskManager
mm
=
Data
.
MM
();
setTitle
(
R
.
string
.
uninstall_magisk_title
);
setMessage
(
R
.
string
.
uninstall_magisk_msg
);
setNeutralButton
(
R
.
string
.
restore_img
,
(
d
,
i
)
->
{
...
...
@@ -41,17 +41,27 @@ public class UninstallDialog extends CustomAlertDialog {
});
});
if
(!
TextUtils
.
isEmpty
(
Data
.
uninstallerLink
))
{
setPositiveButton
(
R
.
string
.
complete_uninstall
,
(
d
,
i
)
->
Download
.
receive
(
activity
,
new
DownloadReceiver
()
{
setPositiveButton
(
R
.
string
.
complete_uninstall
,
(
d
,
i
)
->
{
File
zip
=
new
File
(
activity
.
getFilesDir
(),
"uninstaller.zip"
);
NotificationProgress
progress
=
new
NotificationProgress
(
zip
.
getName
());
AndroidNetworking
.
download
(
Data
.
uninstallerLink
,
zip
.
getParent
(),
zip
.
getName
())
.
build
()
.
setDownloadProgressListener
(
progress
)
.
startDownload
(
new
DownloadListener
()
{
@Override
public
void
onDownloadDone
(
Context
context
,
Uri
uri
)
{
Intent
intent
=
new
Intent
(
context
,
Data
.
classMap
.
get
(
FlashActivity
.
class
))
public
void
onDownloadComplete
()
{
progress
.
defaultDone
();
Intent
intent
=
new
Intent
(
activity
,
Data
.
classMap
.
get
(
FlashActivity
.
class
))
.
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
)
.
setData
(
uri
)
.
setData
(
Uri
.
fromFile
(
zip
)
)
.
putExtra
(
Const
.
Key
.
FLASH_ACTION
,
Const
.
Value
.
UNINSTALL
);
context
.
startActivity
(
intent
);
activity
.
startActivity
(
intent
);
}
},
Data
.
uninstallerLink
,
"magisk-uninstaller.zip"
));
@Override
public
void
onError
(
ANError
anError
)
{}
});
});
}
}
}
app/src/full/java/com/topjohnwu/magisk/container/Repo.java
View file @
0241a50c
...
...
@@ -7,7 +7,6 @@ import com.topjohnwu.magisk.Const;
import
com.topjohnwu.magisk.utils.Download
;
import
com.topjohnwu.magisk.utils.Logger
;
import
com.topjohnwu.magisk.utils.Utils
;
import
com.topjohnwu.magisk.utils.WebService
;
import
java.text.DateFormat
;
import
java.util.Date
;
...
...
@@ -26,7 +25,7 @@ public class Repo extends BaseModule {
}
public
void
update
()
throws
IllegalRepoException
{
String
props
[]
=
Utils
.
d
os2unix
(
WebService
.
getString
(
getManifestUrl
()
)).
split
(
"\\n"
);
String
props
[]
=
Utils
.
d
lString
(
getPropUrl
(
)).
split
(
"\\n"
);
try
{
parseProps
(
props
);
}
catch
(
NumberFormatException
e
)
{
...
...
@@ -57,7 +56,7 @@ public class Repo extends BaseModule {
return
String
.
format
(
Const
.
Url
.
ZIP_URL
,
getId
());
}
public
String
get
Manifest
Url
()
{
public
String
get
Prop
Url
()
{
return
String
.
format
(
Const
.
Url
.
FILE_URL
,
getId
(),
"module.prop"
);
}
...
...
app/src/full/java/com/topjohnwu/magisk/fragments/ModulesFragment.java
View file @
0241a50c
...
...
@@ -118,7 +118,7 @@ public class ModulesFragment extends BaseFragment implements Topic.Subscriber {
Shell
.
su
(
"/system/bin/reboot bootloader"
).
submit
();
return
true
;
case
R
.
id
.
reboot_download
:
Shell
.
su
(
"/system/bin/reboot
download
"
).
submit
();
Shell
.
su
(
"/system/bin/reboot
upgrade
"
).
submit
();
return
true
;
default
:
return
false
;
...
...
app/src/full/java/com/topjohnwu/magisk/fragments/SettingsFragment.java
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
.
fragments
;
import
android.annotation.SuppressLint
;
import
android.content.Context
;
import
android.content.SharedPreferences
;
import
android.net.Uri
;
import
android.os.Build
;
import
android.os.Bundle
;
import
android.view.LayoutInflater
;
...
...
@@ -18,15 +16,13 @@ import com.topjohnwu.magisk.MagiskManager;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.asyncs.CheckUpdates
;
import
com.topjohnwu.magisk.asyncs.PatchAPK
;
import
com.topjohnwu.magisk.
receivers.DownloadReceiv
er
;
import
com.topjohnwu.magisk.
utils.DlInstallManag
er
;
import
com.topjohnwu.magisk.utils.Download
;
import
com.topjohnwu.magisk.utils.FingerprintHelper
;
import
com.topjohnwu.magisk.utils.LocaleManager
;
import
com.topjohnwu.magisk.utils.RootUtils
;
import
com.topjohnwu.magisk.utils.Topic
;
import
com.topjohnwu.magisk.utils.Utils
;
import
com.topjohnwu.superuser.Shell
;
import
com.topjohnwu.superuser.ShellUtils
;
import
java.io.IOException
;
import
java.util.Locale
;
...
...
@@ -85,23 +81,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
});
Preference
restoreManager
=
findPreference
(
"restore"
);
restoreManager
.
setOnPreferenceClickListener
(
pref
->
{
Download
.
receive
(
requireActivity
(),
new
DownloadReceiver
()
{
@Override
public
void
onDownloadDone
(
Context
context
,
Uri
uri
)
{
Data
.
exportPrefs
();
Shell
.
su
(
"cp "
+
uri
.
getPath
()
+
" /data/local/tmp/manager.apk"
).
exec
();
if
(
ShellUtils
.
fastCmdResult
(
"pm install /data/local/tmp/manager.apk"
))
{
Shell
.
su
(
"rm -f /data/local/tmp/manager.apk"
).
exec
();
RootUtils
.
rmAndLaunch
(
context
.
getPackageName
(),
Const
.
ORIG_PKG_NAME
);
return
;
}
Shell
.
su
(
"rm -f /data/local/tmp/manager.apk"
).
exec
();
}
},
Data
.
managerLink
,
Utils
.
fmt
(
"MagiskManager-v%s.apk"
,
Data
.
remoteManagerVersionString
)
);
DlInstallManager
.
restore
();
return
true
;
});
findPreference
(
"clear"
).
setOnPreferenceClickListener
(
pref
->
{
...
...
app/src/full/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java
View file @
0241a50c
...
...
@@ -3,47 +3,16 @@ package com.topjohnwu.magisk.receivers;
import
android.content.BroadcastReceiver
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.net.Uri
;
import
android.os.AsyncTask
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.asyncs.PatchAPK
;
import
com.topjohnwu.magisk.utils.Download
;
import
com.topjohnwu.utils.JarMap
;
import
com.topjohnwu.utils.SignAPK
;
import
java.io.BufferedOutputStream
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.utils.DlInstallManager
;
public
class
ManagerUpdate
extends
BroadcastReceiver
{
@Override
public
void
onReceive
(
Context
context
,
Intent
intent
)
{
Download
.
receive
(
context
,
new
PatchedInstall
(),
intent
.
getStringExtra
(
Const
.
Key
.
INTENT_SET_LINK
),
intent
.
getStringExtra
(
Const
.
Key
.
INTENT_SET_FILENAME
)
);
}
private
static
class
PatchedInstall
extends
ManagerInstall
{
@Override
public
void
onDownloadDone
(
Context
context
,
Uri
uri
)
{
if
(!
context
.
getPackageName
().
equals
(
Const
.
ORIG_PKG_NAME
))
{
AsyncTask
.
THREAD_POOL_EXECUTOR
.
execute
(()
->
{
String
orig
=
uri
.
getPath
();
String
patch
=
orig
.
substring
(
0
,
orig
.
lastIndexOf
(
'.'
))
+
"-patched.apk"
;
try
{
JarMap
apk
=
new
JarMap
(
orig
);
PatchAPK
.
patchPackageID
(
apk
,
Const
.
ORIG_PKG_NAME
,
context
.
getPackageName
());
SignAPK
.
sign
(
apk
,
new
BufferedOutputStream
(
new
FileOutputStream
(
patch
)));
super
.
onDownloadDone
(
context
,
Uri
.
fromFile
(
new
File
(
patch
)));
}
catch
(
Exception
ignored
)
{
}
});
}
else
{
super
.
onDownloadDone
(
context
,
uri
);
}
}
Data
.
managerLink
=
intent
.
getStringExtra
(
Const
.
Key
.
INTENT_SET_LINK
);
DlInstallManager
.
upgrade
(
intent
.
getStringExtra
(
Const
.
Key
.
INTENT_SET_NAME
));
}
}
app/src/full/java/com/topjohnwu/magisk/services/OnBootService.java
View file @
0241a50c
...
...
@@ -5,7 +5,7 @@ import android.content.Intent;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.utils.Notification
Mgr
;
import
com.topjohnwu.magisk.utils.Notification
s
;
import
com.topjohnwu.superuser.Shell
;
import
com.topjohnwu.superuser.ShellUtils
;
...
...
@@ -28,6 +28,6 @@ public class OnBootService extends JobIntentService {
* to reboot if dtbo wasn't patched and patched by Magisk Manager.
* */
if
(
Shell
.
rootAccess
()
&&
ShellUtils
.
fastCmdResult
(
"mm_patch_dtbo"
))
Notification
Mgr
.
dtboPatched
();
Notification
s
.
dtboPatched
();
}
}
app/src/full/java/com/topjohnwu/magisk/utils/DlInstallManager.java
0 → 100644
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
.
utils
;
import
android.os.AsyncTask
;
import
com.androidnetworking.AndroidNetworking
;
import
com.androidnetworking.error.ANError
;
import
com.androidnetworking.interfaces.DownloadListener
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.asyncs.PatchAPK
;
import
com.topjohnwu.magisk.components.NotificationProgress
;
import
com.topjohnwu.superuser.ShellUtils
;
import
com.topjohnwu.utils.JarMap
;
import
com.topjohnwu.utils.SignAPK
;
import
java.io.BufferedOutputStream
;
import
java.io.File
;
import
java.io.FileOutputStream
;
public
class
DlInstallManager
{
public
static
void
upgrade
(
String
name
)
{
dlInstall
(
name
,
new
PatchPackageName
());
}
public
static
void
restore
()
{
String
name
=
Utils
.
fmt
(
"MagiskManager v%s(%d)"
,
Data
.
remoteManagerVersionString
,
Data
.
remoteManagerVersionCode
);
dlInstall
(
name
,
new
RestoreManager
());
}
public
static
void
dlInstall
(
String
name
,
ManagerDownloadListener
listener
)
{
MagiskManager
mm
=
Data
.
MM
();
File
apk
=
new
File
(
mm
.
getFilesDir
(),
"manager.apk"
);
NotificationProgress
progress
=
new
NotificationProgress
(
name
);
listener
.
setInstances
(
apk
,
progress
);
AndroidNetworking
.
download
(
Data
.
managerLink
,
apk
.
getParent
(),
apk
.
getName
())
.
setExecutor
(
AsyncTask
.
THREAD_POOL_EXECUTOR
)
.
build
()
.
setDownloadProgressListener
(
progress
)
.
startDownload
(
listener
);
}
public
abstract
static
class
ManagerDownloadListener
implements
DownloadListener
{
private
File
apk
;
private
NotificationProgress
progress
;
private
void
setInstances
(
File
apk
,
NotificationProgress
progress
)
{
this
.
apk
=
apk
;
this
.
progress
=
progress
;
}
public
abstract
void
onDownloadComplete
(
File
apk
,
NotificationProgress
progress
);
@Override
public
final
void
onDownloadComplete
()
{
onDownloadComplete
(
apk
,
progress
);
}
@Override
public
void
onError
(
ANError
anError
)
{}
}
private
static
class
PatchPackageName
extends
ManagerDownloadListener
{
@Override
public
void
onDownloadComplete
(
File
apk
,
NotificationProgress
progress
)
{
File
patched
=
apk
;
MagiskManager
mm
=
Data
.
MM
();
if
(!
mm
.
getPackageName
().
equals
(
Const
.
ORIG_PKG_NAME
))
{
progress
.
getBuilder
()
.
setProgress
(
0
,
0
,
true
)
.
setContentText
(
"Patching APK"
);
progress
.
update
();
patched
=
new
File
(
apk
.
getParent
(),
"patched.apk"
);
try
{
JarMap
jarMap
=
new
JarMap
(
apk
);
PatchAPK
.
patchPackageID
(
jarMap
,
Const
.
ORIG_PKG_NAME
,
mm
.
getPackageName
());
SignAPK
.
sign
(
jarMap
,
new
BufferedOutputStream
(
new
FileOutputStream
(
patched
)));
}
catch
(
Exception
e
)
{
return
;
}
}
progress
.
defaultDone
();
APKInstall
.
install
(
mm
,
patched
);
}
}
private
static
class
RestoreManager
extends
ManagerDownloadListener
{
@Override
public
void
onDownloadComplete
(
File
apk
,
NotificationProgress
progress
)
{
progress
.
defaultDone
();
Data
.
exportPrefs
();
if
(
ShellUtils
.
fastCmdResult
(
"pm install "
+
apk
))
RootUtils
.
rmAndLaunch
(
Data
.
MM
().
getPackageName
(),
Const
.
ORIG_PKG_NAME
);
}
}
}
app/src/full/java/com/topjohnwu/magisk/utils/Notification
Mgr
.java
→
app/src/full/java/com/topjohnwu/magisk/utils/Notification
s
.java
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
.
utils
;
import
android.app.NotificationManager
;
import
android.app.PendingIntent
;
import
android.content.Context
;
import
android.content.Intent
;
import
com.topjohnwu.magisk.Const
;
...
...
@@ -14,9 +12,10 @@ import com.topjohnwu.magisk.receivers.ManagerUpdate;
import
com.topjohnwu.magisk.receivers.RebootReceiver
;
import
androidx.core.app.NotificationCompat
;
import
androidx.core.app.NotificationManagerCompat
;
import
androidx.core.app.TaskStackBuilder
;
public
class
Notification
Mgr
{
public
class
Notification
s
{
public
static
void
magiskUpdate
()
{
MagiskManager
mm
=
Data
.
MM
();
...
...
@@ -37,19 +36,18 @@ public class NotificationMgr {
.
setAutoCancel
(
true
)
.
setContentIntent
(
pendingIntent
);
NotificationManager
notificationManager
=
(
NotificationManager
)
mm
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
);
notificationManager
.
notify
(
Const
.
ID
.
MAGISK_UPDATE_NOTIFICATION_ID
,
builder
.
build
());
NotificationManagerCompat
mgr
=
NotificationManagerCompat
.
from
(
mm
);
mgr
.
notify
(
Const
.
ID
.
MAGISK_UPDATE_NOTIFICATION_ID
,
builder
.
build
());
}
public
static
void
managerUpdate
()
{
MagiskManager
mm
=
Data
.
MM
();
String
filename
=
Utils
.
fmt
(
"MagiskManager-v%s(%d).apk
"
,
String
name
=
Utils
.
fmt
(
"MagiskManager v%s(%d)
"
,
Data
.
remoteManagerVersionString
,
Data
.
remoteManagerVersionCode
);
Intent
intent
=
new
Intent
(
mm
,
Data
.
classMap
.
get
(
ManagerUpdate
.
class
));
intent
.
putExtra
(
Const
.
Key
.
INTENT_SET_LINK
,
Data
.
managerLink
);
intent
.
putExtra
(
Const
.
Key
.
INTENT_SET_
FILENAME
,
file
name
);
intent
.
putExtra
(
Const
.
Key
.
INTENT_SET_
NAME
,
name
);
PendingIntent
pendingIntent
=
PendingIntent
.
getBroadcast
(
mm
,
Const
.
ID
.
APK_UPDATE_NOTIFICATION_ID
,
intent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
);
...
...
@@ -61,9 +59,8 @@ public class NotificationMgr {
.
setAutoCancel
(
true
)
.
setContentIntent
(
pendingIntent
);
NotificationManager
notificationManager
=
(
NotificationManager
)
mm
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
);
notificationManager
.
notify
(
Const
.
ID
.
APK_UPDATE_NOTIFICATION_ID
,
builder
.
build
());
NotificationManagerCompat
mgr
=
NotificationManagerCompat
.
from
(
mm
);
mgr
.
notify
(
Const
.
ID
.
APK_UPDATE_NOTIFICATION_ID
,
builder
.
build
());
}
public
static
void
dtboPatched
()
{
...
...
@@ -80,8 +77,16 @@ public class NotificationMgr {
.
setVibrate
(
new
long
[]{
0
,
100
,
100
,
100
})
.
addAction
(
R
.
drawable
.
ic_refresh
,
mm
.
getString
(
R
.
string
.
reboot
),
pendingIntent
);
NotificationManager
notificationManager
=
(
NotificationManager
)
mm
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
);
notificationManager
.
notify
(
Const
.
ID
.
DTBO_NOTIFICATION_ID
,
builder
.
build
());
NotificationManagerCompat
mgr
=
NotificationManagerCompat
.
from
(
mm
);
mgr
.
notify
(
Const
.
ID
.
DTBO_NOTIFICATION_ID
,
builder
.
build
());
}
public
static
NotificationCompat
.
Builder
progress
(
String
title
)
{
MagiskManager
mm
=
Data
.
MM
();
NotificationCompat
.
Builder
builder
=
new
NotificationCompat
.
Builder
(
mm
,
Const
.
ID
.
NOTIFICATION_CHANNEL
);
builder
.
setSmallIcon
(
R
.
drawable
.
ic_magisk_outline
)
.
setContentTitle
(
title
)
.
setProgress
(
0
,
0
,
true
);
return
builder
;
}
}
app/src/full/java/com/topjohnwu/magisk/utils/Utils.java
View file @
0241a50c
...
...
@@ -16,6 +16,7 @@ import android.os.AsyncTask;
import
android.provider.OpenableColumns
;
import
android.widget.Toast
;
import
com.androidnetworking.AndroidNetworking
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.Data
;
import
com.topjohnwu.magisk.MagiskManager
;
...
...
@@ -150,4 +151,9 @@ public class Utils {
return
Shell
.
rootAccess
()
&&
(
Const
.
USER_ID
==
0
||
Data
.
multiuserState
!=
Const
.
Value
.
MULTIUSER_MODE_OWNER_MANAGED
);
}
public
static
String
dlString
(
String
url
)
{
String
s
=
(
String
)
AndroidNetworking
.
get
(
url
).
build
().
executeForString
().
getResult
();
return
s
==
null
?
""
:
s
;
}
}
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/components/BaseActivity.java
deleted
100644 → 0
View file @
2a2e1236
package
com
.
topjohnwu
.
magisk
.
components
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.pm.PackageManager
;
import
android.os.Bundle
;
import
android.widget.Toast
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.utils.Download
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
androidx.core.app.ActivityCompat
;
import
androidx.core.content.ContextCompat
;
public
abstract
class
BaseActivity
extends
FlavorActivity
{
public
static
final
String
INTENT_PERM
=
"perm_dialog"
;
protected
static
Runnable
permissionGrantCallback
;
public
static
void
runWithPermission
(
Context
context
,
String
[]
permissions
,
Runnable
callback
)
{
boolean
granted
=
true
;
for
(
String
perm
:
permissions
)
{
if
(
ContextCompat
.
checkSelfPermission
(
context
,
perm
)
!=
PackageManager
.
PERMISSION_GRANTED
)
granted
=
false
;
}
if
(
granted
)
{
Download
.
EXTERNAL_PATH
.
mkdirs
();
callback
.
run
();
}
else
{
// Passed in context should be an activity if not granted, need to show dialog!
permissionGrantCallback
=
callback
;
if
(!(
context
instanceof
BaseActivity
))
{
// Start activity to show dialog
Intent
intent
=
new
Intent
(
context
,
a
.
g
.
class
);
intent
.
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
);
intent
.
putExtra
(
INTENT_PERM
,
permissions
);
context
.
startActivity
(
intent
);
}
else
{
ActivityCompat
.
requestPermissions
((
BaseActivity
)
context
,
permissions
,
0
);
}
}
}
public
void
runWithPermission
(
String
[]
permissions
,
Runnable
callback
)
{
runWithPermission
(
this
,
permissions
,
callback
);
}
@Override
protected
void
onCreate
(
@Nullable
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
String
[]
perms
=
getIntent
().
getStringArrayExtra
(
INTENT_PERM
);
if
(
perms
!=
null
)
ActivityCompat
.
requestPermissions
(
this
,
perms
,
0
);
}
@Override
public
void
onRequestPermissionsResult
(
int
requestCode
,
@NonNull
String
[]
permissions
,
@NonNull
int
[]
grantResults
)
{
boolean
grant
=
true
;
for
(
int
result
:
grantResults
)
{
if
(
result
!=
PackageManager
.
PERMISSION_GRANTED
)
grant
=
false
;
}
if
(
grant
)
{
if
(
permissionGrantCallback
!=
null
)
{
permissionGrantCallback
.
run
();
}
}
else
{
Toast
.
makeText
(
this
,
R
.
string
.
no_rw_storage
,
Toast
.
LENGTH_LONG
).
show
();
}
permissionGrantCallback
=
null
;
}
}
app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java
deleted
100644 → 0
View file @
2a2e1236
package
com
.
topjohnwu
.
magisk
.
receivers
;
import
android.app.DownloadManager
;
import
android.content.BroadcastReceiver
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.database.Cursor
;
import
android.net.Uri
;
import
android.widget.Toast
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.utils.Download
;
import
java.io.File
;
public
abstract
class
DownloadReceiver
extends
BroadcastReceiver
{
protected
File
mFile
;
private
long
downloadID
;
@Override
public
void
onReceive
(
Context
context
,
Intent
intent
)
{
DownloadManager
downloadManager
=
(
DownloadManager
)
context
.
getSystemService
(
Context
.
DOWNLOAD_SERVICE
);
String
action
=
intent
.
getAction
();
if
(
DownloadManager
.
ACTION_DOWNLOAD_COMPLETE
.
equals
(
action
))
{
DownloadManager
.
Query
query
=
new
DownloadManager
.
Query
();
query
.
setFilterById
(
downloadID
);
Cursor
c
=
downloadManager
.
query
(
query
);
if
(
c
.
moveToFirst
())
{
int
columnIndex
=
c
.
getColumnIndex
(
DownloadManager
.
COLUMN_STATUS
);
int
status
=
c
.
getInt
(
columnIndex
);
switch
(
status
)
{
case
DownloadManager
.
STATUS_SUCCESSFUL
:
Uri
uri
=
Uri
.
parse
(
c
.
getString
(
c
.
getColumnIndex
(
DownloadManager
.
COLUMN_LOCAL_URI
)));
onDownloadDone
(
context
,
uri
);
break
;
default
:
Toast
.
makeText
(
context
,
R
.
string
.
download_file_error
,
Toast
.
LENGTH_LONG
).
show
();
break
;
}
context
.
unregisterReceiver
(
this
);
}
c
.
close
();
}
Download
.
isDownloading
=
false
;
}
public
DownloadReceiver
setDownloadID
(
long
id
)
{
downloadID
=
id
;
return
this
;
}
public
DownloadReceiver
setFile
(
File
file
)
{
mFile
=
file
;
return
this
;
}
public
abstract
void
onDownloadDone
(
Context
context
,
Uri
uri
);
}
app/src/main/java/com/topjohnwu/magisk/
receivers/Manager
Install.java
→
app/src/main/java/com/topjohnwu/magisk/
utils/APK
Install.java
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
.
receiver
s
;
package
com
.
topjohnwu
.
magisk
.
util
s
;
import
android.content.Context
;
import
android.content.Intent
;
...
...
@@ -9,22 +9,20 @@ import java.io.File;
import
androidx.core.content.FileProvider
;
public
class
ManagerInstall
extends
DownloadReceiver
{
@Override
public
void
onDownloadDone
(
Context
context
,
Uri
uri
)
{
public
class
APKInstall
{
public
static
void
install
(
Context
c
,
File
apk
)
{
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
N
)
{
Intent
install
=
new
Intent
(
Intent
.
ACTION_INSTALL_PACKAGE
);
install
.
addFlags
(
Intent
.
FLAG_GRANT_READ_URI_PERMISSION
);
install
.
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
);
Uri
content
=
FileProvider
.
getUriForFile
(
context
,
context
.
getPackageName
()
+
".provider"
,
new
File
(
uri
.
getPath
()));
Uri
content
=
FileProvider
.
getUriForFile
(
c
,
c
.
getPackageName
()
+
".provider"
,
apk
);
install
.
setData
(
content
);
c
ontext
.
startActivity
(
install
);
c
.
startActivity
(
install
);
}
else
{
Intent
install
=
new
Intent
(
Intent
.
ACTION_VIEW
);
install
.
setDataAndType
(
uri
,
"application/vnd.android.package-archive"
);
install
.
setDataAndType
(
Uri
.
fromFile
(
apk
)
,
"application/vnd.android.package-archive"
);
install
.
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
);
c
ontext
.
startActivity
(
install
);
c
.
startActivity
(
install
);
}
}
}
app/src/main/java/com/topjohnwu/magisk/utils/Download.java
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
.
utils
;
import
android.Manifest
;
import
android.app.DownloadManager
;
import
android.content.Context
;
import
android.content.IntentFilter
;
import
android.net.ConnectivityManager
;
import
android.net.NetworkInfo
;
import
android.net.Uri
;
import
android.os.Environment
;
import
android.widget.Toast
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.components.BaseActivity
;
import
com.topjohnwu.magisk.receivers.DownloadReceiver
;
import
java.io.File
;
...
...
@@ -25,33 +16,6 @@ public class Download {
EXTERNAL_PATH
.
mkdirs
();
}
public
static
boolean
isDownloading
=
false
;
public
static
void
receive
(
Context
context
,
DownloadReceiver
receiver
,
String
link
,
String
filename
)
{
if
(
isDownloading
)
return
;
BaseActivity
.
runWithPermission
(
context
,
new
String
[]
{
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
},
()
->
{
File
file
=
new
File
(
EXTERNAL_PATH
,
getLegalFilename
(
filename
));
file
.
delete
();
Toast
.
makeText
(
context
,
context
.
getString
(
R
.
string
.
downloading_toast
,
filename
),
Toast
.
LENGTH_LONG
).
show
();
isDownloading
=
true
;
DownloadManager
.
Request
request
=
new
DownloadManager
.
Request
(
Uri
.
parse
(
link
))
.
setDestinationUri
(
Uri
.
fromFile
(
file
));
DownloadManager
dm
=
(
DownloadManager
)
context
.
getSystemService
(
Context
.
DOWNLOAD_SERVICE
);
receiver
.
setDownloadID
(
dm
.
enqueue
(
request
)).
setFile
(
file
);
context
.
getApplicationContext
().
registerReceiver
(
receiver
,
new
IntentFilter
(
DownloadManager
.
ACTION_DOWNLOAD_COMPLETE
));
});
}
public
static
String
getLegalFilename
(
CharSequence
filename
)
{
return
filename
.
toString
().
replace
(
" "
,
"_"
).
replace
(
"'"
,
""
).
replace
(
"\""
,
""
)
.
replace
(
"$"
,
""
).
replace
(
"`"
,
""
).
replace
(
"*"
,
""
).
replace
(
"/"
,
"_"
)
...
...
app/src/main/java/com/topjohnwu/magisk/utils/WebService.java
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
.
utils
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
import
java.util.List
;
import
java.util.Map
;
public
class
WebService
{
public
static
String
getString
(
String
url
)
{
return
getString
(
url
,
null
);
}
public
static
String
getString
(
String
url
,
Map
<
String
,
String
>
header
)
{
try
{
HttpURLConnection
conn
=
request
(
url
,
header
);
return
getString
(
conn
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
""
;
}
}
public
static
String
getString
(
HttpURLConnection
conn
)
{
try
{
StringBuilder
builder
=
new
StringBuilder
();
if
(
conn
.
getResponseCode
()
==
HttpURLConnection
.
HTTP_OK
)
{
try
(
BufferedReader
br
=
new
BufferedReader
(
new
InputStreamReader
(
conn
.
getInputStream
())))
{
int
len
;
char
buf
[]
=
new
char
[
4096
];
while
((
len
=
br
.
read
(
buf
))
!=
-
1
)
{
builder
.
append
(
buf
,
0
,
len
);
}
}
}
conn
.
disconnect
();
return
builder
.
toString
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
""
;
}
}
public
static
HttpURLConnection
request
(
String
address
,
Map
<
String
,
String
>
header
)
throws
IOException
{
public
static
HttpURLConnection
request
(
String
address
)
throws
IOException
{
URL
url
=
new
URL
(
address
);
HttpURLConnection
conn
=
(
HttpURLConnection
)
url
.
openConnection
();
conn
.
setReadTimeout
(
15000
);
conn
.
setConnectTimeout
(
15000
);
if
(
header
!=
null
)
{
for
(
Map
.
Entry
<
String
,
String
>
entry
:
header
.
entrySet
())
{
conn
.
setRequestProperty
(
entry
.
getKey
(),
entry
.
getValue
());
}
}
conn
.
connect
();
if
(
header
!=
null
)
{
header
.
clear
();
for
(
Map
.
Entry
<
String
,
List
<
String
>>
entry
:
conn
.
getHeaderFields
().
entrySet
())
{
List
<
String
>
l
=
entry
.
getValue
();
header
.
put
(
entry
.
getKey
(),
l
.
get
(
l
.
size
()
-
1
));
}
}
return
conn
;
}
public
static
HttpURLConnection
mustRequest
(
String
address
,
Map
<
String
,
String
>
header
)
throws
IOException
{
public
static
HttpURLConnection
mustRequest
(
String
address
)
throws
IOException
{
HttpURLConnection
conn
;
do
{
conn
=
WebService
.
request
(
address
,
header
);
conn
=
WebService
.
request
(
address
);
int
total
=
conn
.
getContentLength
();
if
(
total
<
0
)
conn
.
disconnect
();
...
...
app/src/main/res/xml/file_paths.xml
View file @
0241a50c
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name=
"internal_files"
path=
"."
/>
<external-path
name=
"external_files"
path=
"."
/>
</paths>
\ No newline at end of file
app/src/stub/AndroidManifest.xml
View file @
0241a50c
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
package=
"com.topjohnwu.magisk"
>
<application>
<application
tools:ignore=
"GoogleAppIndexingWarning"
>
<activity
android:name=
".NoUIActivity"
android:label=
"@string/app_name"
android:name=
".MainActivity"
android:theme=
"@android:style/Theme.Translucent.NoTitleBar"
>
<intent-filter>
<action
android:name=
"android.intent.action.MAIN"
/>
...
...
@@ -12,7 +15,7 @@
</intent-filter>
</activity>
<receiver
android:name=
".
receivers.
BootLauncher"
>
<receiver
android:name=
".BootLauncher"
>
<intent-filter>
<action
android:name=
"android.intent.action.BOOT_COMPLETED"
/>
</intent-filter>
...
...
app/src/stub/java/com/topjohnwu/magisk/
receivers/
BootLauncher.java
→
app/src/stub/java/com/topjohnwu/magisk/BootLauncher.java
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
.
receivers
;
package
com
.
topjohnwu
.
magisk
;
import
android.content.BroadcastReceiver
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.text.TextUtils
;
import
com.topjohnwu.magisk.NoUIActivity
;
public
class
BootLauncher
extends
BroadcastReceiver
{
@Override
public
void
onReceive
(
Context
context
,
Intent
intent
)
{
if
(
TextUtils
.
equals
(
intent
.
getAction
(),
Intent
.
ACTION_BOOT_COMPLETED
))
{
Intent
i
=
new
Intent
(
context
,
NoUI
Activity
.
class
).
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
);
Intent
i
=
new
Intent
(
context
,
Main
Activity
.
class
).
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
);
context
.
startActivity
(
i
);
}
}
...
...
app/src/stub/java/com/topjohnwu/magisk/MainActivity.java
0 → 100644
View file @
0241a50c
package
com
.
topjohnwu
.
magisk
;
import
android.app.Activity
;
import
android.app.AlertDialog
;
import
android.app.Application
;
import
android.os.AsyncTask
;
import
android.os.Bundle
;
import
com.topjohnwu.magisk.utils.APKInstall
;
import
com.topjohnwu.magisk.utils.Download
;
import
com.topjohnwu.magisk.utils.WebService
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
java.io.BufferedInputStream
;
import
java.io.BufferedOutputStream
;
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
;
public
class
MainActivity
extends
Activity
{
private
static
final
String
URL
=
"https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json"
;
private
String
apkLink
;
private
void
dlAPK
()
{
Application
app
=
getApplication
();
AsyncTask
.
THREAD_POOL_EXECUTOR
.
execute
(()
->
{
try
{
HttpURLConnection
conn
=
WebService
.
request
(
apkLink
);
File
apk
=
new
File
(
getFilesDir
(),
"manager.apk"
);
try
(
InputStream
in
=
new
BufferedInputStream
(
conn
.
getInputStream
());
OutputStream
out
=
new
BufferedOutputStream
(
new
FileOutputStream
(
apk
)))
{
int
len
;
byte
[]
buf
=
new
byte
[
4096
];
while
((
len
=
in
.
read
(
buf
))
!=
-
1
)
{
out
.
write
(
buf
,
0
,
len
);
}
}
conn
.
disconnect
();
APKInstall
.
install
(
app
,
apk
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
});
finish
();
}
private
void
dlJSON
()
throws
IOException
,
JSONException
{
HttpURLConnection
conn
=
WebService
.
request
(
URL
);
StringBuilder
builder
=
new
StringBuilder
();
if
(
conn
.
getResponseCode
()
==
HttpURLConnection
.
HTTP_OK
)
{
try
(
BufferedReader
br
=
new
BufferedReader
(
new
InputStreamReader
(
conn
.
getInputStream
())))
{
int
len
;
char
buf
[]
=
new
char
[
4096
];
while
((
len
=
br
.
read
(
buf
))
!=
-
1
)
{
builder
.
append
(
buf
,
0
,
len
);
}
}
}
conn
.
disconnect
();
JSONObject
json
=
new
JSONObject
(
builder
.
toString
());
JSONObject
manager
=
json
.
getJSONObject
(
"app"
);
apkLink
=
manager
.
getString
(
"link"
);
}
@Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
if
(
Download
.
checkNetworkStatus
(
this
))
{
AsyncTask
.
THREAD_POOL_EXECUTOR
.
execute
(()
->
{
try
{
dlJSON
();
runOnUiThread
(()
->
{
new
AlertDialog
.
Builder
(
this
,
AlertDialog
.
THEME_DEVICE_DEFAULT_LIGHT
)
.
setCancelable
(
false
)
.
setTitle
(
R
.
string
.
app_name
)
.
setMessage
(
R
.
string
.
upgrade_msg
)
.
setPositiveButton
(
R
.
string
.
yes
,
(
d
,
w
)
->
dlAPK
())
.
setNegativeButton
(
R
.
string
.
no_thanks
,
(
d
,
w
)
->
finish
())
.
show
();
});
}
catch
(
JSONException
|
IOException
e
)
{
finish
();
}
});
}
else
{
new
AlertDialog
.
Builder
(
this
,
AlertDialog
.
THEME_DEVICE_DEFAULT_LIGHT
)
.
setCancelable
(
false
)
.
setTitle
(
R
.
string
.
app_name
)
.
setMessage
(
R
.
string
.
no_internet_msg
)
.
setNegativeButton
(
R
.
string
.
ok
,
(
d
,
w
)
->
finish
())
.
show
();
}
}
}
app/src/stub/java/com/topjohnwu/magisk/NoUIActivity.java
deleted
100644 → 0
View file @
2a2e1236
package
com
.
topjohnwu
.
magisk
;
import
android.Manifest
;
import
android.app.AlertDialog
;
import
android.os.AsyncTask
;
import
android.os.Bundle
;
import
com.topjohnwu.magisk.components.BaseActivity
;
import
com.topjohnwu.magisk.receivers.ManagerInstall
;
import
com.topjohnwu.magisk.utils.Download
;
import
com.topjohnwu.magisk.utils.WebService
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
java.util.Locale
;
public
class
NoUIActivity
extends
BaseActivity
{
private
String
apkLink
;
private
String
version
;
private
int
versionCode
;
public
static
final
String
URL
=
"https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json"
;
@Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
if
(
Download
.
checkNetworkStatus
(
this
))
{
AsyncTask
.
THREAD_POOL_EXECUTOR
.
execute
(()
->
{
String
str
=
WebService
.
getString
(
URL
);
try
{
JSONObject
json
=
new
JSONObject
(
str
);
JSONObject
manager
=
json
.
getJSONObject
(
"app"
);
version
=
manager
.
getString
(
"version"
);
versionCode
=
manager
.
getInt
(
"versionCode"
);
apkLink
=
manager
.
getString
(
"link"
);
}
catch
(
JSONException
e
)
{
e
.
printStackTrace
();
finish
();
return
;
}
runOnUiThread
(()
->
{
String
filename
=
String
.
format
(
Locale
.
US
,
"MagiskManager-v%s(%d).apk"
,
version
,
versionCode
);
new
AlertDialog
.
Builder
(
this
,
AlertDialog
.
THEME_DEVICE_DEFAULT_LIGHT
)
.
setCancelable
(
false
)
.
setTitle
(
R
.
string
.
app_name
)
.
setMessage
(
R
.
string
.
upgrade_msg
)
.
setPositiveButton
(
R
.
string
.
yes
,
(
d
,
w
)
->
runWithPermission
(
new
String
[]
{
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
},
()
->
{
Download
.
receive
(
this
,
new
ManagerInstall
(),
apkLink
,
filename
);
finish
();
}))
.
setNegativeButton
(
R
.
string
.
no_thanks
,
(
d
,
w
)
->
finish
())
.
show
();
});
});
}
else
{
new
AlertDialog
.
Builder
(
this
,
AlertDialog
.
THEME_DEVICE_DEFAULT_LIGHT
)
.
setCancelable
(
false
)
.
setTitle
(
R
.
string
.
app_name
)
.
setMessage
(
R
.
string
.
no_internet_msg
)
.
setNegativeButton
(
R
.
string
.
ok
,
(
d
,
w
)
->
finish
())
.
show
();
}
}
}
app/src/stub/java/com/topjohnwu/magisk/components/FlavorActivity.java
deleted
100644 → 0
View file @
2a2e1236
package
com
.
topjohnwu
.
magisk
.
components
;
import
android.app.Activity
;
public
abstract
class
FlavorActivity
extends
Activity
{}
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