mirror of
https://github.com/topjohnwu/Magisk
synced 2025-11-01 12:30:51 +01:00
Compare commits
366 Commits
manager-v4
...
manager-v5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47ccf4b1f5 | ||
|
|
a356b21895 | ||
|
|
614a36c888 | ||
|
|
f520fe36bd | ||
|
|
7273a1c34d | ||
|
|
dc45cbce37 | ||
|
|
708d8f75c0 | ||
|
|
bd37d90228 | ||
|
|
b1ad691464 | ||
|
|
f4e7baf31e | ||
|
|
c0e60c41f2 | ||
|
|
c8dad43e00 | ||
|
|
a8f124704d | ||
|
|
eed2816491 | ||
|
|
a6334b3e35 | ||
|
|
334beebfeb | ||
|
|
13dad848bd | ||
|
|
e518f4cef8 | ||
|
|
c8fd5da2da | ||
|
|
3a74729ecc | ||
|
|
49c672ac4d | ||
|
|
b570cb5b77 | ||
|
|
97bf388471 | ||
|
|
1a32aaea6f | ||
|
|
4635883dec | ||
|
|
3ba6db4a50 | ||
|
|
2f1de25747 | ||
|
|
f60fd42ac0 | ||
|
|
ecc8f9c792 | ||
|
|
e295dfdcf7 | ||
|
|
fc42c25390 | ||
|
|
27d5858e06 | ||
|
|
e1ef732b60 | ||
|
|
9840b95c21 | ||
|
|
a6f8446d81 | ||
|
|
c1c844c830 | ||
|
|
389299afd1 | ||
|
|
826543a291 | ||
|
|
4ac83cfded | ||
|
|
64c363ce53 | ||
|
|
cca4347bf9 | ||
|
|
3ae3d4926a | ||
|
|
36025d6d9f | ||
|
|
e171362e3e | ||
|
|
3e0bf2ae15 | ||
|
|
07aa9f4b8b | ||
|
|
b2d9f3fc64 | ||
|
|
5fb3e9167e | ||
|
|
99c74b31be | ||
|
|
ce5b13824e | ||
|
|
c39170c42e | ||
|
|
fd19fbf300 | ||
|
|
166469827f | ||
|
|
a34ed538b6 | ||
|
|
5f22d3e055 | ||
|
|
fdd700f3e5 | ||
|
|
adf930f126 | ||
|
|
05f41928cd | ||
|
|
2ee0829871 | ||
|
|
743560825d | ||
|
|
e3d84ac349 | ||
|
|
266c832b30 | ||
|
|
f5374a024e | ||
|
|
4956d826fb | ||
|
|
f5cc2af5d0 | ||
|
|
5880d4a6ec | ||
|
|
ae05dce958 | ||
|
|
9ebe372a9a | ||
|
|
e6e04cc5b3 | ||
|
|
12352510fd | ||
|
|
2b3d927937 | ||
|
|
a8890740f5 | ||
|
|
f60d7ee54b | ||
|
|
896ca2ef6b | ||
|
|
c036f6d529 | ||
|
|
6f457c0c59 | ||
|
|
13bf1b27b4 | ||
|
|
f742bb1c47 | ||
|
|
aa0b9e2db2 | ||
|
|
c10076f7ed | ||
|
|
bcd92499f2 | ||
|
|
b2bb0d4f72 | ||
|
|
e140481f14 | ||
|
|
186bd11463 | ||
|
|
a0490d6687 | ||
|
|
beef740ade | ||
|
|
2ac7786a90 | ||
|
|
a3fb5e910f | ||
|
|
319afe86b5 | ||
|
|
762ab66b86 | ||
|
|
0c239a42de | ||
|
|
e9322fba26 | ||
|
|
39b6df27b3 | ||
|
|
b1ee284e7f | ||
|
|
e986332bf2 | ||
|
|
48f9b27381 | ||
|
|
42a6e0dd10 | ||
|
|
d4798b02ac | ||
|
|
963edfe8ab | ||
|
|
53237f3ae0 | ||
|
|
64da9281a4 | ||
|
|
ab7fd9799d | ||
|
|
f6bcc84251 | ||
|
|
35dc3d9df9 | ||
|
|
566714a75d | ||
|
|
c92f30b122 | ||
|
|
294ad094c4 | ||
|
|
c1a0f520f9 | ||
|
|
773c24b7fc | ||
|
|
8f926c7ca9 | ||
|
|
c562cbc2bb | ||
|
|
3fbbb0865a | ||
|
|
7d5f612a48 | ||
|
|
4a5a36440b | ||
|
|
43dd5cfea1 | ||
|
|
7b5fec1842 | ||
|
|
5762ded601 | ||
|
|
a3abb86daa | ||
|
|
4f5c656b05 | ||
|
|
a31cddbe7b | ||
|
|
b4ecd93f1c | ||
|
|
0acc23e058 | ||
|
|
cdd5f9b628 | ||
|
|
4c9f5f4655 | ||
|
|
b80ba13cb4 | ||
|
|
8260bdc09c | ||
|
|
24f856e02b | ||
|
|
3aa619b928 | ||
|
|
4cb5e98d94 | ||
|
|
272910575e | ||
|
|
a15a62f4bc | ||
|
|
53cf11db8c | ||
|
|
01052fbe47 | ||
|
|
a5e1e075c7 | ||
|
|
6be32ac688 | ||
|
|
b362c0ef38 | ||
|
|
bba9969e31 | ||
|
|
007ba24809 | ||
|
|
df21539311 | ||
|
|
2592cb6019 | ||
|
|
f7df17a7ed | ||
|
|
62f42b72f8 | ||
|
|
a1ba4fda6f | ||
|
|
1c06b04c45 | ||
|
|
2ee22fd374 | ||
|
|
4c230d9e61 | ||
|
|
727294fbbe | ||
|
|
478c43969b | ||
|
|
79b5303350 | ||
|
|
ce4b742b25 | ||
|
|
a9dc15bda5 | ||
|
|
ba6387ff5c | ||
|
|
8fa98508b7 | ||
|
|
decdbaecf9 | ||
|
|
6d87cf9be0 | ||
|
|
94f434c4a6 | ||
|
|
7ba867c30b | ||
|
|
3424395e10 | ||
|
|
926c7359a2 | ||
|
|
ec0af99a2e | ||
|
|
b4d948886c | ||
|
|
4d8d79372a | ||
|
|
04a589722c | ||
|
|
d4a10e2873 | ||
|
|
4998ad6c7e | ||
|
|
a07ca5ff50 | ||
|
|
f07e7571ab | ||
|
|
834c16485c | ||
|
|
04a4265ef3 | ||
|
|
0ec473195d | ||
|
|
0bf09256b0 | ||
|
|
db8fd2c913 | ||
|
|
dbe6e5b3d7 | ||
|
|
cc81cd446b | ||
|
|
439c7118f1 | ||
|
|
d8154a5815 | ||
|
|
4e3787bc0d | ||
|
|
02e0955924 | ||
|
|
a78950e822 | ||
|
|
1ce1a94a35 | ||
|
|
977b6d9f67 | ||
|
|
b5e6dbd797 | ||
|
|
833e6688f1 | ||
|
|
bc22c9f84f | ||
|
|
2149a7d116 | ||
|
|
29175d2c17 | ||
|
|
803454d5c8 | ||
|
|
36cf32dc42 | ||
|
|
657f4ab303 | ||
|
|
ea6552615d | ||
|
|
4bf3287fce | ||
|
|
832c2034c2 | ||
|
|
b0aa26e1f1 | ||
|
|
e52baeb967 | ||
|
|
8268eb9a83 | ||
|
|
3cc458abd9 | ||
|
|
337b4c4268 | ||
|
|
001f8657f6 | ||
|
|
ea884e7fa1 | ||
|
|
1b1394cf5d | ||
|
|
1eef930dbb | ||
|
|
1e175e74ed | ||
|
|
75a46c365e | ||
|
|
8e7b8825f5 | ||
|
|
2ecbca303b | ||
|
|
8195a4d616 | ||
|
|
7ba40f925f | ||
|
|
345cd1795f | ||
|
|
959aaee045 | ||
|
|
53477f0f59 | ||
|
|
5716218f41 | ||
|
|
9df6b9d5c0 | ||
|
|
ec46031d36 | ||
|
|
55b84d166a | ||
|
|
34ae8bacec | ||
|
|
cb4e5ca0f7 | ||
|
|
0ba45468c4 | ||
|
|
710502784e | ||
|
|
0275a8558d | ||
|
|
58acc75cf6 | ||
|
|
874ababb9f | ||
|
|
3771e6b0cd | ||
|
|
33eaefa966 | ||
|
|
cd7e236d57 | ||
|
|
54c0b7c7d5 | ||
|
|
a2177daec2 | ||
|
|
628386b453 | ||
|
|
b222bfb3e0 | ||
|
|
ab199d883d | ||
|
|
356065d1ee | ||
|
|
76e7c5623d | ||
|
|
085fba050a | ||
|
|
295334d3ac | ||
|
|
36124ddca4 | ||
|
|
bd6585765e | ||
|
|
c325deb4ed | ||
|
|
73bb0b10ee | ||
|
|
72820b162c | ||
|
|
89e5b8d057 | ||
|
|
da4f53ebbb | ||
|
|
8458553b74 | ||
|
|
55ecc41d06 | ||
|
|
28fcdf2cbb | ||
|
|
24087679a8 | ||
|
|
5ac6a8cb4a | ||
|
|
668d85d14e | ||
|
|
c11a3dc95c | ||
|
|
56f57c20a2 | ||
|
|
240d14779a | ||
|
|
3550d1e61c | ||
|
|
6513ad249c | ||
|
|
50297b1880 | ||
|
|
f189b78b9e | ||
|
|
5c0250f495 | ||
|
|
2093f726e9 | ||
|
|
10efe3859d | ||
|
|
6933bcf7bb | ||
|
|
2ea046cd80 | ||
|
|
f4097a372b | ||
|
|
87ea2a2bef | ||
|
|
cc14a1c361 | ||
|
|
bcdface60d | ||
|
|
4dc9419d2e | ||
|
|
d2bcac813e | ||
|
|
080c37a7f6 | ||
|
|
f9a3838db6 | ||
|
|
1e61db104b | ||
|
|
30a9c7718d | ||
|
|
34b052b5d3 | ||
|
|
aaa12853ad | ||
|
|
b0ab55b0bf | ||
|
|
d2f8496f4e | ||
|
|
1a69b16d36 | ||
|
|
b5e8673e62 | ||
|
|
264c6a50b6 | ||
|
|
493642eb38 | ||
|
|
28d42b9164 | ||
|
|
42f29062ca | ||
|
|
c4377ed6c2 | ||
|
|
7d283ed65f | ||
|
|
bf1f941e50 | ||
|
|
789fef34ba | ||
|
|
1daf5a611c | ||
|
|
6aed1db67e | ||
|
|
cf68854770 | ||
|
|
711392c73b | ||
|
|
9573c32481 | ||
|
|
a15f80f79d | ||
|
|
23e7475f06 | ||
|
|
1eb571b787 | ||
|
|
dd3b716d85 | ||
|
|
28649c07e3 | ||
|
|
961e02be0d | ||
|
|
a161491bfd | ||
|
|
e0b4d1c1e4 | ||
|
|
fd4aaab137 | ||
|
|
42d14d5ca2 | ||
|
|
d3ff482c9b | ||
|
|
f682368eeb | ||
|
|
4a5d033efb | ||
|
|
343161b195 | ||
|
|
bc576a9659 | ||
|
|
19e407fcc4 | ||
|
|
bc7327d004 | ||
|
|
666fa1c797 | ||
|
|
0eda4a7821 | ||
|
|
862058fd2b | ||
|
|
69e5bcd57d | ||
|
|
efeddda328 | ||
|
|
ff6938280e | ||
|
|
1e4425b30f | ||
|
|
b5d1d8cdad | ||
|
|
029be5ccca | ||
|
|
29c2d785b5 | ||
|
|
abda8cfa32 | ||
|
|
44e7d79d4c | ||
|
|
9a1dc8ee0e | ||
|
|
27879c3f01 | ||
|
|
29096eb5d7 | ||
|
|
a573baea03 | ||
|
|
5af07c4531 | ||
|
|
44e36feb09 | ||
|
|
2a7d996881 | ||
|
|
738f943a68 | ||
|
|
47e62a5681 | ||
|
|
1ecbfd7590 | ||
|
|
67c139a04b | ||
|
|
31cc008249 | ||
|
|
9cb026439d | ||
|
|
e6f10176c6 | ||
|
|
0917c79470 | ||
|
|
597baa986d | ||
|
|
75cc4b4843 | ||
|
|
aac088d496 | ||
|
|
a822e5bbc5 | ||
|
|
c527249c21 | ||
|
|
9ef798f534 | ||
|
|
e69b99f089 | ||
|
|
55b8079e86 | ||
|
|
e272dbe9af | ||
|
|
962f8354ac | ||
|
|
20e4a960f7 | ||
|
|
82249cb50a | ||
|
|
fad417e553 | ||
|
|
5ba692f50c | ||
|
|
907e01e524 | ||
|
|
b8ed23efa7 | ||
|
|
2b3bbf7e67 | ||
|
|
464fe627a3 | ||
|
|
6a9e39c470 | ||
|
|
7fec9a3cc6 | ||
|
|
008f6ef462 | ||
|
|
2440c108ca | ||
|
|
430baad8a4 | ||
|
|
51132e74b4 | ||
|
|
a4f33e106a | ||
|
|
baba3190e0 | ||
|
|
47b13aa5ea | ||
|
|
ae88d3054d | ||
|
|
411b600e14 | ||
|
|
0a0ad9a184 | ||
|
|
234bead59e | ||
|
|
76de310986 | ||
|
|
817f050bcd | ||
|
|
60ae685d1e | ||
|
|
4c7bdbb284 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -3,6 +3,10 @@
|
|||||||
/local.properties
|
/local.properties
|
||||||
.idea/
|
.idea/
|
||||||
/build
|
/build
|
||||||
app/app-release.apk
|
app/release
|
||||||
*.hprof
|
*.hprof
|
||||||
app/.externalNativeBuild/
|
app/.externalNativeBuild/
|
||||||
|
*.sh
|
||||||
|
public.certificate.x509.pem
|
||||||
|
private.key.pk8
|
||||||
|
*.apk
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
# Magisk Manager
|
# Magisk Manager
|
||||||
The project should be built with Android Studio version 2.2.0+
|
This is one of the submodules used in Magisk. The project is licensed under GPL v3 (or newer).
|
||||||
I use Java 8 features, which requires Jack compiler and it's only available in 2.2.0+
|
More info are written in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk)
|
||||||
Also, you need to install CMake and NDK to build the zipadjust library for zip preprocessing
|
|
||||||
|
## Building Notes
|
||||||
|
You need to install CMake and NDK to build the zipadjust library.
|
||||||
|
There are several files required to let Magisk Manager work properly, and they can be copied by using the build script in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk). These files are: `magisk_uninstaller.sh`, `util_functions.sh`, `public.certificate.x509.pem`, and `private.key.pk8` under the `app/src/main/assets` folder.
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 25
|
compileSdkVersion 27
|
||||||
buildToolsVersion "25.0.2"
|
buildToolsVersion "27.0.1"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.topjohnwu.magisk"
|
applicationId "com.topjohnwu.magisk"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 27
|
||||||
versionCode 26
|
versionCode 63
|
||||||
versionName "4.2.7"
|
versionName "5.4.2"
|
||||||
jackOptions {
|
|
||||||
enabled true
|
|
||||||
jackInProcess true
|
|
||||||
}
|
|
||||||
ndk {
|
ndk {
|
||||||
moduleName 'zipadjust'
|
moduleName 'zipadjust'
|
||||||
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
||||||
}
|
}
|
||||||
|
javaCompileOptions {
|
||||||
|
annotationProcessorOptions {
|
||||||
|
argument('butterknife.debuggable', 'false')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
|
shrinkResources true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,34 +33,34 @@ android {
|
|||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
dexOptions {
|
dexOptions {
|
||||||
preDexLibraries = true
|
preDexLibraries true
|
||||||
|
javaMaxHeapSize "2g"
|
||||||
}
|
}
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
path 'src/main/jni/CMakeLists.txt'
|
path 'src/main/jni/CMakeLists.txt'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lintOptions {
|
||||||
|
disable 'MissingTranslation'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
google()
|
||||||
maven { url "https://jitpack.io" }
|
maven { url "https://jitpack.io" }
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
implementation project(':crypto')
|
||||||
compile 'com.android.support:recyclerview-v7:25.3.0'
|
implementation 'com.android.support:recyclerview-v7:27.0.1'
|
||||||
compile 'com.android.support:cardview-v7:25.3.0'
|
implementation 'com.android.support:cardview-v7:27.0.1'
|
||||||
compile 'com.android.support:design:25.3.0'
|
implementation 'com.android.support:design:27.0.1'
|
||||||
compile 'com.android.support:support-v4:25.3.0'
|
implementation 'com.android.support:support-v4:27.0.1'
|
||||||
compile 'com.jakewharton:butterknife:8.5.1'
|
implementation 'com.jakewharton:butterknife:8.8.1'
|
||||||
compile 'com.github.clans:fab:1.6.4'
|
implementation 'com.atlassian.commonmark:commonmark:0.10.0'
|
||||||
compile 'com.thoughtbot:expandablerecyclerview:1.4'
|
implementation 'org.kamranzafar:jtar:2.3'
|
||||||
compile 'us.feras.mdv:markdownview:1.1.0'
|
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
|
||||||
compile 'com.madgag.spongycastle:core:1.54.0.0'
|
|
||||||
compile 'com.madgag.spongycastle:prov:1.54.0.0'
|
|
||||||
compile 'com.madgag.spongycastle:pkix:1.54.0.0'
|
|
||||||
compile 'com.madgag.spongycastle:pg:1.54.0.0'
|
|
||||||
compile 'com.google.android.gms:play-services-safetynet:9.0.1'
|
|
||||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
app/proguard-rules.pro
vendored
11
app/proguard-rules.pro
vendored
@@ -16,10 +16,9 @@
|
|||||||
# public *;
|
# public *;
|
||||||
#}
|
#}
|
||||||
|
|
||||||
-keep class android.support.v7.internal.** { *; }
|
# Keep all names, we are open source anyway :)
|
||||||
-keep interface android.support.v7.internal.** { *; }
|
-keepnames class ** { *; }
|
||||||
-keep class android.support.v7.** { *; }
|
|
||||||
-keep interface android.support.v7.** { *; }
|
|
||||||
|
|
||||||
# SpongyCastle
|
# BouncyCastle
|
||||||
-keep class org.spongycastle.** {*;}
|
-keep class org.bouncycastle.jcajce.provider.** { *; }
|
||||||
|
-dontwarn javax.naming.**
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest package="com.topjohnwu.magisk"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
package="com.topjohnwu.magisk">
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".MagiskManager"
|
android:name=".MagiskManager"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
|
android:directBootAware="true"
|
||||||
|
tools:ignore="UnusedAttribute">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:exported="true"/>
|
android:exported="true" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".SplashActivity"
|
android:name=".SplashActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
@@ -30,16 +31,22 @@
|
|||||||
android:theme="@style/SplashTheme">
|
android:theme="@style/SplashTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".AboutActivity"
|
android:name=".AboutActivity"
|
||||||
android:theme="@style/AppTheme.Transparent"/>
|
android:theme="@style/AppTheme.Transparent" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".SettingsActivity"
|
android:name=".SettingsActivity"
|
||||||
android:theme="@style/AppTheme.Transparent" />
|
android:theme="@style/AppTheme.Transparent" />
|
||||||
|
<activity
|
||||||
|
android:name=".FlashActivity"
|
||||||
|
android:screenOrientation="nosensor"
|
||||||
|
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||||
|
android:theme="@style/AppTheme.Transparent" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".superuser.RequestActivity"
|
android:name=".superuser.RequestActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
@@ -52,21 +59,28 @@
|
|||||||
android:taskAffinity="internal.superuser"
|
android:taskAffinity="internal.superuser"
|
||||||
android:theme="@style/SuRequest" />
|
android:theme="@style/SuRequest" />
|
||||||
|
|
||||||
<receiver
|
<receiver android:name=".superuser.SuReceiver" />
|
||||||
android:name=".superuser.SuReceiver" />
|
|
||||||
|
|
||||||
<receiver android:name=".receivers.BootReceiver">
|
<receiver android:name=".receivers.BootReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.PackageReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||||
|
<action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
|
||||||
|
|
||||||
<service android:name=".services.BootupIntentService" />
|
<data android:scheme="package" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receivers.ManagerUpdate" />
|
||||||
|
<receiver android:name=".receivers.RebootReceiver" />
|
||||||
|
|
||||||
|
<service android:name=".services.OnBootIntentService" />
|
||||||
<service
|
<service
|
||||||
android:name=".services.UpdateCheckService"
|
android:name=".services.UpdateCheckService"
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
android:exported="true"
|
||||||
android:exported="true" />
|
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="android.support.v4.content.FileProvider"
|
android:name="android.support.v4.content.FileProvider"
|
||||||
@@ -78,10 +92,11 @@
|
|||||||
android:resource="@xml/file_paths" />
|
android:resource="@xml/file_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<!-- Hardcode GMS version -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.gms.version"
|
android:name="com.google.android.gms.version"
|
||||||
android:value="@integer/google_play_services_version" />
|
android:value="11717000" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
[ -z $BOOTMODE ] && BOOTMODE=false
|
|
||||||
|
|
||||||
# This path should work in any cases
|
|
||||||
TMPDIR=/dev/tmp
|
|
||||||
|
|
||||||
BOOTTMP=$TMPDIR/boottmp
|
|
||||||
MAGISKBIN=/data/magisk
|
|
||||||
CHROMEDIR=$MAGISKBIN/chromeos
|
|
||||||
|
|
||||||
SYSTEMLIB=/system/lib
|
|
||||||
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64
|
|
||||||
|
|
||||||
# Default permissions
|
|
||||||
umask 022
|
|
||||||
|
|
||||||
ui_print_wrapper() {
|
|
||||||
type ui_print >/dev/null && ui_print "$1" || echo "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
grep_prop() {
|
|
||||||
REGEX="s/^$1=//p"
|
|
||||||
shift
|
|
||||||
FILES=$@
|
|
||||||
if [ -z "$FILES" ]; then
|
|
||||||
FILES='/system/build.prop'
|
|
||||||
fi
|
|
||||||
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
|
|
||||||
}
|
|
||||||
|
|
||||||
find_boot_image() {
|
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
|
||||||
for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
|
|
||||||
BOOTIMAGE=`readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION`
|
|
||||||
if [ ! -z "$BOOTIMAGE" ]; then break; fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
|
||||||
FSTAB="/etc/recovery.fstab"
|
|
||||||
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
|
|
||||||
[ -f "$FSTAB" ] && BOOTIMAGE=`grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*'`
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
# Set permissions
|
|
||||||
chmod -R 755 $CHROMEDIR/futility $MAGISKBIN 2>/dev/null
|
|
||||||
# Temporary busybox for installation
|
|
||||||
mkdir -p $TMPDIR/busybox
|
|
||||||
$MAGISKBIN/busybox --install -s $TMPDIR/busybox
|
|
||||||
rm -f $TMPDIR/busybox/su $TMPDIR/busybox/sh $TMPDIR/busybox/reboot
|
|
||||||
PATH=$TMPDIR/busybox:$PATH
|
|
||||||
|
|
||||||
# Find the boot image
|
|
||||||
find_boot_image
|
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
|
||||||
ui_print_wrapper "! Unable to detect boot image"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ui_print_wrapper "- Found Boot Image: $BOOTIMAGE"
|
|
||||||
|
|
||||||
rm -rf $BOOTTMP 2>/dev/null
|
|
||||||
mkdir -p $BOOTTMP
|
|
||||||
cd $BOOTTMP
|
|
||||||
|
|
||||||
ui_print_wrapper "- Unpacking boot image"
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --unpack $BOOTIMAGE
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
ui_print_wrapper "! Unable to unpack boot image"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update our previous backup to new format if exists
|
|
||||||
if [ -f /data/stock_boot.img ]; then
|
|
||||||
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --sha1 /data/stock_boot.img | tail -n 1`
|
|
||||||
STOCKDUMP=/data/stock_boot_${SHA1}.img
|
|
||||||
mv /data/stock_boot.img $STOCKDUMP
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --compress $STOCKDUMP
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Detect boot image state
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-test ramdisk.cpio
|
|
||||||
case $? in
|
|
||||||
0 )
|
|
||||||
ui_print_wrapper "! Magisk is not installed!"
|
|
||||||
ui_print_wrapper "! Nothing to uninstall"
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
1 )
|
|
||||||
# Find SHA1 of stock boot image
|
|
||||||
if [ -z $SHA1 ]; then
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc
|
|
||||||
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc`
|
|
||||||
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
|
|
||||||
rm -f init.magisk.rc
|
|
||||||
fi
|
|
||||||
if [ -f ${STOCKDUMP}.gz ]; then
|
|
||||||
ui_print_wrapper "- Boot image backup found!"
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
|
|
||||||
else
|
|
||||||
ui_print_wrapper "! Boot image backup unavailable"
|
|
||||||
ui_print_wrapper "- Restoring ramdisk with backup"
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
2 )
|
|
||||||
ui_print_wrapper "- SuperSU patched image detected"
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Sign chromeos boot
|
|
||||||
if [ -f chromeos ]; then
|
|
||||||
echo > config
|
|
||||||
echo > bootloader
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack stock_boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz stock_boot.img --config config --arch arm --bootloader bootloader --flags 0x1
|
|
||||||
rm -f stock_boot.img
|
|
||||||
mv stock_boot.img.signed stock_boot.img
|
|
||||||
fi
|
|
||||||
|
|
||||||
ui_print_wrapper "- Flashing stock/reverted image"
|
|
||||||
[ ! -L "$BOOTIMAGE" ] && dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
|
|
||||||
dd if=stock_boot.img of=$BOOTIMAGE bs=4096
|
|
||||||
|
|
||||||
ui_print_wrapper "- Removing Magisk files"
|
|
||||||
rm -rf /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \
|
|
||||||
/cache/magisk /cache/magisk_merge /cache/magisk_mount /cache/unblock /cache/magisk_uninstaller.sh \
|
|
||||||
/data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img \
|
|
||||||
/data/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null
|
|
||||||
|
|
||||||
$BOOTMODE && reboot
|
|
||||||
Binary file not shown.
@@ -1,27 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
|
|
||||||
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
|
|
||||||
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
|
|
||||||
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
|
|
||||||
Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET
|
|
||||||
MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
|
|
||||||
A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
|
|
||||||
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
|
|
||||||
hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
|
|
||||||
qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
|
|
||||||
wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
|
|
||||||
4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
|
|
||||||
RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
|
|
||||||
zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
|
|
||||||
HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
|
|
||||||
AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
|
|
||||||
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
|
|
||||||
QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
|
|
||||||
CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
|
|
||||||
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa
|
|
||||||
J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y
|
|
||||||
LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe
|
|
||||||
+ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX
|
|
||||||
31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr
|
|
||||||
sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 57 KiB |
@@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
@@ -13,26 +12,22 @@ import android.text.Spanned;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class AboutActivity extends Activity {
|
public class AboutActivity extends Activity {
|
||||||
|
|
||||||
private static final String DONATION_URL = "http://topjohnwu.github.io/donate";
|
|
||||||
private static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
|
|
||||||
private static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/MagiskManager";
|
|
||||||
|
|
||||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||||
@BindView(R.id.app_version_info) AboutCardRow appVersionInfo;
|
@BindView(R.id.app_version_info) AboutCardRow appVersionInfo;
|
||||||
@BindView(R.id.app_changelog) AboutCardRow appChangelog;
|
@BindView(R.id.app_changelog) AboutCardRow appChangelog;
|
||||||
@@ -45,10 +40,8 @@ public class AboutActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
String theme = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("theme", "");
|
if (getMagiskManager().isDarkTheme) {
|
||||||
Logger.dev("AboutActivity: Theme is " + theme);
|
setTheme(R.style.AppTheme_Transparent_Dark);
|
||||||
if (getApplicationContext().isDarkTheme) {
|
|
||||||
setTheme(R.style.AppTheme_Dark);
|
|
||||||
}
|
}
|
||||||
setContentView(R.layout.activity_about);
|
setContentView(R.layout.activity_about);
|
||||||
ButterKnife.bind(this);
|
ButterKnife.bind(this);
|
||||||
@@ -62,7 +55,7 @@ public class AboutActivity extends Activity {
|
|||||||
ab.setDisplayHomeAsUpEnabled(true);
|
ab.setDisplayHomeAsUpEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
appVersionInfo.setSummary(BuildConfig.VERSION_NAME);
|
appVersionInfo.setSummary(String.format(Locale.US, "%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
|
||||||
|
|
||||||
String changes = null;
|
String changes = null;
|
||||||
try (InputStream is = getAssets().open("changelog.html")) {
|
try (InputStream is = getAssets().open("changelog.html")) {
|
||||||
@@ -124,29 +117,15 @@ public class AboutActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
appSourceCode.removeSummary();
|
appSourceCode.removeSummary();
|
||||||
appSourceCode.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(SOURCE_CODE_URL))));
|
appSourceCode.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.SOURCE_CODE_URL))));
|
||||||
|
|
||||||
supportThread.removeSummary();
|
supportThread.removeSummary();
|
||||||
supportThread.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(XDA_THREAD))));
|
supportThread.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.XDA_THREAD))));
|
||||||
|
|
||||||
donation.removeSummary();
|
donation.removeSummary();
|
||||||
donation.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(DONATION_URL))));
|
donation.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.DONATION_URL))));
|
||||||
|
|
||||||
setFloating();
|
setFloating();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFloating() {
|
|
||||||
boolean isTablet = getResources().getBoolean(R.bool.isTablet);
|
|
||||||
if (isTablet) {
|
|
||||||
WindowManager.LayoutParams params = getWindow().getAttributes();
|
|
||||||
params.height = getResources().getDimensionPixelSize(R.dimen.floating_height);
|
|
||||||
params.width = getResources().getDimensionPixelSize(R.dimen.floating_width);
|
|
||||||
params.alpha = 1.0f;
|
|
||||||
params.dimAmount = 0.6f;
|
|
||||||
params.flags |= 2;
|
|
||||||
getWindow().setAttributes(params);
|
|
||||||
setFinishOnTouchOutside(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
129
app/src/main/java/com/topjohnwu/magisk/FlashActivity.java
Normal file
129
app/src/main/java/com/topjohnwu/magisk/FlashActivity.java
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.asyncs.FlashZip;
|
||||||
|
import com.topjohnwu.magisk.asyncs.InstallMagisk;
|
||||||
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.container.CallbackList;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnClick;
|
||||||
|
|
||||||
|
public class FlashActivity extends Activity {
|
||||||
|
|
||||||
|
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||||
|
@BindView(R.id.txtLog) TextView flashLogs;
|
||||||
|
@BindView(R.id.button_panel) public LinearLayout buttonPanel;
|
||||||
|
@BindView(R.id.reboot) public Button reboot;
|
||||||
|
@BindView(R.id.scrollView) ScrollView sv;
|
||||||
|
|
||||||
|
private List<String> logs;
|
||||||
|
|
||||||
|
@OnClick(R.id.no_thanks)
|
||||||
|
void dismiss() {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.reboot)
|
||||||
|
void reboot() {
|
||||||
|
Shell.su_raw("/system/bin/reboot");
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.save_logs)
|
||||||
|
void saveLogs() {
|
||||||
|
Calendar now = Calendar.getInstance();
|
||||||
|
String filename = String.format(Locale.US,
|
||||||
|
"install_log_%04d%02d%02d_%02d:%02d:%02d.log",
|
||||||
|
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||||
|
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||||
|
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
||||||
|
|
||||||
|
File logFile = new File(Const.EXTERNAL_PATH + "/logs", filename);
|
||||||
|
logFile.getParentFile().mkdirs();
|
||||||
|
try (FileWriter writer = new FileWriter(logFile)) {
|
||||||
|
for (String s : logs) {
|
||||||
|
writer.write(s);
|
||||||
|
writer.write('\n');
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MagiskManager.toast(logFile.getPath(), Toast.LENGTH_LONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_flash);
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
ActionBar ab = getSupportActionBar();
|
||||||
|
if (ab != null) {
|
||||||
|
ab.setTitle(R.string.flashing);
|
||||||
|
}
|
||||||
|
setFloating();
|
||||||
|
setFinishOnTouchOutside(false);
|
||||||
|
if (!Shell.rootAccess())
|
||||||
|
reboot.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
logs = new ArrayList<>();
|
||||||
|
List<String> console = new CallbackList<String>() {
|
||||||
|
@Override
|
||||||
|
public synchronized void onAddElement(String e) {
|
||||||
|
logs.add(e);
|
||||||
|
flashLogs.setText(TextUtils.join("\n", this));
|
||||||
|
sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// We must receive a Uri of the target zip
|
||||||
|
Intent intent = getIntent();
|
||||||
|
Uri uri = intent.getData();
|
||||||
|
|
||||||
|
boolean keepEnc = intent.getBooleanExtra(Const.Key.FLASH_SET_ENC, false);
|
||||||
|
boolean keepVerity = intent.getBooleanExtra(Const.Key.FLASH_SET_VERITY, false);
|
||||||
|
|
||||||
|
switch (intent.getStringExtra(Const.Key.FLASH_ACTION)) {
|
||||||
|
case Const.Value.FLASH_ZIP:
|
||||||
|
new FlashZip(this, uri, console, logs).exec();
|
||||||
|
break;
|
||||||
|
case Const.Value.PATCH_BOOT:
|
||||||
|
new InstallMagisk(this, console, logs, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT))
|
||||||
|
.exec();
|
||||||
|
break;
|
||||||
|
case Const.Value.FLASH_MAGISK:
|
||||||
|
new InstallMagisk(this, console, logs, uri, keepEnc, keepVerity, intent.getStringExtra(Const.Key.FLASH_SET_BOOT))
|
||||||
|
.exec();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
// Prevent user accidentally press back button
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
package com.topjohnwu.magisk;
|
|
||||||
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.CountDownTimer;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.design.widget.Snackbar;
|
|
||||||
import android.support.v7.widget.CardView;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.ProcessMagiskZip;
|
|
||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
|
||||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
|
||||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
import butterknife.Unbinder;
|
|
||||||
|
|
||||||
public class InstallFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
|
||||||
|
|
||||||
|
|
||||||
private static final String UNINSTALLER = "magisk_uninstaller.sh";
|
|
||||||
|
|
||||||
@BindView(R.id.current_version_title) TextView currentVersionTitle;
|
|
||||||
@BindView(R.id.install_title) TextView installTitle;
|
|
||||||
@BindView(R.id.block_spinner) Spinner spinner;
|
|
||||||
@BindView(R.id.detect_bootimage) Button detectButton;
|
|
||||||
@BindView(R.id.install_button) CardView installButton;
|
|
||||||
@BindView(R.id.install_text) TextView installText;
|
|
||||||
@BindView(R.id.uninstall_button) CardView uninstallButton;
|
|
||||||
@BindView(R.id.keep_force_enc) CheckBox keepEncChkbox;
|
|
||||||
@BindView(R.id.keep_verity) CheckBox keepVerityChkbox;
|
|
||||||
|
|
||||||
@OnClick(R.id.detect_bootimage)
|
|
||||||
public void toAutoDetect() {
|
|
||||||
if (magiskManager.bootBlock != null) {
|
|
||||||
spinner.setSelection(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.install_button)
|
|
||||||
public void install() {
|
|
||||||
String bootImage = null;
|
|
||||||
if (magiskManager.blockList != null) {
|
|
||||||
int idx = spinner.getSelectedItemPosition();
|
|
||||||
if (magiskManager.bootBlock != null) {
|
|
||||||
if (idx > 0) {
|
|
||||||
bootImage = magiskManager.blockList.get(idx - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (idx > 0) {
|
|
||||||
bootImage = magiskManager.blockList.get(idx - 1);
|
|
||||||
} else {
|
|
||||||
SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final String finalBootImage = bootImage;
|
|
||||||
String filename = "Magisk-v" + magiskManager.remoteMagiskVersion + ".zip";
|
|
||||||
new AlertDialogBuilder(getActivity())
|
|
||||||
.setTitle(getString(R.string.repo_install_title, getString(R.string.magisk)))
|
|
||||||
.setMessage(getString(R.string.repo_install_msg, filename))
|
|
||||||
.setCancelable(true)
|
|
||||||
.setPositiveButton(Shell.rootAccess() ? R.string.install : R.string.download,
|
|
||||||
(dialogInterface, i) -> Utils.dlAndReceive(
|
|
||||||
getActivity(),
|
|
||||||
new DownloadReceiver() {
|
|
||||||
private String boot = finalBootImage;
|
|
||||||
private boolean enc = keepEncChkbox.isChecked();
|
|
||||||
private boolean verity = keepVerityChkbox.isChecked();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDownloadDone(Uri uri) {
|
|
||||||
new ProcessMagiskZip(getActivity(), uri, boot, enc, verity).exec();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
magiskManager.magiskLink,
|
|
||||||
Utils.getLegalFilename(filename)))
|
|
||||||
.setNeutralButton(R.string.release_notes, (dialog, which) -> {
|
|
||||||
magiskManager.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink)));
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.no_thanks, null)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.uninstall_button)
|
|
||||||
public void uninstall() {
|
|
||||||
new AlertDialogBuilder(getActivity())
|
|
||||||
.setTitle(R.string.uninstall_magisk_title)
|
|
||||||
.setMessage(R.string.uninstall_magisk_msg)
|
|
||||||
.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
|
|
||||||
try {
|
|
||||||
InputStream in = magiskManager.getAssets().open(UNINSTALLER);
|
|
||||||
File uninstaller = new File(magiskManager.getCacheDir(), UNINSTALLER);
|
|
||||||
FileOutputStream out = new FileOutputStream(uninstaller);
|
|
||||||
byte[] bytes = new byte[1024];
|
|
||||||
int read;
|
|
||||||
while ((read = in.read(bytes)) != -1) {
|
|
||||||
out.write(bytes, 0, read);
|
|
||||||
}
|
|
||||||
in.close();
|
|
||||||
out.close();
|
|
||||||
ProgressDialog progress = new ProgressDialog(getActivity());
|
|
||||||
progress.setTitle(R.string.reboot);
|
|
||||||
progress.show();
|
|
||||||
new CountDownTimer(5000, 1000) {
|
|
||||||
@Override
|
|
||||||
public void onTick(long millisUntilFinished) {
|
|
||||||
progress.setMessage(getString(R.string.reboot_countdown, millisUntilFinished / 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFinish() {
|
|
||||||
progress.setMessage(getString(R.string.reboot_countdown, 0));
|
|
||||||
Shell.su(true, "mv -f " + uninstaller + " /cache/" + UNINSTALLER,
|
|
||||||
"reboot");
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.no_thanks, null)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Unbinder unbinder;
|
|
||||||
private MagiskManager magiskManager;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
View v = inflater.inflate(R.layout.fragment_install, container, false);
|
|
||||||
unbinder = ButterKnife.bind(this, v);
|
|
||||||
magiskManager = getApplication();
|
|
||||||
if (magiskManager.magiskVersion < 0) {
|
|
||||||
currentVersionTitle.setText(getString(R.string.current_magisk_title, getString(R.string.version_none)));
|
|
||||||
} else {
|
|
||||||
currentVersionTitle.setText(getString(R.string.current_magisk_title, "v" + magiskManager.magiskVersionString));
|
|
||||||
}
|
|
||||||
installTitle.setText(getString(R.string.install_magisk_title, "v" + String.format(Locale.US, "%.1f", magiskManager.remoteMagiskVersion)));
|
|
||||||
|
|
||||||
updateUI();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTrigger(CallbackEvent<Void> event) {
|
|
||||||
updateUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateUI() {
|
|
||||||
if (magiskManager.blockList == null || !Shell.rootAccess()) {
|
|
||||||
uninstallButton.setVisibility(View.GONE);
|
|
||||||
installText.setText(R.string.download);
|
|
||||||
detectButton.setEnabled(false);
|
|
||||||
keepEncChkbox.setEnabled(false);
|
|
||||||
keepVerityChkbox.setEnabled(false);
|
|
||||||
spinner.setEnabled(false);
|
|
||||||
} else {
|
|
||||||
uninstallButton.setVisibility(magiskManager.magiskVersion > 10.3 ? View.VISIBLE : View.GONE);
|
|
||||||
installText.setText(R.string.download_install);
|
|
||||||
detectButton.setEnabled(true);
|
|
||||||
keepEncChkbox.setEnabled(true);
|
|
||||||
keepVerityChkbox.setEnabled(true);
|
|
||||||
spinner.setEnabled(true);
|
|
||||||
|
|
||||||
List<String> items = new ArrayList<>();
|
|
||||||
if (magiskManager.bootBlock != null) {
|
|
||||||
items.add(getString(R.string.auto_detect, magiskManager.bootBlock));
|
|
||||||
} else {
|
|
||||||
items.add(getString(R.string.cannot_auto_detect));
|
|
||||||
}
|
|
||||||
items.addAll(magiskManager.blockList);
|
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
|
|
||||||
android.R.layout.simple_spinner_item, items);
|
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
||||||
spinner.setAdapter(adapter);
|
|
||||||
toAutoDetect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
getActivity().setTitle(R.string.install);
|
|
||||||
magiskManager.blockDetectionDone.register(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
magiskManager.blockDetectionDone.unRegister(this);
|
|
||||||
super.onStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
super.onDestroyView();
|
|
||||||
unbinder.unbind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,15 +29,14 @@ public class LogFragment extends Fragment {
|
|||||||
View v = inflater.inflate(R.layout.fragment_log, container, false);
|
View v = inflater.inflate(R.layout.fragment_log, container, false);
|
||||||
unbinder = ButterKnife.bind(this, v);
|
unbinder = ButterKnife.bind(this, v);
|
||||||
|
|
||||||
|
((MainActivity) getActivity()).toolbar.setElevation(0);
|
||||||
|
|
||||||
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
|
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
|
||||||
|
|
||||||
|
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
|
||||||
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
||||||
|
tab.setupWithViewPager(viewPager);
|
||||||
if (getApplication().isSuClient) {
|
tab.setVisibility(View.VISIBLE);
|
||||||
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
|
|
||||||
tab.setupWithViewPager(viewPager);
|
|
||||||
tab.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
viewPager.setAdapter(adapter);
|
viewPager.setAdapter(adapter);
|
||||||
|
|
||||||
|
|||||||
301
app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java
Normal file
301
app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,9 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.view.MenuItemCompat;
|
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@@ -15,16 +12,14 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.SearchView;
|
import android.widget.SearchView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
||||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import butterknife.Unbinder;
|
import butterknife.Unbinder;
|
||||||
|
|
||||||
public class MagiskHideFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
public class MagiskHideFragment extends Fragment implements Topic.Subscriber {
|
||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||||
@@ -46,13 +41,12 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen
|
|||||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.fragment_magisk_hide, container, false);
|
View view = inflater.inflate(R.layout.fragment_magisk_hide, container, false);
|
||||||
unbinder = ButterKnife.bind(this, view);
|
unbinder = ButterKnife.bind(this, view);
|
||||||
|
lastFilter = "";
|
||||||
PackageManager packageManager = getActivity().getPackageManager();
|
|
||||||
|
|
||||||
mSwipeRefreshLayout.setRefreshing(true);
|
mSwipeRefreshLayout.setRefreshing(true);
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> new MagiskHide(getActivity()).list());
|
mSwipeRefreshLayout.setOnRefreshListener(() -> appAdapter.refresh());
|
||||||
|
|
||||||
appAdapter = new ApplicationAdapter(packageManager);
|
appAdapter = new ApplicationAdapter(getActivity());
|
||||||
recyclerView.setAdapter(appAdapter);
|
recyclerView.setAdapter(appAdapter);
|
||||||
|
|
||||||
searchListener = new SearchView.OnQueryTextListener() {
|
searchListener = new SearchView.OnQueryTextListener() {
|
||||||
@@ -71,9 +65,7 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (getApplication().magiskHideDone.isTriggered) {
|
getActivity().setTitle(R.string.magiskhide);
|
||||||
onTrigger(getApplication().magiskHideDone);
|
|
||||||
}
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@@ -81,23 +73,10 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen
|
|||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
inflater.inflate(R.menu.menu_magiskhide, menu);
|
inflater.inflate(R.menu.menu_magiskhide, menu);
|
||||||
SearchView search = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.app_search));
|
SearchView search = (SearchView) menu.findItem(R.id.app_search).getActionView();
|
||||||
search.setOnQueryTextListener(searchListener);
|
search.setOnQueryTextListener(searchListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
getActivity().setTitle(R.string.magiskhide);
|
|
||||||
getApplication().magiskHideDone.register(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
getApplication().magiskHideDone.unRegister(this);
|
|
||||||
super.onStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
@@ -105,12 +84,13 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrigger(CallbackEvent<Void> event) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
Logger.dev("MagiskHideFragment: UI refresh");
|
|
||||||
appAdapter.setLists(getApplication().appList, getApplication().magiskHideList);
|
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
if (!TextUtils.isEmpty(lastFilter)) {
|
appAdapter.filter(lastFilter);
|
||||||
appAdapter.filter(lastFilter);
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public Topic[] getSubscription() {
|
||||||
|
return new Topic[] { getApplication().magiskHideDone };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,7 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@@ -20,14 +17,16 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class MainActivity extends Activity
|
public class MainActivity extends Activity
|
||||||
implements NavigationView.OnNavigationItemSelectedListener, CallbackEvent.Listener<Void> {
|
implements NavigationView.OnNavigationItemSelectedListener, Topic.Subscriber {
|
||||||
|
|
||||||
private final Handler mDrawerHandler = new Handler();
|
private final Handler mDrawerHandler = new Handler();
|
||||||
private SharedPreferences prefs;
|
private SharedPreferences prefs;
|
||||||
@@ -42,23 +41,35 @@ public class MainActivity extends Activity
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
|
|
||||||
prefs = getApplicationContext().prefs;
|
MagiskManager mm = getMagiskManager();
|
||||||
|
|
||||||
if (getApplicationContext().isDarkTheme) {
|
if (!mm.hasInit) {
|
||||||
|
Intent intent = new Intent(this, SplashActivity.class);
|
||||||
|
String section = getIntent().getStringExtra(Const.Key.OPEN_SECTION);
|
||||||
|
if (section != null) {
|
||||||
|
intent.putExtra(Const.Key.OPEN_SECTION, section);
|
||||||
|
}
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
String perm = getIntent().getStringExtra(Const.Key.INTENT_PERM);
|
||||||
|
if (perm != null) {
|
||||||
|
ActivityCompat.requestPermissions(this, new String[] { perm }, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
prefs = mm.prefs;
|
||||||
|
|
||||||
|
if (mm.isDarkTheme) {
|
||||||
setTheme(R.style.AppTheme_Dark);
|
setTheme(R.style.AppTheme_Dark);
|
||||||
}
|
}
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
ButterKnife.bind(this);
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|
|
||||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
|
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.magisk, R.string.magisk) {
|
||||||
@Override
|
@Override
|
||||||
public void onDrawerOpened(View drawerView) {
|
public void onDrawerOpened(View drawerView) {
|
||||||
super.onDrawerOpened(drawerView);
|
super.onDrawerOpened(drawerView);
|
||||||
@@ -77,11 +88,9 @@ public class MainActivity extends Activity
|
|||||||
toggle.syncState();
|
toggle.syncState();
|
||||||
|
|
||||||
if (savedInstanceState == null)
|
if (savedInstanceState == null)
|
||||||
navigate(getIntent().getStringExtra(MagiskManager.INTENT_SECTION));
|
navigate(getIntent().getStringExtra(Const.Key.OPEN_SECTION));
|
||||||
|
|
||||||
navigationView.setNavigationItemSelectedListener(this);
|
navigationView.setNavigationItemSelectedListener(this);
|
||||||
getApplicationContext().reloadMainActivity.register(this);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -90,30 +99,15 @@ public class MainActivity extends Activity
|
|||||||
checkHideSection();
|
checkHideSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
|
||||||
navigate(savedInstanceState.getInt(MagiskManager.INTENT_SECTION, R.id.status));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
outState.putInt(MagiskManager.INTENT_SECTION, mDrawerItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
getApplicationContext().reloadMainActivity.unRegister(this);
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
if (drawer.isDrawerOpen(navigationView))
|
if (drawer.isDrawerOpen(navigationView)) {
|
||||||
drawer.closeDrawer(navigationView);
|
drawer.closeDrawer(navigationView);
|
||||||
else
|
} else if (mDrawerItem != R.id.magisk) {
|
||||||
|
navigate(R.id.magisk);
|
||||||
|
} else {
|
||||||
finish();
|
finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,34 +119,36 @@ public class MainActivity extends Activity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrigger(CallbackEvent<Void> event) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
recreate();
|
recreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkHideSection() {
|
@Override
|
||||||
|
public Topic[] getSubscription() {
|
||||||
|
return new Topic[] { getMagiskManager().reloadActivity };
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkHideSection() {
|
||||||
|
MagiskManager mm = getMagiskManager();
|
||||||
Menu menu = navigationView.getMenu();
|
Menu menu = navigationView.getMenu();
|
||||||
menu.findItem(R.id.magiskhide).setVisible(
|
menu.findItem(R.id.magiskhide).setVisible(
|
||||||
Shell.rootAccess() && getApplicationContext().magiskVersion >= 8
|
Shell.rootAccess() && mm.magiskVersionCode >= 1300
|
||||||
&& prefs.getBoolean("magiskhide", false));
|
&& prefs.getBoolean(Const.Key.MAGISKHIDE, false));
|
||||||
menu.findItem(R.id.modules).setVisible(
|
menu.findItem(R.id.modules).setVisible(
|
||||||
Shell.rootAccess() && getApplicationContext().magiskVersion >= 4);
|
Shell.rootAccess() && mm.magiskVersionCode >= 0);
|
||||||
menu.findItem(R.id.downloads).setVisible(
|
menu.findItem(R.id.downloads).setVisible(Utils.checkNetworkStatus() &&
|
||||||
Shell.rootAccess() && getApplicationContext().magiskVersion >= 4);
|
Shell.rootAccess() && mm.magiskVersionCode >= 0);
|
||||||
|
menu.setGroupVisible(R.id.second_group, !mm.coreOnly);
|
||||||
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
|
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
|
||||||
menu.findItem(R.id.superuser).setVisible(
|
menu.findItem(R.id.superuser).setVisible(Shell.rootAccess());
|
||||||
Shell.rootAccess() && getApplicationContext().isSuClient);
|
|
||||||
menu.findItem(R.id.install).setVisible(getApplicationContext().remoteMagiskVersion > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void navigate(String item) {
|
public void navigate(String item) {
|
||||||
int itemId = R.id.status;
|
int itemId = R.id.magisk;
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
switch (item) {
|
switch (item) {
|
||||||
case "status":
|
case "magisk":
|
||||||
itemId = R.id.status;
|
itemId = R.id.magisk;
|
||||||
break;
|
|
||||||
case "install":
|
|
||||||
itemId = R.id.install;
|
|
||||||
break;
|
break;
|
||||||
case "superuser":
|
case "superuser":
|
||||||
itemId = R.id.superuser;
|
itemId = R.id.superuser;
|
||||||
@@ -185,11 +181,8 @@ public class MainActivity extends Activity
|
|||||||
mDrawerItem = itemId;
|
mDrawerItem = itemId;
|
||||||
navigationView.setCheckedItem(itemId);
|
navigationView.setCheckedItem(itemId);
|
||||||
switch (itemId) {
|
switch (itemId) {
|
||||||
case R.id.status:
|
case R.id.magisk:
|
||||||
displayFragment(new StatusFragment(), "status", true);
|
displayFragment(new MagiskFragment(), "magisk", true);
|
||||||
break;
|
|
||||||
case R.id.install:
|
|
||||||
displayFragment(new InstallFragment(), "install", true);
|
|
||||||
break;
|
break;
|
||||||
case R.id.superuser:
|
case R.id.superuser:
|
||||||
displayFragment(new SuperuserFragment(), "superuser", true);
|
displayFragment(new SuperuserFragment(), "superuser", true);
|
||||||
@@ -201,7 +194,7 @@ public class MainActivity extends Activity
|
|||||||
displayFragment(new ReposFragment(), "downloads", true);
|
displayFragment(new ReposFragment(), "downloads", true);
|
||||||
break;
|
break;
|
||||||
case R.id.magiskhide:
|
case R.id.magiskhide:
|
||||||
displayFragment(new MagiskHideFragment(), "magiskhide", true);
|
displayFragment(new MagiskHideFragment(), Const.Key.MAGISKHIDE, true);
|
||||||
break;
|
break;
|
||||||
case R.id.log:
|
case R.id.log:
|
||||||
displayFragment(new LogFragment(), "log", false);
|
displayFragment(new LogFragment(), "log", false);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
@@ -12,31 +12,36 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.github.clans.fab.FloatingActionButton;
|
|
||||||
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
||||||
import com.topjohnwu.magisk.asyncs.FlashZip;
|
|
||||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnClick;
|
||||||
import butterknife.Unbinder;
|
import butterknife.Unbinder;
|
||||||
|
|
||||||
public class ModulesFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
||||||
|
|
||||||
private static final int FETCH_ZIP_CODE = 2;
|
|
||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
@BindView(R.id.empty_rv) TextView emptyRv;
|
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||||
@BindView(R.id.fab) FloatingActionButton fabio;
|
@OnClick(R.id.fab)
|
||||||
|
public void selectFile() {
|
||||||
|
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, () -> {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
intent.setType("application/zip");
|
||||||
|
startActivityForResult(intent, Const.ID.FETCH_ZIP);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private List<Module> listModules = new ArrayList<>();
|
private List<Module> listModules = new ArrayList<>();
|
||||||
|
|
||||||
@@ -46,15 +51,9 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener<
|
|||||||
View view = inflater.inflate(R.layout.fragment_modules, container, false);
|
View view = inflater.inflate(R.layout.fragment_modules, container, false);
|
||||||
unbinder = ButterKnife.bind(this, view);
|
unbinder = ButterKnife.bind(this, view);
|
||||||
|
|
||||||
fabio.setOnClickListener(v -> {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
||||||
intent.setType("application/zip");
|
|
||||||
startActivityForResult(intent, FETCH_ZIP_CODE);
|
|
||||||
});
|
|
||||||
|
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
new LoadModules(getActivity()).exec();
|
new LoadModules().exec();
|
||||||
});
|
});
|
||||||
|
|
||||||
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
@@ -69,40 +68,29 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener<
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (getApplication().moduleLoadDone.isTriggered) {
|
getActivity().setTitle(R.string.modules);
|
||||||
updateUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrigger(CallbackEvent<Void> event) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
Logger.dev("ModulesFragment: UI refresh triggered");
|
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Topic[] getSubscription() {
|
||||||
|
return new Topic[] { getApplication().moduleLoadDone };
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) {
|
||||||
// Get the URI of the selected file
|
// Get the URI of the selected file
|
||||||
final Uri uri = data.getData();
|
Intent intent = new Intent(getActivity(), FlashActivity.class);
|
||||||
new FlashZip(getActivity(), uri).exec();
|
intent.setData(data.getData()).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
|
||||||
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
getApplication().moduleLoadDone.register(this);
|
|
||||||
getActivity().setTitle(R.string.modules);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
getApplication().moduleLoadDone.unRegister(this);
|
|
||||||
super.onStop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.view.MenuItemCompat;
|
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -14,39 +13,22 @@ import android.widget.SearchView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||||
import com.topjohnwu.magisk.adapters.SimpleSectionedRecyclerViewAdapter;
|
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||||
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
|
||||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
import com.topjohnwu.magisk.module.Repo;
|
|
||||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import butterknife.Unbinder;
|
import butterknife.Unbinder;
|
||||||
|
|
||||||
public class ReposFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
public class ReposFragment extends Fragment implements Topic.Subscriber {
|
||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
@BindView(R.id.empty_rv) TextView emptyRv;
|
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||||
|
|
||||||
private List<Repo> mUpdateRepos = new ArrayList<>();
|
public static ReposAdapter adapter;
|
||||||
private List<Repo> mInstalledRepos = new ArrayList<>();
|
|
||||||
private List<Repo> mOthersRepos = new ArrayList<>();
|
|
||||||
private List<Repo> fUpdateRepos = new ArrayList<>();
|
|
||||||
private List<Repo> fInstalledRepos = new ArrayList<>();
|
|
||||||
private List<Repo> fOthersRepos = new ArrayList<>();
|
|
||||||
|
|
||||||
private SimpleSectionedRecyclerViewAdapter mSectionedAdapter;
|
|
||||||
|
|
||||||
private SearchView.OnQueryTextListener searchListener;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
@@ -60,24 +42,49 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
|
|||||||
View view = inflater.inflate(R.layout.fragment_repos, container, false);
|
View view = inflater.inflate(R.layout.fragment_repos, container, false);
|
||||||
unbinder = ButterKnife.bind(this, view);
|
unbinder = ButterKnife.bind(this, view);
|
||||||
|
|
||||||
mSectionedAdapter = new SimpleSectionedRecyclerViewAdapter(R.layout.section,
|
|
||||||
R.id.section_text, new ReposAdapter(fUpdateRepos, fInstalledRepos, fOthersRepos));
|
|
||||||
|
|
||||||
recyclerView.setAdapter(mSectionedAdapter);
|
|
||||||
|
|
||||||
mSwipeRefreshLayout.setRefreshing(true);
|
mSwipeRefreshLayout.setRefreshing(true);
|
||||||
|
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
new LoadRepos(getActivity()).exec();
|
emptyRv.setVisibility(View.GONE);
|
||||||
|
new UpdateRepos(true).exec();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (getApplication().repoLoadDone.isTriggered) {
|
getActivity().setTitle(R.string.downloads);
|
||||||
reloadRepos();
|
|
||||||
updateUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
searchListener = new SearchView.OnQueryTextListener() {
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
adapter = new ReposAdapter(getApplication().repoDB, getApplication().moduleMap);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
super.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
adapter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
|
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
||||||
|
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Topic[] getSubscription() {
|
||||||
|
return new Topic[] { getApplication().repoLoadDone };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.menu_repo, menu);
|
||||||
|
SearchView search = (SearchView) menu.findItem(R.id.repo_search).getActionView();
|
||||||
|
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onQueryTextSubmit(String query) {
|
public boolean onQueryTextSubmit(String query) {
|
||||||
return false;
|
return false;
|
||||||
@@ -85,39 +92,10 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onQueryTextChange(String newText) {
|
public boolean onQueryTextChange(String newText) {
|
||||||
new FilterApps().exec(newText);
|
adapter.filter(newText);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTrigger(CallbackEvent<Void> event) {
|
|
||||||
Logger.dev("ReposFragment: UI refresh triggered");
|
|
||||||
reloadRepos();
|
|
||||||
updateUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
|
||||||
inflater.inflate(R.menu.menu_repo, menu);
|
|
||||||
SearchView search = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.repo_search));
|
|
||||||
search.setOnQueryTextListener(searchListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
getApplication().repoLoadDone.register(this);
|
|
||||||
getActivity().setTitle(R.string.downloads);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
getApplication().repoLoadDone.unRegister(this);
|
|
||||||
super.onStop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,92 +103,4 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
|
|||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
unbinder.unbind();
|
unbinder.unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reloadRepos() {
|
|
||||||
mUpdateRepos.clear();
|
|
||||||
mInstalledRepos.clear();
|
|
||||||
mOthersRepos.clear();
|
|
||||||
for (Repo repo : getApplication().repoMap.values()) {
|
|
||||||
Module module = getApplication().moduleMap.get(repo.getId());
|
|
||||||
if (module != null) {
|
|
||||||
if (repo.getVersionCode() > module.getVersionCode()) {
|
|
||||||
mUpdateRepos.add(repo);
|
|
||||||
} else {
|
|
||||||
mInstalledRepos.add(repo);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mOthersRepos.add(repo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fUpdateRepos.clear();
|
|
||||||
fInstalledRepos.clear();
|
|
||||||
fOthersRepos.clear();
|
|
||||||
fUpdateRepos.addAll(mUpdateRepos);
|
|
||||||
fInstalledRepos.addAll(mInstalledRepos);
|
|
||||||
fOthersRepos.addAll(mOthersRepos);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateUI() {
|
|
||||||
if (fUpdateRepos.size() + fInstalledRepos.size() + fOthersRepos.size() == 0) {
|
|
||||||
emptyRv.setVisibility(View.VISIBLE);
|
|
||||||
recyclerView.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
List<SimpleSectionedRecyclerViewAdapter.Section> sections = new ArrayList<>();
|
|
||||||
if (!fUpdateRepos.isEmpty()) {
|
|
||||||
sections.add(new SimpleSectionedRecyclerViewAdapter.Section(0, getString(R.string.update_available)));
|
|
||||||
}
|
|
||||||
if (!fInstalledRepos.isEmpty()) {
|
|
||||||
sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size(), getString(R.string.installed)));
|
|
||||||
}
|
|
||||||
if (!fOthersRepos.isEmpty()) {
|
|
||||||
sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size() + fInstalledRepos.size(), getString(R.string.not_installed)));
|
|
||||||
}
|
|
||||||
SimpleSectionedRecyclerViewAdapter.Section[] array = sections.toArray(new SimpleSectionedRecyclerViewAdapter.Section[sections.size()]);
|
|
||||||
mSectionedAdapter.setSections(array);
|
|
||||||
emptyRv.setVisibility(View.GONE);
|
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class FilterApps extends ParallelTask<String, Void, Void> {
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(String... strings) {
|
|
||||||
String newText = strings[0];
|
|
||||||
fUpdateRepos.clear();
|
|
||||||
fInstalledRepos.clear();
|
|
||||||
fOthersRepos.clear();
|
|
||||||
for (Repo repo: mUpdateRepos) {
|
|
||||||
if (repo.getName().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
|| repo.getAuthor().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
|| repo.getDescription().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
) {
|
|
||||||
fUpdateRepos.add(repo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Repo repo: mInstalledRepos) {
|
|
||||||
if (repo.getName().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
|| repo.getAuthor().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
|| repo.getDescription().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
) {
|
|
||||||
fInstalledRepos.add(repo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Repo repo: mOthersRepos) {
|
|
||||||
if (repo.getName().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
|| repo.getAuthor().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
|| repo.getDescription().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
) {
|
|
||||||
fOthersRepos.add(repo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void v) {
|
|
||||||
updateUI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,73 +1,134 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
import android.app.job.JobInfo;
|
import android.app.job.JobInfo;
|
||||||
import android.app.job.JobScheduler;
|
import android.app.job.JobScheduler;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
import com.topjohnwu.magisk.asyncs.GetBootBlocks;
|
|
||||||
import com.topjohnwu.magisk.asyncs.LoadApps;
|
|
||||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||||
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.services.UpdateCheckService;
|
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
public class SplashActivity extends Activity{
|
import java.util.List;
|
||||||
|
|
||||||
private static final int UPDATE_SERVICE_ID = 1;
|
public class SplashActivity extends Activity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
MagiskManager magiskManager = getApplicationContext();
|
MagiskManager mm = getMagiskManager();
|
||||||
|
|
||||||
// Init the info and configs and root shell
|
// Dynamic detect all locales
|
||||||
magiskManager.init();
|
new LoadLocale().exec();
|
||||||
|
|
||||||
// Initialize the update check service, notify every 3 hours
|
// Create notification channel on Android O
|
||||||
if (!"install".equals(getIntent().getStringExtra(MagiskManager.INTENT_SECTION))) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
ComponentName service = new ComponentName(magiskManager, UpdateCheckService.class);
|
NotificationChannel channel = new NotificationChannel(Const.ID.NOTIFICATION_CHANNEL,
|
||||||
JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service)
|
getString(R.string.magisk_updates), NotificationManager.IMPORTANCE_DEFAULT);
|
||||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
getSystemService(NotificationManager.class).createNotificationChannel(channel);
|
||||||
.setPersisted(true)
|
|
||||||
.setPeriodic(3 * 60 * 60 * 1000)
|
|
||||||
.build();
|
|
||||||
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
|
||||||
scheduler.schedule(jobInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now fire all async tasks
|
mm.loadMagiskInfo();
|
||||||
new GetBootBlocks(this).exec();
|
LoadModules loadModuleTask = new LoadModules();
|
||||||
if (magiskManager.magiskHide && !magiskManager.disabled &&
|
|
||||||
magiskManager.magiskVersion > 11 && !magiskManager.magiskHideStarted) {
|
if (Utils.checkNetworkStatus()) {
|
||||||
new MagiskHide().enable();
|
|
||||||
|
// Fire update check
|
||||||
|
new CheckUpdates().exec();
|
||||||
|
|
||||||
|
// Add repo update check
|
||||||
|
loadModuleTask.setCallBack(() -> new UpdateRepos(false).exec());
|
||||||
}
|
}
|
||||||
new LoadModules(this) {
|
|
||||||
@Override
|
// Magisk working as expected
|
||||||
protected void onPostExecute(Void v) {
|
if (Shell.rootAccess() && mm.magiskVersionCode > 0) {
|
||||||
super.onPostExecute(v);
|
|
||||||
new LoadRepos(activity).exec();
|
List<String> ret = Shell.su("echo \"$BOOTIMAGE\"");
|
||||||
|
if (Utils.isValidShellResponse(ret)) {
|
||||||
|
mm.bootBlock = ret.get(0);
|
||||||
}
|
}
|
||||||
}.exec();
|
|
||||||
new LoadApps(this).exec();
|
// Setup suDB
|
||||||
new CheckUpdates(this, false){
|
SuDatabaseHelper.setupSuDB();
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void v) {
|
// Check alternative Magisk Manager
|
||||||
super.onPostExecute(v);
|
String pkg;
|
||||||
String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION);
|
if (getPackageName().equals(Const.ORIG_PKG_NAME) &&
|
||||||
Intent intent = new Intent(magiskManager, MainActivity.class);
|
(pkg = mm.suDB.getStrings(Const.Key.SU_REQUESTER, null)) != null) {
|
||||||
if (section != null) {
|
Shell.su_raw("pm uninstall " + pkg);
|
||||||
intent.putExtra(MagiskManager.INTENT_SECTION, section);
|
mm.suDB.setStrings(Const.Key.SU_REQUESTER, null);
|
||||||
}
|
|
||||||
startActivity(intent);
|
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
}.exec();
|
|
||||||
|
// Add update checking service
|
||||||
|
if (Const.Value.UPDATE_SERVICE_VER > mm.updateServiceVersion) {
|
||||||
|
ComponentName service = new ComponentName(this, UpdateCheckService.class);
|
||||||
|
JobInfo info = new JobInfo.Builder(Const.ID.UPDATE_SERVICE_ID, service)
|
||||||
|
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
||||||
|
.setPersisted(true)
|
||||||
|
.setPeriodic(8 * 60 * 60 * 1000)
|
||||||
|
.build();
|
||||||
|
((JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(info);
|
||||||
|
mm.updateServiceVersion = Const.Value.UPDATE_SERVICE_VER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire asynctasks
|
||||||
|
loadModuleTask.exec();
|
||||||
|
|
||||||
|
// Check dtbo status
|
||||||
|
Utils.patchDTBO();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write back default values
|
||||||
|
mm.prefs.edit()
|
||||||
|
.putBoolean(Const.Key.DARK_THEME, mm.isDarkTheme)
|
||||||
|
.putBoolean(Const.Key.MAGISKHIDE, mm.magiskHide)
|
||||||
|
.putBoolean(Const.Key.UPDATE_NOTIFICATION, mm.updateNotification)
|
||||||
|
.putBoolean(Const.Key.HOSTS, Utils.itemExist(Const.MAGISK_HOST_FILE()))
|
||||||
|
.putBoolean(Const.Key.DISABLE, Utils.itemExist(Const.MAGISK_DISABLE_FILE))
|
||||||
|
.putBoolean(Const.Key.SU_REAUTH, mm.suReauth)
|
||||||
|
.putString(Const.Key.SU_REQUEST_TIMEOUT, String.valueOf(mm.suRequestTimeout))
|
||||||
|
.putString(Const.Key.SU_AUTO_RESPONSE, String.valueOf(mm.suResponseType))
|
||||||
|
.putString(Const.Key.SU_NOTIFICATION, String.valueOf(mm.suNotificationType))
|
||||||
|
.putString(Const.Key.ROOT_ACCESS, String.valueOf(mm.suAccessState))
|
||||||
|
.putString(Const.Key.SU_MULTIUSER_MODE, String.valueOf(mm.multiuserMode))
|
||||||
|
.putString(Const.Key.SU_MNT_NS, String.valueOf(mm.suNamespaceMode))
|
||||||
|
.putString(Const.Key.UPDATE_CHANNEL, String.valueOf(mm.updateChannel))
|
||||||
|
.putString(Const.Key.LOCALE, mm.localeConfig)
|
||||||
|
.putString(Const.Key.BOOT_FORMAT, mm.bootFormat)
|
||||||
|
.putInt(Const.Key.UPDATE_SERVICE_VER, mm.updateServiceVersion)
|
||||||
|
.apply();
|
||||||
|
|
||||||
|
mm.hasInit = true;
|
||||||
|
|
||||||
|
Intent intent = new Intent(this, MainActivity.class);
|
||||||
|
intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION));
|
||||||
|
intent.putExtra(Const.Key.INTENT_PERM, getIntent().getStringExtra(Const.Key.INTENT_PERM));
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LoadLocale extends ParallelTask<Void, Void, Void> {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... voids) {
|
||||||
|
MagiskManager.get().locales = Utils.getAvailableLocale();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void aVoid) {
|
||||||
|
MagiskManager.get().localeDone.publish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,10 +13,6 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.SuLogAdapter;
|
import com.topjohnwu.magisk.adapters.SuLogAdapter;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.database.SuLogDatabaseHelper;
|
|
||||||
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@@ -28,7 +24,8 @@ public class SuLogFragment extends Fragment {
|
|||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
private SuLogDatabaseHelper dbHelper;
|
private MagiskManager mm;
|
||||||
|
private SuLogAdapter adapter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
@@ -48,8 +45,9 @@ public class SuLogFragment extends Fragment {
|
|||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
||||||
unbinder = ButterKnife.bind(this, v);
|
unbinder = ButterKnife.bind(this, v);
|
||||||
|
mm = getApplication();
|
||||||
dbHelper = new SuLogDatabaseHelper(getActivity());
|
adapter = new SuLogAdapter(mm.suDB);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
updateList();
|
updateList();
|
||||||
|
|
||||||
@@ -57,13 +55,12 @@ public class SuLogFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateList() {
|
private void updateList() {
|
||||||
List<SuLogEntry> logs = dbHelper.getLogList();
|
adapter.notifyDBChanged();
|
||||||
|
|
||||||
if (logs.size() == 0) {
|
if (adapter.getSectionCount() == 0) {
|
||||||
emptyRv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
recyclerView.setAdapter(new SuLogAdapter(logs).getAdapter());
|
|
||||||
emptyRv.setVisibility(View.GONE);
|
emptyRv.setVisibility(View.GONE);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
@@ -76,7 +73,7 @@ public class SuLogFragment extends Fragment {
|
|||||||
updateList();
|
updateList();
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_clear:
|
case R.id.menu_clear:
|
||||||
dbHelper.clearLogs();
|
mm.suDB.clearLogs();
|
||||||
updateList();
|
updateList();
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
import com.topjohnwu.magisk.container.Policy;
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -33,15 +32,15 @@ public class SuperuserFragment extends Fragment {
|
|||||||
unbinder = ButterKnife.bind(this, view);
|
unbinder = ButterKnife.bind(this, view);
|
||||||
|
|
||||||
PackageManager pm = getActivity().getPackageManager();
|
PackageManager pm = getActivity().getPackageManager();
|
||||||
|
MagiskManager mm = getApplication();
|
||||||
|
|
||||||
SuDatabaseHelper dbHelper = new SuDatabaseHelper(getActivity());
|
List<Policy> policyList = mm.suDB.getPolicyList(pm);
|
||||||
List<Policy> policyList = dbHelper.getPolicyList(pm);
|
|
||||||
|
|
||||||
if (policyList.size() == 0) {
|
if (policyList.size() == 0) {
|
||||||
emptyRv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
recyclerView.setAdapter(new PolicyAdapter(policyList, dbHelper, pm));
|
recyclerView.setAdapter(new PolicyAdapter(policyList, mm.suDB, pm));
|
||||||
emptyRv.setVisibility(View.GONE);
|
emptyRv.setVisibility(View.GONE);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.topjohnwu.magisk.adapters;
|
package com.topjohnwu.magisk.adapters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -13,13 +15,16 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
@@ -27,33 +32,23 @@ import butterknife.ButterKnife;
|
|||||||
|
|
||||||
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
|
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
|
||||||
|
|
||||||
public static final List<String> BLACKLIST = Arrays.asList(
|
|
||||||
"android",
|
|
||||||
"com.topjohnwu.magisk",
|
|
||||||
"com.google.android.gms"
|
|
||||||
);
|
|
||||||
|
|
||||||
private static final List<String> SNLIST = Arrays.asList(
|
|
||||||
"com.google.android.apps.walletnfcrel",
|
|
||||||
"com.nianticlabs.pokemongo"
|
|
||||||
);
|
|
||||||
|
|
||||||
private List<ApplicationInfo> mOriginalList, mList;
|
private List<ApplicationInfo> mOriginalList, mList;
|
||||||
private List<String> mHideList;
|
private List<String> mHideList;
|
||||||
private PackageManager packageManager;
|
private PackageManager pm;
|
||||||
private ApplicationFilter filter;
|
private ApplicationFilter filter;
|
||||||
|
private Topic magiskHideDone;
|
||||||
|
|
||||||
public ApplicationAdapter(PackageManager packageManager) {
|
public ApplicationAdapter(Context context) {
|
||||||
mOriginalList = mList = Collections.emptyList();
|
mOriginalList = mList = Collections.emptyList();
|
||||||
mHideList = Collections.emptyList();
|
mHideList = Collections.emptyList();
|
||||||
this.packageManager = packageManager;
|
|
||||||
filter = new ApplicationFilter();
|
filter = new ApplicationFilter();
|
||||||
|
pm = context.getPackageManager();
|
||||||
|
magiskHideDone = Utils.getMagiskManager(context).magiskHideDone;
|
||||||
|
new LoadApps().exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLists(List<ApplicationInfo> listApps, List<String> hideList) {
|
private boolean lowercaseContains(CharSequence string, CharSequence nonNullLowercaseSearch) {
|
||||||
mOriginalList = mList = listApps;
|
return !TextUtils.isEmpty(string) && string.toString().toLowerCase().contains(nonNullLowercaseSearch);
|
||||||
mHideList = hideList;
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -66,15 +61,15 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||||
ApplicationInfo info = mList.get(position);
|
ApplicationInfo info = mList.get(position);
|
||||||
|
|
||||||
holder.appIcon.setImageDrawable(info.loadIcon(packageManager));
|
holder.appIcon.setImageDrawable(info.loadIcon(pm));
|
||||||
holder.appName.setText(info.loadLabel(packageManager));
|
holder.appName.setText(info.loadLabel(pm));
|
||||||
holder.appPackage.setText(info.packageName);
|
holder.appPackage.setText(info.packageName);
|
||||||
|
|
||||||
// Remove all listeners
|
// Remove all listeners
|
||||||
holder.itemView.setOnClickListener(null);
|
holder.itemView.setOnClickListener(null);
|
||||||
holder.checkBox.setOnCheckedChangeListener(null);
|
holder.checkBox.setOnCheckedChangeListener(null);
|
||||||
|
|
||||||
if (SNLIST.contains(info.packageName)) {
|
if (Const.SN_DEFAULTLIST.contains(info.packageName)) {
|
||||||
holder.checkBox.setChecked(true);
|
holder.checkBox.setChecked(true);
|
||||||
holder.checkBox.setEnabled(false);
|
holder.checkBox.setEnabled(false);
|
||||||
holder.itemView.setOnClickListener(v ->
|
holder.itemView.setOnClickListener(v ->
|
||||||
@@ -86,10 +81,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
||||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
new MagiskHide().add(info.packageName);
|
Shell.su_raw("magiskhide --add " + info.packageName);
|
||||||
mHideList.add(info.packageName);
|
mHideList.add(info.packageName);
|
||||||
} else {
|
} else {
|
||||||
new MagiskHide().rm(info.packageName);
|
Shell.su_raw("magiskhide --rm " + info.packageName);
|
||||||
mHideList.remove(info.packageName);
|
mHideList.remove(info.packageName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -105,6 +100,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
filter.filter(constraint);
|
filter.filter(constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void refresh() {
|
||||||
|
new LoadApps().exec();
|
||||||
|
}
|
||||||
|
|
||||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
@BindView(R.id.app_icon) ImageView appIcon;
|
@BindView(R.id.app_icon) ImageView appIcon;
|
||||||
@@ -122,31 +121,47 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected FilterResults performFiltering(CharSequence constraint) {
|
protected FilterResults performFiltering(CharSequence constraint) {
|
||||||
List<ApplicationInfo> filteredApps;
|
|
||||||
if (constraint == null || constraint.length() == 0) {
|
if (constraint == null || constraint.length() == 0) {
|
||||||
filteredApps = mOriginalList;
|
mList = mOriginalList;
|
||||||
} else {
|
} else {
|
||||||
filteredApps = new ArrayList<>();
|
mList = new ArrayList<>();
|
||||||
String filter = constraint.toString().toLowerCase();
|
String filter = constraint.toString().toLowerCase();
|
||||||
for (ApplicationInfo info : mOriginalList) {
|
for (ApplicationInfo info : mOriginalList) {
|
||||||
if (Utils.lowercaseContains(info.loadLabel(packageManager), filter)
|
if (lowercaseContains(info.loadLabel(pm), filter)
|
||||||
|| Utils.lowercaseContains(info.packageName, filter)) {
|
|| lowercaseContains(info.packageName, filter)) {
|
||||||
filteredApps.add(info);
|
mList.add(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
FilterResults results = new FilterResults();
|
|
||||||
results.values = filteredApps;
|
|
||||||
results.count = filteredApps.size();
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
protected void publishResults(CharSequence constraint, FilterResults results) {
|
protected void publishResults(CharSequence constraint, FilterResults results) {
|
||||||
mList = (List<ApplicationInfo>) results.values;
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class LoadApps extends ParallelTask<Void, Void, Void> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... voids) {
|
||||||
|
mOriginalList = pm.getInstalledApplications(0);
|
||||||
|
for (Iterator<ApplicationInfo> i = mOriginalList.iterator(); i.hasNext(); ) {
|
||||||
|
ApplicationInfo info = i.next();
|
||||||
|
if (Const.SN_BLACKLIST.contains(info.packageName) || !info.enabled) {
|
||||||
|
i.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(mOriginalList, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
|
||||||
|
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
|
||||||
|
mHideList = Shell.su("magiskhide --ls");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void v) {
|
||||||
|
magiskHideDone.publish(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,8 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.SerialTask;
|
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -53,44 +52,31 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
|||||||
|
|
||||||
holder.checkBox.setOnCheckedChangeListener(null);
|
holder.checkBox.setOnCheckedChangeListener(null);
|
||||||
holder.checkBox.setChecked(module.isEnabled());
|
holder.checkBox.setChecked(module.isEnabled());
|
||||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> new SerialTask<Void, Void, Void>() {
|
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
@Override
|
int snack;
|
||||||
protected Void doInBackground(Void... voids) {
|
if (isChecked) {
|
||||||
if (isChecked) {
|
module.removeDisableFile();
|
||||||
module.removeDisableFile();
|
snack = R.string.disable_file_removed;
|
||||||
} else {
|
} else {
|
||||||
module.createDisableFile();
|
module.createDisableFile();
|
||||||
}
|
snack = R.string.disable_file_created;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
|
||||||
@Override
|
holder.delete.setOnClickListener(v -> {
|
||||||
protected void onPostExecute(Void v) {
|
boolean removed = module.willBeRemoved();
|
||||||
int snack = isChecked ? R.string.disable_file_removed : R.string.disable_file_created;
|
int snack;
|
||||||
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
if (removed) {
|
||||||
|
module.deleteRemoveFile();
|
||||||
|
snack = R.string.remove_file_deleted;
|
||||||
|
} else {
|
||||||
|
module.createRemoveFile();
|
||||||
|
snack = R.string.remove_file_created;
|
||||||
}
|
}
|
||||||
}.exec());
|
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||||
|
updateDeleteButton(holder, module);
|
||||||
holder.delete.setOnClickListener(v -> new SerialTask<Void, Void, Void>() {
|
});
|
||||||
private final boolean removed = module.willBeRemoved();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... voids) {
|
|
||||||
if (removed) {
|
|
||||||
module.deleteRemoveFile();
|
|
||||||
} else {
|
|
||||||
module.createRemoveFile();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void v) {
|
|
||||||
int snack = removed ? R.string.remove_file_deleted : R.string.remove_file_created;
|
|
||||||
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
|
||||||
updateDeleteButton(holder, module);
|
|
||||||
}
|
|
||||||
}.exec());
|
|
||||||
|
|
||||||
if (module.isUpdated()) {
|
if (module.isUpdated()) {
|
||||||
holder.notice.setVisibility(View.VISIBLE);
|
holder.notice.setVisibility(View.VISIBLE);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,11 @@
|
|||||||
package com.topjohnwu.magisk.adapters;
|
package com.topjohnwu.magisk.adapters;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.database.Cursor;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -12,99 +14,165 @@ import android.widget.LinearLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
||||||
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.components.MarkDownWindow;
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.module.Repo;
|
import com.topjohnwu.magisk.container.Repo;
|
||||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> {
|
public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, ReposAdapter.RepoHolder> {
|
||||||
|
|
||||||
private List<Repo> mUpdateRepos, mInstalledRepos, mOthersRepos;
|
private static final int UPDATES = 0;
|
||||||
private Context mContext;
|
private static final int INSTALLED = 1;
|
||||||
|
private static final int OTHERS = 2;
|
||||||
|
|
||||||
public ReposAdapter(List<Repo> update, List<Repo> installed, List<Repo> others) {
|
private Cursor repoCursor = null;
|
||||||
mUpdateRepos = update;
|
private Map<String, Module> moduleMap;
|
||||||
mInstalledRepos = installed;
|
private RepoDatabaseHelper repoDB;
|
||||||
mOthersRepos = others;
|
private List<Pair<Integer, List<Repo>>> repoPairs;
|
||||||
|
|
||||||
|
public ReposAdapter(RepoDatabaseHelper db, Map<String, Module> map) {
|
||||||
|
repoDB = db;
|
||||||
|
moduleMap = map;
|
||||||
|
repoPairs = new ArrayList<>();
|
||||||
|
notifyDBChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionCount() {
|
||||||
|
return repoPairs.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public int getItemCount(int section) {
|
||||||
mContext = parent.getContext();
|
return repoPairs.get(section).second.size();
|
||||||
View v = LayoutInflater.from(mContext).inflate(R.layout.list_item_repo, parent, false);
|
|
||||||
return new ViewHolder(v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
public SectionHolder onCreateSectionViewHolder(ViewGroup parent) {
|
||||||
Repo repo = getItem(position);
|
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.section, parent, false);
|
||||||
|
return new SectionHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RepoHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false);
|
||||||
|
return new RepoHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindSectionViewHolder(SectionHolder holder, int section) {
|
||||||
|
switch (repoPairs.get(section).first) {
|
||||||
|
case UPDATES:
|
||||||
|
holder.sectionText.setText(R.string.update_available);
|
||||||
|
break;
|
||||||
|
case INSTALLED:
|
||||||
|
holder.sectionText.setText(R.string.installed);
|
||||||
|
break;
|
||||||
|
case OTHERS:
|
||||||
|
holder.sectionText.setText(R.string.not_installed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindItemViewHolder(RepoHolder holder, int section, int position) {
|
||||||
|
Repo repo = repoPairs.get(section).second.get(position);
|
||||||
|
Context context = holder.itemView.getContext();
|
||||||
|
|
||||||
holder.title.setText(repo.getName());
|
holder.title.setText(repo.getName());
|
||||||
holder.versionName.setText(repo.getVersion());
|
holder.versionName.setText(repo.getVersion());
|
||||||
String author = repo.getAuthor();
|
String author = repo.getAuthor();
|
||||||
holder.author.setText(TextUtils.isEmpty(author) ? null : mContext.getString(R.string.author, author));
|
holder.author.setText(TextUtils.isEmpty(author) ? null : context.getString(R.string.author, author));
|
||||||
holder.description.setText(repo.getDescription());
|
holder.description.setText(repo.getDescription());
|
||||||
|
|
||||||
holder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), mContext));
|
holder.infoLayout.setOnClickListener(v ->
|
||||||
|
new MarkDownWindow((Activity) context, null, repo.getDetailUrl()).exec());
|
||||||
|
|
||||||
holder.downloadImage.setOnClickListener(v -> {
|
holder.downloadImage.setOnClickListener(v -> {
|
||||||
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
|
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
|
||||||
new AlertDialogBuilder(mContext)
|
new AlertDialogBuilder((Activity) context)
|
||||||
.setTitle(mContext.getString(R.string.repo_install_title, repo.getName()))
|
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
|
||||||
.setMessage(mContext.getString(R.string.repo_install_msg, filename))
|
.setMessage(context.getString(R.string.repo_install_msg, filename))
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive(
|
.setPositiveButton(R.string.install, (d, i) ->
|
||||||
mContext,
|
new ProcessRepoZip((Activity) context, repo.getZipUrl(),
|
||||||
new DownloadReceiver() {
|
Utils.getLegalFilename(filename), true).exec()
|
||||||
@Override
|
)
|
||||||
public void onDownloadDone(Uri uri) {
|
.setNeutralButton(R.string.download, (d, i) ->
|
||||||
new ProcessRepoZip(activity, uri, true).exec();
|
new ProcessRepoZip((Activity) context, repo.getZipUrl(),
|
||||||
}
|
Utils.getLegalFilename(filename), false).exec())
|
||||||
},
|
|
||||||
repo.getZipUrl(),
|
|
||||||
Utils.getLegalFilename(filename)))
|
|
||||||
.setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive(
|
|
||||||
mContext,
|
|
||||||
new DownloadReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onDownloadDone(Uri uri) {
|
|
||||||
new ProcessRepoZip(activity, uri, false).exec();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
repo.getZipUrl(),
|
|
||||||
Utils.getLegalFilename(filename)))
|
|
||||||
.setNegativeButton(R.string.no_thanks, null)
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
.show();
|
.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void notifyDBChanged() {
|
||||||
public int getItemCount() {
|
if (repoCursor != null)
|
||||||
return mUpdateRepos.size() + mInstalledRepos.size() + mOthersRepos.size();
|
repoCursor.close();
|
||||||
|
repoCursor = repoDB.getRepoCursor();
|
||||||
|
filter("");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Repo getItem(int position) {
|
public void filter(String s) {
|
||||||
if (position >= mUpdateRepos.size()) {
|
List<Repo> updates = new ArrayList<>();
|
||||||
position -= mUpdateRepos.size();
|
List<Repo> installed = new ArrayList<>();
|
||||||
if (position >= mInstalledRepos.size()) {
|
List<Repo> others = new ArrayList<>();
|
||||||
position -= mInstalledRepos.size();
|
|
||||||
return mOthersRepos.get(position);
|
repoPairs.clear();
|
||||||
} else {
|
while (repoCursor.moveToNext()) {
|
||||||
return mInstalledRepos.get(position);
|
Repo repo = new Repo(repoCursor);
|
||||||
|
if (repo.getName().toLowerCase().contains(s.toLowerCase())
|
||||||
|
|| repo.getAuthor().toLowerCase().contains(s.toLowerCase())
|
||||||
|
|| repo.getDescription().toLowerCase().contains(s.toLowerCase())
|
||||||
|
) {
|
||||||
|
// Passed the repoFilter
|
||||||
|
Module module = moduleMap.get(repo.getId());
|
||||||
|
if (module != null) {
|
||||||
|
if (repo.getVersionCode() > module.getVersionCode()) {
|
||||||
|
// Updates
|
||||||
|
updates.add(repo);
|
||||||
|
} else {
|
||||||
|
installed.add(repo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
others.add(repo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return mUpdateRepos.get(position);
|
repoCursor.moveToFirst();
|
||||||
|
|
||||||
|
if (!updates.isEmpty())
|
||||||
|
repoPairs.add(new Pair<>(UPDATES, updates));
|
||||||
|
if (!installed.isEmpty())
|
||||||
|
repoPairs.add(new Pair<>(INSTALLED, installed));
|
||||||
|
if (!others.isEmpty())
|
||||||
|
repoPairs.add(new Pair<>(OTHERS, others));
|
||||||
|
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SectionHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
@BindView(R.id.section_text) TextView sectionText;
|
||||||
|
|
||||||
|
SectionHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
ButterKnife.bind(this, itemView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
static class RepoHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
@BindView(R.id.title) TextView title;
|
@BindView(R.id.title) TextView title;
|
||||||
@BindView(R.id.version_name) TextView versionName;
|
@BindView(R.id.version_name) TextView versionName;
|
||||||
@@ -113,7 +181,7 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
|
|||||||
@BindView(R.id.info_layout) LinearLayout infoLayout;
|
@BindView(R.id.info_layout) LinearLayout infoLayout;
|
||||||
@BindView(R.id.download) ImageView downloadImage;
|
@BindView(R.id.download) ImageView downloadImage;
|
||||||
|
|
||||||
ViewHolder(View itemView) {
|
RepoHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
ButterKnife.bind(this, itemView);
|
ButterKnife.bind(this, itemView);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package com.topjohnwu.magisk.adapters;
|
||||||
|
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
public abstract class SectionedAdapter<S extends RecyclerView.ViewHolder, C extends RecyclerView.ViewHolder>
|
||||||
|
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
|
||||||
|
private static final int SECTION_TYPE = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
if (viewType == SECTION_TYPE)
|
||||||
|
return onCreateSectionViewHolder(parent);
|
||||||
|
return onCreateItemViewHolder(parent, viewType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||||
|
PositionInfo info = getPositionInfo(position);
|
||||||
|
if (info.position == -1)
|
||||||
|
onBindSectionViewHolder((S) holder, info.section);
|
||||||
|
else
|
||||||
|
onBindItemViewHolder((C) holder, info.section, info.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public int getItemCount() {
|
||||||
|
int size, sec;
|
||||||
|
size = sec = getSectionCount();
|
||||||
|
for (int i = 0; i < sec; ++i){
|
||||||
|
size += getItemCount(i);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public int getItemViewType(int position) {
|
||||||
|
PositionInfo info = getPositionInfo(position);
|
||||||
|
if (info.position == -1)
|
||||||
|
return SECTION_TYPE;
|
||||||
|
else
|
||||||
|
return getItemViewType(info.section, info.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getItemViewType(int section, int position) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getSectionPosition(int section) {
|
||||||
|
return getItemPosition(section, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getItemPosition(int section, int position) {
|
||||||
|
int realPosition = 0;
|
||||||
|
// Previous sections
|
||||||
|
for (int i = 0; i < section; ++i) {
|
||||||
|
realPosition += getItemCount(i) + 1;
|
||||||
|
}
|
||||||
|
// Current section
|
||||||
|
realPosition += position + 1;
|
||||||
|
return realPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PositionInfo getPositionInfo(int position) {
|
||||||
|
int section = 0;
|
||||||
|
while (true) {
|
||||||
|
if (position == 0)
|
||||||
|
return new PositionInfo(section, -1);
|
||||||
|
position -= 1;
|
||||||
|
if (position < getItemCount(section))
|
||||||
|
return new PositionInfo(section, position);
|
||||||
|
position -= getItemCount(section++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PositionInfo {
|
||||||
|
int section;
|
||||||
|
int position;
|
||||||
|
PositionInfo(int section, int position) {
|
||||||
|
this.section = section;
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int getSectionCount();
|
||||||
|
public abstract int getItemCount(int section);
|
||||||
|
public abstract S onCreateSectionViewHolder(ViewGroup parent);
|
||||||
|
public abstract C onCreateItemViewHolder(ViewGroup parent, int viewType);
|
||||||
|
public abstract void onBindSectionViewHolder(S holder, int section);
|
||||||
|
public abstract void onBindItemViewHolder(C holder, int section, int position);
|
||||||
|
}
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.adapters;
|
|
||||||
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.util.SparseArray;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
public class SimpleSectionedRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|
||||||
|
|
||||||
private static final int SECTION_TYPE = 0;
|
|
||||||
|
|
||||||
private boolean mValid = true;
|
|
||||||
private int mSectionResourceId;
|
|
||||||
private int mTextResourceId;
|
|
||||||
private RecyclerView.Adapter mBaseAdapter;
|
|
||||||
private SparseArray<Section> mSections = new SparseArray<Section>();
|
|
||||||
|
|
||||||
|
|
||||||
public SimpleSectionedRecyclerViewAdapter(int sectionResourceId, int textResourceId,
|
|
||||||
RecyclerView.Adapter baseAdapter) {
|
|
||||||
|
|
||||||
mSectionResourceId = sectionResourceId;
|
|
||||||
mTextResourceId = textResourceId;
|
|
||||||
mBaseAdapter = baseAdapter;
|
|
||||||
|
|
||||||
mBaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
|
||||||
@Override
|
|
||||||
public void onChanged() {
|
|
||||||
mValid = mBaseAdapter.getItemCount()>0;
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onItemRangeChanged(int positionStart, int itemCount) {
|
|
||||||
mValid = mBaseAdapter.getItemCount()>0;
|
|
||||||
notifyItemRangeChanged(positionStart, itemCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onItemRangeInserted(int positionStart, int itemCount) {
|
|
||||||
mValid = mBaseAdapter.getItemCount()>0;
|
|
||||||
notifyItemRangeInserted(positionStart, itemCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onItemRangeRemoved(int positionStart, int itemCount) {
|
|
||||||
mValid = mBaseAdapter.getItemCount()>0;
|
|
||||||
notifyItemRangeRemoved(positionStart, itemCount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class SectionViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
|
|
||||||
public TextView title;
|
|
||||||
|
|
||||||
public SectionViewHolder(View view, int mTextResourceid) {
|
|
||||||
super(view);
|
|
||||||
title = (TextView) view.findViewById(mTextResourceid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int typeView) {
|
|
||||||
if (typeView == SECTION_TYPE) {
|
|
||||||
View view = LayoutInflater.from(parent.getContext()).inflate(mSectionResourceId, parent, false);
|
|
||||||
return new SectionViewHolder(view,mTextResourceId);
|
|
||||||
}else{
|
|
||||||
return mBaseAdapter.onCreateViewHolder(parent, typeView -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) {
|
|
||||||
if (isSectionHeaderPosition(position)) {
|
|
||||||
((SectionViewHolder)sectionViewHolder).title.setText(mSections.get(position).title);
|
|
||||||
}else{
|
|
||||||
mBaseAdapter.onBindViewHolder(sectionViewHolder,sectionedPositionToPosition(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemViewType(int position) {
|
|
||||||
return isSectionHeaderPosition(position)
|
|
||||||
? SECTION_TYPE
|
|
||||||
: mBaseAdapter.getItemViewType(sectionedPositionToPosition(position)) +1 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class Section {
|
|
||||||
int firstPosition;
|
|
||||||
int sectionedPosition;
|
|
||||||
CharSequence title;
|
|
||||||
|
|
||||||
public Section(int firstPosition, CharSequence title) {
|
|
||||||
this.firstPosition = firstPosition;
|
|
||||||
this.title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CharSequence getTitle() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setSections(Section[] sections) {
|
|
||||||
mSections.clear();
|
|
||||||
|
|
||||||
Arrays.sort(sections, new Comparator<Section>() {
|
|
||||||
@Override
|
|
||||||
public int compare(Section o, Section o1) {
|
|
||||||
return (o.firstPosition == o1.firstPosition)
|
|
||||||
? 0
|
|
||||||
: ((o.firstPosition < o1.firstPosition) ? -1 : 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
int offset = 0; // offset positions for the headers we're adding
|
|
||||||
for (Section section : sections) {
|
|
||||||
section.sectionedPosition = section.firstPosition + offset;
|
|
||||||
mSections.append(section.sectionedPosition, section);
|
|
||||||
++offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int positionToSectionedPosition(int position) {
|
|
||||||
int offset = 0;
|
|
||||||
for (int i = 0; i < mSections.size(); i++) {
|
|
||||||
if (mSections.valueAt(i).firstPosition > position) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++offset;
|
|
||||||
}
|
|
||||||
return position + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int sectionedPositionToPosition(int sectionedPosition) {
|
|
||||||
if (isSectionHeaderPosition(sectionedPosition)) {
|
|
||||||
return RecyclerView.NO_POSITION;
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = 0;
|
|
||||||
for (int i = 0; i < mSections.size(); i++) {
|
|
||||||
if (mSections.valueAt(i).sectionedPosition > sectionedPosition) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
--offset;
|
|
||||||
}
|
|
||||||
return sectionedPosition + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSectionHeaderPosition(int position) {
|
|
||||||
return mSections.get(position) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getItemId(int position) {
|
|
||||||
return isSectionHeaderPosition(position)
|
|
||||||
? Integer.MAX_VALUE - mSections.indexOfKey(position)
|
|
||||||
: mBaseAdapter.getItemId(sectionedPositionToPosition(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return (mValid ? mBaseAdapter.getItemCount() + mSections.size() : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user