mirror of
https://github.com/topjohnwu/Magisk
synced 2025-10-27 04:02:14 +01:00
Compare commits
149 Commits
manager-v4
...
manager-v5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
435251ca41 | ||
|
|
324a0dd38f | ||
|
|
cc77d93918 | ||
|
|
0ea7d8bd8c | ||
|
|
849b217143 | ||
|
|
9af6efba59 | ||
|
|
079d6f06ef | ||
|
|
9cf0757689 | ||
|
|
b54c438948 | ||
|
|
c3ff4bfdad | ||
|
|
5d62e066e2 | ||
|
|
e94219c5a3 | ||
|
|
8ed9634adf | ||
|
|
0aefa9599f | ||
|
|
e279cf0575 | ||
|
|
a3f0ef8e77 | ||
|
|
8eba05ed4a | ||
|
|
2f78155723 | ||
|
|
6785221479 | ||
|
|
9bc410dd3d | ||
|
|
2491ab6bf9 | ||
|
|
f615ed40cd | ||
|
|
430f2cafc1 | ||
|
|
0ad049da88 | ||
|
|
2c7691567b | ||
|
|
1d70d0fe94 | ||
|
|
ac44f05811 | ||
|
|
d99252f394 | ||
|
|
b58c7ba7c5 | ||
|
|
8c5acd1a0a | ||
|
|
b9b1ebf18c | ||
|
|
8ca132cef0 | ||
|
|
a03bb90754 | ||
|
|
d1c939f48a | ||
|
|
21b11f1b48 | ||
|
|
23c84a7803 | ||
|
|
f9ab060403 | ||
|
|
df7a5bf149 | ||
|
|
c4afa069df | ||
|
|
1bfafdb44f | ||
|
|
1ef5bd7076 | ||
|
|
29176fa4f4 | ||
|
|
958c95732b | ||
|
|
44b0d4127c | ||
|
|
1418ec2416 | ||
|
|
b51978f51c | ||
|
|
b07361580a | ||
|
|
d1b5ebad7d | ||
|
|
f4ce813de9 | ||
|
|
b44ac994d8 | ||
|
|
333948814c | ||
|
|
1a51ad6e01 | ||
|
|
22a5c11f0d | ||
|
|
51b22d1ad4 | ||
|
|
bef5969580 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,6 +3,6 @@
|
||||
/local.properties
|
||||
.idea/
|
||||
/build
|
||||
app/app-release.apk
|
||||
app/release
|
||||
*.hprof
|
||||
app/.externalNativeBuild/
|
||||
|
||||
10
README.md
10
README.md
@@ -1,4 +1,6 @@
|
||||
# Magisk Manager
|
||||
The project should be built with Android Studio version 2.2.0+
|
||||
I use Java 8 features, which requires Jack compiler and it's only available in 2.2.0+
|
||||
Also, you need to install CMake and NDK to build the zipadjust library for zip preprocessing
|
||||
# Magisk Manager
|
||||
You need to install CMake and NDK to build the zipadjust library for zip preprocessing
|
||||
|
||||
## Pre-built Binaries
|
||||
Busybox (arm and x86) compiled by osm0sis (`libbusybox.so` under `app\src\main\jniLibs`)
|
||||
Source and more info: [osm0sis' Odds and Ends](https://forum.xda-developers.com/showthread.php?t=2239421)
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion "25.0.2"
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion "26.0.0"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.topjohnwu.magisk"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 20
|
||||
versionName "4.0"
|
||||
jackOptions {
|
||||
enabled true
|
||||
jackInProcess true
|
||||
}
|
||||
targetSdkVersion 26
|
||||
versionCode 44
|
||||
versionName "5.0.4"
|
||||
ndk {
|
||||
moduleName 'zipadjust'
|
||||
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
||||
abiFilters 'x86', 'armeabi-v7a'
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
@@ -31,35 +28,36 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
dexOptions {
|
||||
preDexLibraries = true
|
||||
preDexLibraries true
|
||||
javaMaxHeapSize "2g"
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path 'src/main/jni/CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
disable 'MissingTranslation'
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url "https://jitpack.io" }
|
||||
maven { url "https://maven.google.com" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
|
||||
compile 'com.android.support:recyclerview-v7:25.1.1'
|
||||
compile 'com.android.support:cardview-v7:25.1.1'
|
||||
compile 'com.android.support:design:25.1.1'
|
||||
compile 'com.android.support:support-v4:25.1.1'
|
||||
compile 'com.android.support:support-v13:25.1.1'
|
||||
compile 'com.jakewharton:butterknife:8.5.1'
|
||||
compile 'com.google.code.gson:gson:2.8.0'
|
||||
compile 'com.github.clans:fab:1.6.4'
|
||||
compile 'com.thoughtbot:expandablerecyclerview:1.4'
|
||||
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'
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.android.support:recyclerview-v7:26.0.0-beta2'
|
||||
implementation 'com.android.support:cardview-v7:26.0.0-beta2'
|
||||
implementation 'com.android.support:design:26.0.0-beta2'
|
||||
implementation 'com.android.support:support-v4:26.0.0-beta2'
|
||||
implementation 'com.jakewharton:butterknife:8.6.0'
|
||||
implementation 'com.thoughtbot:expandablerecyclerview:1.4'
|
||||
implementation 'us.feras.mdv:markdownview:1.1.0'
|
||||
implementation 'com.madgag.spongycastle:core:1.54.0.0'
|
||||
implementation 'com.madgag.spongycastle:prov:1.54.0.0'
|
||||
implementation 'com.madgag.spongycastle:pkix:1.54.0.0'
|
||||
implementation 'com.google.android.gms:play-services-safetynet:9.0.1'
|
||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'
|
||||
}
|
||||
|
||||
33
app/proguard-rules.pro
vendored
33
app/proguard-rules.pro
vendored
@@ -16,31 +16,10 @@
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Gson uses generic type information stored in a class file when working with fields. Proguard
|
||||
# removes such information by default, so configure it to keep all of it.
|
||||
-keepattributes Signature
|
||||
|
||||
# For using GSON @Expose annotation
|
||||
-keepattributes *Annotation*
|
||||
|
||||
# Gson specific classes
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
-keep class com.google.gson.** { *; }
|
||||
|
||||
# Application classes that will be serialized/deserialized over Gson
|
||||
-keep class com.topjohnwu.magisk.module.** { *; }
|
||||
-keep class com.topjohnwu.magisk.module.ModuleHelper$ValueSortedMap { *; }
|
||||
|
||||
# Prevent proguard from stripping interface information from TypeAdapterFactory,
|
||||
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
|
||||
-keep class * implements com.google.gson.TypeAdapterFactory
|
||||
-keep class * implements com.google.gson.JsonSerializer
|
||||
-keep class * implements com.google.gson.JsonDeserializer
|
||||
|
||||
-keep class android.support.v7.internal.** { *; }
|
||||
-keep interface android.support.v7.internal.** { *; }
|
||||
-keep class android.support.v7.** { *; }
|
||||
-keep interface android.support.v7.** { *; }
|
||||
|
||||
# SpongyCastle
|
||||
-keep class org.spongycastle.** {*;}
|
||||
-keep class org.spongycastle.** { *; }
|
||||
-dontwarn javax.naming.**
|
||||
|
||||
-dontwarn android.content.**
|
||||
-dontwarn android.animation.**
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.topjohnwu.magisk"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest
|
||||
package="com.topjohnwu.magisk"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<application
|
||||
android:name=".MagiskManager"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
@@ -50,8 +52,7 @@
|
||||
android:taskAffinity="internal.superuser"
|
||||
android:theme="@style/SuRequest" />
|
||||
|
||||
<receiver
|
||||
android:name=".superuser.SuReceiver" />
|
||||
<receiver android:name=".superuser.SuReceiver" />
|
||||
|
||||
<receiver android:name=".receivers.BootReceiver">
|
||||
<intent-filter>
|
||||
@@ -59,6 +60,23 @@
|
||||
</intent-filter>
|
||||
</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" />
|
||||
<data android:scheme="package" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".receivers.ManagerUpdate" />
|
||||
|
||||
<service android:name=".services.OnBootIntentService" />
|
||||
|
||||
<service
|
||||
android:name=".services.UpdateCheckService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||
android:exported="true" />
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="com.topjohnwu.magisk.provider"
|
||||
|
||||
276
app/src/main/assets/dark.css
Normal file
276
app/src/main/assets/dark.css
Normal file
File diff suppressed because it is too large
Load Diff
277
app/src/main/assets/light.css
Normal file
277
app/src/main/assets/light.css
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
192
app/src/main/assets/util_functions.sh
Normal file
192
app/src/main/assets/util_functions.sh
Normal file
@@ -0,0 +1,192 @@
|
||||
##########################################################################################
|
||||
#
|
||||
# Magisk General Utility Functions
|
||||
# by topjohnwu
|
||||
#
|
||||
# Used in flash_script.sh, addon.d.sh, magisk module installers, and uninstaller
|
||||
#
|
||||
##########################################################################################
|
||||
|
||||
get_outfd() {
|
||||
readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
|
||||
if [ "$?" -eq "0" ]; then
|
||||
OUTFD=0
|
||||
|
||||
for FD in `ls /proc/$$/fd`; do
|
||||
readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
|
||||
if [ "$?" -eq "0" ]; then
|
||||
ps | grep " 3 $FD " | grep -v grep >/dev/null
|
||||
if [ "$?" -eq "0" ]; then
|
||||
OUTFD=$FD
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
ui_print() {
|
||||
if $BOOTMODE; then
|
||||
echo "$1"
|
||||
else
|
||||
echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD
|
||||
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
|
||||
fi
|
||||
}
|
||||
|
||||
getvar() {
|
||||
local VARNAME=$1
|
||||
local VALUE=$(eval echo \$"$VARNAME");
|
||||
for FILE in /dev/.magisk /data/.magisk /cache/.magisk /system/.magisk; do
|
||||
if [ -z "$VALUE" ]; then
|
||||
LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=")
|
||||
if [ ! -z "$LINE" ]; then
|
||||
VALUE=${LINE#*=}
|
||||
fi
|
||||
fi
|
||||
done
|
||||
eval $VARNAME=\$VALUE
|
||||
}
|
||||
|
||||
find_boot_image() {
|
||||
if [ -z "$BOOTIMAGE" ]; then
|
||||
for BLOCK in boot_a BOOT_A kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
|
||||
BOOTIMAGE=`ls /dev/block/by-name/$BLOCK || ls /dev/block/platform/*/by-name/$BLOCK || ls /dev/block/platform/*/*/by-name/$BLOCK` 2>/dev/null
|
||||
[ ! -z $BOOTIMAGE ] && break
|
||||
done
|
||||
fi
|
||||
# Recovery fallback
|
||||
if [ -z "$BOOTIMAGE" ]; then
|
||||
for FSTAB in /etc/*fstab*; do
|
||||
BOOTIMAGE=`grep -E '\b/boot\b' $FSTAB | grep -v "#" | grep -oE '/dev/[a-zA-Z0-9_./-]*'`
|
||||
[ ! -z $BOOTIMAGE ] && break
|
||||
done
|
||||
fi
|
||||
[ -L "$BOOTIMAGE" ] && BOOTIMAGE=`readlink $BOOTIMAGE`
|
||||
}
|
||||
|
||||
is_mounted() {
|
||||
if [ ! -z "$2" ]; then
|
||||
cat /proc/mounts | grep $1 | grep $2, >/dev/null
|
||||
else
|
||||
cat /proc/mounts | grep $1 >/dev/null
|
||||
fi
|
||||
return $?
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
remove_system_su() {
|
||||
if [ -f /system/bin/su -o -f /system/xbin/su ] && [ ! -f /su/bin/su ]; then
|
||||
ui_print "! System installed root detected, mount rw :("
|
||||
mount -o rw,remount /system
|
||||
# SuperSU
|
||||
if [ -e /system/bin/.ext/.su ]; then
|
||||
mv -f /system/bin/app_process32_original /system/bin/app_process32 2>/dev/null
|
||||
mv -f /system/bin/app_process64_original /system/bin/app_process64 2>/dev/null
|
||||
mv -f /system/bin/install-recovery_original.sh /system/bin/install-recovery.sh 2>/dev/null
|
||||
cd /system/bin
|
||||
if [ -e app_process64 ]; then
|
||||
ln -sf app_process64 app_process
|
||||
else
|
||||
ln -sf app_process32 app_process
|
||||
fi
|
||||
fi
|
||||
rm -rf /system/.pin /system/bin/.ext /system/etc/.installed_su_daemon /system/etc/.has_su_daemon \
|
||||
/system/xbin/daemonsu /system/xbin/su /system/xbin/sugote /system/xbin/sugote-mksh /system/xbin/supolicy \
|
||||
/system/bin/app_process_init /system/bin/su /cache/su /system/lib/libsupol.so /system/lib64/libsupol.so \
|
||||
/system/su.d /system/etc/install-recovery.sh /system/etc/init.d/99SuperSUDaemon /cache/install-recovery.sh \
|
||||
/system/.supersu /cache/.supersu /data/.supersu \
|
||||
/system/app/Superuser.apk /system/app/SuperSU /cache/Superuser.apk 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
api_level_arch_detect() {
|
||||
API=`grep_prop ro.build.version.sdk`
|
||||
ABI=`grep_prop ro.product.cpu.abi | cut -c-3`
|
||||
ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3`
|
||||
ABILONG=`grep_prop ro.product.cpu.abi`
|
||||
|
||||
ARCH=arm
|
||||
IS64BIT=false
|
||||
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
|
||||
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
|
||||
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
|
||||
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
|
||||
}
|
||||
|
||||
recovery_actions() {
|
||||
# TWRP bug fix
|
||||
mount -o bind /dev/urandom /dev/random
|
||||
# Temporarily block out all custom recovery binaries/libs
|
||||
mv /sbin /sbin_tmp
|
||||
# Add all possible library paths
|
||||
OLD_LD_PATH=$LD_LIBRARY_PATH
|
||||
$IS64BIT && export LD_LIBRARY_PATH=/system/lib64:/system/vendor/lib64 || export LD_LIBRARY_PATH=/system/lib:/system/vendor/lib
|
||||
}
|
||||
|
||||
recovery_cleanup() {
|
||||
mv /sbin_tmp /sbin
|
||||
# Clear LD_LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH=$OLD_LD_PATH
|
||||
ui_print "- Unmounting partitions"
|
||||
umount -l /system
|
||||
umount -l /vendor 2>/dev/null
|
||||
umount -l /dev/random
|
||||
}
|
||||
|
||||
abort() {
|
||||
ui_print "$1"
|
||||
mv /sbin_tmp /sbin 2>/dev/null
|
||||
exit 1
|
||||
}
|
||||
|
||||
set_perm() {
|
||||
chown $2:$3 $1 || exit 1
|
||||
chmod $4 $1 || exit 1
|
||||
if [ ! -z $5 ]; then
|
||||
chcon $5 $1 2>/dev/null
|
||||
else
|
||||
chcon 'u:object_r:system_file:s0' $1 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
set_perm_recursive() {
|
||||
find $1 -type d 2>/dev/null | while read dir; do
|
||||
set_perm $dir $2 $3 $4 $6
|
||||
done
|
||||
find $1 -type f 2>/dev/null | while read file; do
|
||||
set_perm $file $2 $3 $5 $6
|
||||
done
|
||||
}
|
||||
|
||||
mktouch() {
|
||||
mkdir -p ${1%/*}
|
||||
if [ -z "$2" ]; then
|
||||
touch $1
|
||||
else
|
||||
echo $2 > $1
|
||||
fi
|
||||
chmod 644 $1
|
||||
}
|
||||
|
||||
request_size_check() {
|
||||
reqSizeM=`du -s $1 | cut -f1`
|
||||
reqSizeM=$((reqSizeM / 1024 + 1))
|
||||
}
|
||||
|
||||
image_size_check() {
|
||||
SIZE="`$MAGISKBIN/magisk --imgsize $IMG`"
|
||||
curUsedM=`echo "$SIZE" | cut -d" " -f1`
|
||||
curSizeM=`echo "$SIZE" | cut -d" " -f2`
|
||||
curFreeM=$((curSizeM - curUsedM))
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 73 KiB |
@@ -1,24 +1,22 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -26,9 +24,9 @@ import java.io.InputStream;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class AboutActivity extends AppCompatActivity {
|
||||
public class AboutActivity extends Activity {
|
||||
|
||||
private static final String DONATION_URL = "http://topjohnwu.github.io/donate";
|
||||
private static final String DONATION_URL = "https://www.paypal.me/topjohnwu";
|
||||
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";
|
||||
|
||||
@@ -44,10 +42,8 @@ public class AboutActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
String theme = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("theme", "");
|
||||
Logger.dev("AboutActivity: Theme is " + theme);
|
||||
if (Global.Configs.isDarkTheme) {
|
||||
setTheme(R.style.AppTheme_dh);
|
||||
if (getApplicationContext().isDarkTheme) {
|
||||
setTheme(R.style.AppTheme_Transparent_Dark);
|
||||
}
|
||||
setContentView(R.layout.activity_about);
|
||||
ButterKnife.bind(this);
|
||||
@@ -85,7 +81,7 @@ public class AboutActivity extends AppCompatActivity {
|
||||
result = Html.fromHtml(changes);
|
||||
}
|
||||
appChangelog.setOnClickListener(v -> {
|
||||
AlertDialog d = Utils.getAlertDialogBuilder(this)
|
||||
AlertDialog d = new AlertDialogBuilder(this)
|
||||
.setTitle(R.string.app_changelog)
|
||||
.setMessage(result)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
@@ -104,7 +100,7 @@ public class AboutActivity extends AppCompatActivity {
|
||||
} else {
|
||||
result = Html.fromHtml(getString(R.string.app_developers_));
|
||||
}
|
||||
AlertDialog d = Utils.getAlertDialogBuilder(this)
|
||||
AlertDialog d = new AlertDialogBuilder(this)
|
||||
.setTitle(R.string.app_developers)
|
||||
.setMessage(result)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
@@ -134,18 +130,4 @@ public class AboutActivity extends AppCompatActivity {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ValueSortedMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class Global {
|
||||
|
||||
public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk";
|
||||
|
||||
public static class Info {
|
||||
public static double magiskVersion;
|
||||
public static String magiskVersionString = "(none)";
|
||||
public static double remoteMagiskVersion = -1;
|
||||
public static String magiskLink;
|
||||
public static String releaseNoteLink;
|
||||
public static int SNCheckResult = -1;
|
||||
public static String bootBlock = null;
|
||||
public static boolean isSuClient = false;
|
||||
public static String suVersion = null;
|
||||
public static boolean disabled = false;
|
||||
}
|
||||
public static class Data {
|
||||
public static ValueSortedMap<String, Repo> repoMap;
|
||||
public static ValueSortedMap<String, Module> moduleMap;
|
||||
public static List<String> blockList;
|
||||
public static List<ApplicationInfo> appList;
|
||||
public static List<String> magiskHideList;
|
||||
}
|
||||
public static class Events {
|
||||
public static final CallbackHandler.Event blockDetectionDone = new CallbackHandler.Event();
|
||||
public static final CallbackHandler.Event packageLoadDone = new CallbackHandler.Event();
|
||||
public static final CallbackHandler.Event reloadMainActivity = new CallbackHandler.Event();
|
||||
public static final CallbackHandler.Event moduleLoadDone = new CallbackHandler.Event();
|
||||
public static final CallbackHandler.Event repoLoadDone = new CallbackHandler.Event();
|
||||
public static final CallbackHandler.Event updateCheckDone = new CallbackHandler.Event();
|
||||
public static final CallbackHandler.Event safetyNetDone = new CallbackHandler.Event();
|
||||
public static SparseArray<CallbackHandler.Event> uidMap = new SparseArray<>();
|
||||
}
|
||||
public static class Configs {
|
||||
public static boolean isDarkTheme;
|
||||
public static boolean shellLogging;
|
||||
public static boolean devLogging;
|
||||
public static boolean magiskHide;
|
||||
public static int suRequestTimeout;
|
||||
public static int suLogTimeout = 14;
|
||||
public static int suAccessState;
|
||||
public static int suResponseType;
|
||||
public static int suNotificationType;
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Configs.isDarkTheme = prefs.getBoolean("dark_theme", false);
|
||||
Configs.devLogging = prefs.getBoolean("developer_logging", false);
|
||||
Configs.shellLogging = prefs.getBoolean("shell_logging", false);
|
||||
Configs.magiskHide = prefs.getBoolean("magiskhide", false);
|
||||
updateMagiskInfo();
|
||||
initSuAccess();
|
||||
initSuConfigs(context);
|
||||
// Initialize prefs
|
||||
prefs.edit()
|
||||
.putBoolean("dark_theme", Configs.isDarkTheme)
|
||||
.putBoolean("magiskhide", Configs.magiskHide)
|
||||
.putBoolean("busybox", Utils.commandExists("busybox"))
|
||||
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
|
||||
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
|
||||
.putString("su_request_timeout", String.valueOf(Configs.suRequestTimeout))
|
||||
.putString("su_auto_response", String.valueOf(Configs.suResponseType))
|
||||
.putString("su_notification", String.valueOf(Configs.suNotificationType))
|
||||
.putString("su_access", String.valueOf(Configs.suAccessState))
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void initSuConfigs(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Configs.suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
|
||||
Configs.suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
|
||||
Configs.suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
|
||||
}
|
||||
|
||||
public static void initSuAccess() {
|
||||
List<String> ret = Shell.sh("su -v");
|
||||
if (Utils.isValidShellResponse(ret)) {
|
||||
Info.suVersion = ret.get(0);
|
||||
Info.isSuClient = Info.suVersion.toUpperCase().contains("MAGISK");
|
||||
}
|
||||
if (Info.isSuClient) {
|
||||
ret = Shell.sh("getprop persist.sys.root_access");
|
||||
if (Utils.isValidShellResponse(ret))
|
||||
Configs.suAccessState = Integer.parseInt(ret.get(0));
|
||||
else {
|
||||
Shell.su(true, "setprop persist.sys.root_access 3");
|
||||
Configs.suAccessState = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateMagiskInfo() {
|
||||
List<String> ret = Shell.sh("getprop magisk.version");
|
||||
if (!Utils.isValidShellResponse(ret)) {
|
||||
Info.magiskVersion = -1;
|
||||
} else {
|
||||
try {
|
||||
Info.magiskVersionString = ret.get(0);
|
||||
Info.magiskVersion = Double.parseDouble(ret.get(0));
|
||||
} catch (NumberFormatException e) {
|
||||
// Custom version don't need to receive updates
|
||||
Info.magiskVersion = Double.POSITIVE_INFINITY;
|
||||
}
|
||||
}
|
||||
ret = Shell.sh("getprop ro.magisk.disable");
|
||||
try {
|
||||
Info.disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
|
||||
} catch (NumberFormatException e) {
|
||||
Info.disabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,174 +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.v4.app.Fragment;
|
||||
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.receivers.MagiskDlReceiver;
|
||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
||||
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 butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class InstallFragment extends Fragment implements CallbackHandler.EventListener {
|
||||
|
||||
|
||||
private static final String UNINSTALLER = "magisk_uninstaller.sh";
|
||||
|
||||
private Unbinder unbinder;
|
||||
@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.flash_button) CardView flashButton;
|
||||
@BindView(R.id.uninstall_button) CardView uninstallButton;
|
||||
@BindView(R.id.keep_force_enc) CheckBox keepEncChkbox;
|
||||
@BindView(R.id.keep_verity) CheckBox keepVerityChkbox;
|
||||
|
||||
@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);
|
||||
detectButton.setOnClickListener(v1 -> toAutoDetect());
|
||||
currentVersionTitle.setText(getString(R.string.current_magisk_title, Global.Info.magiskVersionString));
|
||||
installTitle.setText(getString(R.string.install_magisk_title, Global.Info.remoteMagiskVersion));
|
||||
flashButton.setOnClickListener(v1 -> {
|
||||
String bootImage;
|
||||
if (Global.Info.bootBlock != null) {
|
||||
if (spinner.getSelectedItemPosition() > 0)
|
||||
bootImage = Global.Data.blockList.get(spinner.getSelectedItemPosition() - 1);
|
||||
else
|
||||
bootImage = Global.Info.bootBlock;
|
||||
} else {
|
||||
bootImage = Global.Data.blockList.get(spinner.getSelectedItemPosition());
|
||||
}
|
||||
String filename = "Magisk-v" + Global.Info.remoteMagiskVersion + ".zip";
|
||||
Utils.getAlertDialogBuilder(getActivity())
|
||||
.setTitle(getString(R.string.repo_install_title, getString(R.string.magisk)))
|
||||
.setMessage(getString(R.string.repo_install_msg, filename))
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive(
|
||||
getActivity(),
|
||||
new MagiskDlReceiver(bootImage, keepEncChkbox.isChecked(), keepVerityChkbox.isChecked()),
|
||||
Global.Info.magiskLink,
|
||||
Utils.getLegalFilename(filename)))
|
||||
.setNeutralButton(R.string.check_release_notes, (dialog, which) -> {
|
||||
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Global.Info.releaseNoteLink)));
|
||||
})
|
||||
.setNegativeButton(R.string.no_thanks, null)
|
||||
.show();
|
||||
});
|
||||
if (Global.Info.magiskVersion < 10.3) {
|
||||
uninstallButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
uninstallButton.setOnClickListener(vi -> {
|
||||
Utils.getAlertDialogBuilder(getActivity())
|
||||
.setTitle("Uninstall Magisk")
|
||||
.setMessage("This will remove all modules, MagiskSU, and potentially re-encrypt your device\nAre you sure to process?")
|
||||
.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
|
||||
try {
|
||||
InputStream in = getActivity().getAssets().open(UNINSTALLER);
|
||||
File uninstaller = new File(getActivity().getCacheDir().getAbsolutePath() + "/" + 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, "cp -af " + uninstaller + " /cache/" + UNINSTALLER,
|
||||
"reboot");
|
||||
}
|
||||
}.start();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.no_thanks, null)
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
if (Global.Events.blockDetectionDone.isTriggered) {
|
||||
updateUI();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackHandler.Event event) {
|
||||
updateUI();
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
List<String> items = new ArrayList<>(Global.Data.blockList);
|
||||
if (Global.Info.bootBlock != null)
|
||||
items.add(0, getString(R.string.auto_detect, Global.Info.bootBlock));
|
||||
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();
|
||||
}
|
||||
|
||||
private void toAutoDetect() {
|
||||
if (Global.Info.bootBlock != null) {
|
||||
spinner.setSelection(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getActivity().setTitle(R.string.install);
|
||||
CallbackHandler.register(Global.Events.blockDetectionDone, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
CallbackHandler.unRegister(Global.Events.blockDetectionDone, this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
unbinder.unbind();
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,13 @@ package com.topjohnwu.magisk;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.TabFragmentAdapter;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
@@ -31,14 +31,14 @@ public class LogFragment extends Fragment {
|
||||
|
||||
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
|
||||
|
||||
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
||||
|
||||
if (Global.Info.isSuClient) {
|
||||
if (getApplication().isSuClient) {
|
||||
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
|
||||
tab.setupWithViewPager(viewPager);
|
||||
tab.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
||||
|
||||
viewPager.setAdapter(adapter);
|
||||
|
||||
return v;
|
||||
|
||||
509
app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java
Normal file
509
app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
@@ -16,15 +15,16 @@ import android.view.ViewGroup;
|
||||
import android.widget.SearchView;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
||||
import com.topjohnwu.magisk.utils.Async;
|
||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class MagiskHideFragment extends Fragment implements CallbackHandler.EventListener {
|
||||
public class MagiskHideFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
||||
|
||||
private Unbinder unbinder;
|
||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||
@@ -50,7 +50,7 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
||||
PackageManager packageManager = getActivity().getPackageManager();
|
||||
|
||||
mSwipeRefreshLayout.setRefreshing(true);
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> new Async.LoadApps(packageManager).exec());
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> new MagiskHide(getActivity()).list());
|
||||
|
||||
appAdapter = new ApplicationAdapter(packageManager);
|
||||
recyclerView.setAdapter(appAdapter);
|
||||
@@ -71,6 +71,10 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
||||
}
|
||||
};
|
||||
|
||||
if (getApplication().magiskHideDone.isTriggered) {
|
||||
onTrigger(getApplication().magiskHideDone);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -85,15 +89,12 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getActivity().setTitle(R.string.magiskhide);
|
||||
CallbackHandler.register(Global.Events.packageLoadDone, this);
|
||||
if (Global.Events.packageLoadDone.isTriggered) {
|
||||
onTrigger(Global.Events.packageLoadDone);
|
||||
}
|
||||
getApplication().magiskHideDone.register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
CallbackHandler.unRegister(Global.Events.packageLoadDone, this);
|
||||
getApplication().magiskHideDone.unRegister(this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@@ -104,9 +105,9 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackHandler.Event event) {
|
||||
public void onTrigger(CallbackEvent<Void> event) {
|
||||
Logger.dev("MagiskHideFragment: UI refresh");
|
||||
appAdapter.setLists(Global.Data.appList, Global.Data.magiskHideList);
|
||||
appAdapter.setLists(getApplication().appList, getApplication().magiskHideList);
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
if (!TextUtils.isEmpty(lastFilter)) {
|
||||
appAdapter.filter(lastFilter);
|
||||
|
||||
@@ -11,7 +11,6 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -25,7 +24,9 @@ import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.utils.Async;
|
||||
import com.topjohnwu.magisk.asyncs.RootTask;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
@@ -121,19 +122,19 @@ public class MagiskLogFragment extends Fragment {
|
||||
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||
}
|
||||
} else {
|
||||
Snackbar.make(txtLog, R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
SnackbarMaker.make(txtLog, R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LogManager extends Async.RootTask<Object, Void, Object> {
|
||||
private class LogManager extends RootTask<Object, Void, Object> {
|
||||
|
||||
int mode;
|
||||
File targetFile;
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
@Override
|
||||
protected Object doInBackground(Object... params) {
|
||||
protected Object doInRoot(Object... params) {
|
||||
mode = (int) params[0];
|
||||
switch (mode) {
|
||||
case 0:
|
||||
@@ -150,7 +151,7 @@ public class MagiskLogFragment extends Fragment {
|
||||
|
||||
case 1:
|
||||
Shell.su("echo > " + MAGISK_LOG);
|
||||
Snackbar.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
||||
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
||||
return "";
|
||||
|
||||
case 2:
|
||||
@@ -161,8 +162,9 @@ public class MagiskLogFragment extends Fragment {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
String filename = String.format(
|
||||
@@ -174,8 +176,9 @@ public class MagiskLogFragment extends Fragment {
|
||||
targetFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/MagiskManager/" + filename);
|
||||
|
||||
if ((!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs())
|
||||
|| (targetFile.exists() && !targetFile.delete()))
|
||||
|| (targetFile.exists() && !targetFile.delete())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> in = Utils.readFile(MAGISK_LOG);
|
||||
|
||||
@@ -213,10 +216,11 @@ public class MagiskLogFragment extends Fragment {
|
||||
break;
|
||||
case 2:
|
||||
bool = (boolean) o;
|
||||
if (bool)
|
||||
if (bool) {
|
||||
Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG).show();
|
||||
else
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.logs_save_failed), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
207
app/src/main/java/com/topjohnwu/magisk/MagiskManager.java
Normal file
207
app/src/main/java/com/topjohnwu/magisk/MagiskManager.java
Normal file
@@ -0,0 +1,207 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.SafetyNetHelper;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ValueSortedMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class MagiskManager extends Application {
|
||||
|
||||
public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk";
|
||||
public static final String TMP_FOLDER_PATH = "/dev/tmp";
|
||||
public static final String MAGISK_PATH = "/magisk";
|
||||
public static final String UNINSTALLER = "magisk_uninstaller.sh";
|
||||
public static final String UTIL_FUNCTIONS= "util_functions.sh";
|
||||
public static final String INTENT_SECTION = "section";
|
||||
public static final String BUSYBOX_VERSION = "1.26.2";
|
||||
public static final String MAGISKHIDE_PROP = "persist.magisk.hide";
|
||||
public static final String DISABLE_INDICATION_PROP = "ro.magisk.disable";
|
||||
|
||||
// Events
|
||||
public final CallbackEvent<Void> blockDetectionDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> magiskHideDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> reloadMainActivity = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> moduleLoadDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> repoLoadDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> updateCheckDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> safetyNetDone = new CallbackEvent<>();
|
||||
|
||||
// Info
|
||||
public String magiskVersionString;
|
||||
public int magiskVersionCode = -1;
|
||||
public String remoteMagiskVersionString;
|
||||
public int remoteMagiskVersionCode = -1;
|
||||
public String magiskLink;
|
||||
public String releaseNoteLink;
|
||||
public String remoteManagerVersionString;
|
||||
public int remoteManagerVersionCode = -1;
|
||||
public String managerLink;
|
||||
public SafetyNetHelper.Result SNCheckResult;
|
||||
public String bootBlock = null;
|
||||
public boolean isSuClient = false;
|
||||
public String suVersion = null;
|
||||
public boolean disabled;
|
||||
|
||||
// Data
|
||||
public ValueSortedMap<String, Repo> repoMap;
|
||||
public ValueSortedMap<String, Module> moduleMap;
|
||||
public List<String> blockList;
|
||||
public List<ApplicationInfo> appList;
|
||||
public List<String> magiskHideList;
|
||||
|
||||
// Configurations
|
||||
public static boolean shellLogging;
|
||||
public static boolean devLogging;
|
||||
|
||||
public boolean magiskHide;
|
||||
public boolean isDarkTheme;
|
||||
public boolean updateNotification;
|
||||
public boolean suReauth;
|
||||
public int suRequestTimeout;
|
||||
public int suLogTimeout = 14;
|
||||
public int suAccessState;
|
||||
public int multiuserMode;
|
||||
public int suResponseType;
|
||||
public int suNotificationType;
|
||||
public int suNamespaceMode;
|
||||
|
||||
// Global resources
|
||||
public SharedPreferences prefs;
|
||||
public SuDatabaseHelper suDB;
|
||||
|
||||
private static Handler mHandler = new Handler();
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
}
|
||||
|
||||
public void toast(String msg, int duration) {
|
||||
mHandler.post(() -> Toast.makeText(this, msg, duration).show());
|
||||
}
|
||||
|
||||
public void toast(int resId, int duration) {
|
||||
mHandler.post(() -> Toast.makeText(this, resId, duration).show());
|
||||
}
|
||||
|
||||
public void init() {
|
||||
isDarkTheme = prefs.getBoolean("dark_theme", false);
|
||||
if (BuildConfig.DEBUG) {
|
||||
devLogging = prefs.getBoolean("developer_logging", false);
|
||||
shellLogging = prefs.getBoolean("shell_logging", false);
|
||||
} else {
|
||||
devLogging = false;
|
||||
shellLogging = false;
|
||||
}
|
||||
magiskHide = prefs.getBoolean("magiskhide", true);
|
||||
updateNotification = prefs.getBoolean("notification", true);
|
||||
initSU();
|
||||
// Always start a new root shell manually, just for safety
|
||||
Shell.init();
|
||||
updateMagiskInfo();
|
||||
// Initialize busybox
|
||||
File busybox = new File(getApplicationInfo().dataDir + "/busybox/busybox");
|
||||
if (!busybox.exists() || !TextUtils.equals(prefs.getString("busybox_version", ""), BUSYBOX_VERSION)) {
|
||||
busybox.getParentFile().mkdirs();
|
||||
Shell.su(
|
||||
"cp -f " + new File(getApplicationInfo().nativeLibraryDir, "libbusybox.so") + " " + busybox,
|
||||
"chmod -R 755 " + busybox.getParent(),
|
||||
busybox + " --install -s " + busybox.getParent()
|
||||
);
|
||||
}
|
||||
// Initialize prefs
|
||||
prefs.edit()
|
||||
.putBoolean("dark_theme", isDarkTheme)
|
||||
.putBoolean("magiskhide", magiskHide)
|
||||
.putBoolean("notification", updateNotification)
|
||||
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
|
||||
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
|
||||
.putBoolean("su_reauth", suReauth)
|
||||
.putString("su_request_timeout", String.valueOf(suRequestTimeout))
|
||||
.putString("su_auto_response", String.valueOf(suResponseType))
|
||||
.putString("su_notification", String.valueOf(suNotificationType))
|
||||
.putString("su_access", String.valueOf(suAccessState))
|
||||
.putString("multiuser_mode", String.valueOf(multiuserMode))
|
||||
.putString("mnt_ns", String.valueOf(suNamespaceMode))
|
||||
.putString("busybox_version", BUSYBOX_VERSION)
|
||||
.apply();
|
||||
// Add busybox to PATH
|
||||
Shell.su("PATH=$PATH:" + busybox.getParent());
|
||||
}
|
||||
|
||||
public void initSUConfig() {
|
||||
suDB = new SuDatabaseHelper(this);
|
||||
suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
|
||||
suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
|
||||
suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
|
||||
suReauth = prefs.getBoolean("su_reauth", false);
|
||||
}
|
||||
|
||||
public void initSU() {
|
||||
// Create the app data directory, so su binary can work properly
|
||||
new File(getApplicationInfo().dataDir).mkdirs();
|
||||
|
||||
initSUConfig();
|
||||
|
||||
List<String> ret = Shell.sh("su -v");
|
||||
if (Utils.isValidShellResponse(ret)) {
|
||||
suVersion = ret.get(0);
|
||||
isSuClient = suVersion.toUpperCase().contains("MAGISK");
|
||||
}
|
||||
if (isSuClient) {
|
||||
suAccessState = suDB.getSettings(SuDatabaseHelper.ROOT_ACCESS, 3);
|
||||
multiuserMode = suDB.getSettings(SuDatabaseHelper.MULTIUSER_MODE, 0);
|
||||
suNamespaceMode = suDB.getSettings(SuDatabaseHelper.MNT_NS, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateMagiskInfo() {
|
||||
List<String> ret;
|
||||
ret = Shell.sh("magisk -v");
|
||||
if (!Utils.isValidShellResponse(ret)) {
|
||||
ret = Shell.sh("getprop magisk.version");
|
||||
if (Utils.isValidShellResponse(ret)) {
|
||||
try {
|
||||
magiskVersionString = ret.get(0);
|
||||
magiskVersionCode = (int) Double.parseDouble(ret.get(0)) * 10;
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
} else {
|
||||
magiskVersionString = ret.get(0).split(":")[0];
|
||||
ret = Shell.sh("magisk -V");
|
||||
try {
|
||||
magiskVersionCode = Integer.parseInt(ret.get(0));
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
ret = Shell.sh("getprop " + DISABLE_INDICATION_PROP);
|
||||
try {
|
||||
disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
|
||||
} catch (NumberFormatException e) {
|
||||
disabled = false;
|
||||
}
|
||||
ret = Shell.sh("getprop " + MAGISKHIDE_PROP);
|
||||
try {
|
||||
magiskHide = !Utils.isValidShellResponse(ret) || Integer.parseInt(ret.get(0)) != 0;
|
||||
} catch (NumberFormatException e) {
|
||||
magiskHide = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
@@ -15,23 +14,25 @@ import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class MainActivity extends AppCompatActivity
|
||||
implements NavigationView.OnNavigationItemSelectedListener, CallbackHandler.EventListener {
|
||||
public class MainActivity extends Activity
|
||||
implements NavigationView.OnNavigationItemSelectedListener, CallbackEvent.Listener<Void> {
|
||||
|
||||
private final Handler mDrawerHandler = new Handler();
|
||||
private SharedPreferences prefs;
|
||||
private int mDrawerItem;
|
||||
|
||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||
@BindView(R.id.drawer_layout) DrawerLayout drawer;
|
||||
@@ -42,10 +43,10 @@ public class MainActivity extends AppCompatActivity
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
prefs = getApplicationContext().prefs;
|
||||
|
||||
if (Global.Configs.isDarkTheme) {
|
||||
setTheme(R.style.AppTheme_dh);
|
||||
if (getApplicationContext().isDarkTheme) {
|
||||
setTheme(R.style.AppTheme_Dark);
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
@@ -76,40 +77,35 @@ public class MainActivity extends AppCompatActivity
|
||||
drawer.addDrawerListener(toggle);
|
||||
toggle.syncState();
|
||||
|
||||
navigate(R.id.status);
|
||||
if (savedInstanceState == null)
|
||||
navigate(getIntent().getStringExtra(MagiskManager.INTENT_SECTION));
|
||||
|
||||
navigationView.setNavigationItemSelectedListener(this);
|
||||
CallbackHandler.register(Global.Events.reloadMainActivity, this);
|
||||
getApplicationContext().reloadMainActivity.register(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
CallbackHandler.register(Global.Events.updateCheckDone, this);
|
||||
if (Global.Events.updateCheckDone.isTriggered)
|
||||
onTrigger(Global.Events.updateCheckDone);
|
||||
checkHideSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
CallbackHandler.unRegister(Global.Events.updateCheckDone, this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
CallbackHandler.unRegister(Global.Events.reloadMainActivity, this);
|
||||
getApplicationContext().reloadMainActivity.unRegister(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (drawer.isDrawerOpen(navigationView))
|
||||
if (drawer.isDrawerOpen(navigationView)) {
|
||||
drawer.closeDrawer(navigationView);
|
||||
else
|
||||
} else if (mDrawerItem != R.id.magisk) {
|
||||
navigate(R.id.magisk);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -121,35 +117,65 @@ public class MainActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackHandler.Event event) {
|
||||
if (event == Global.Events.updateCheckDone) {
|
||||
Menu menu = navigationView.getMenu();
|
||||
menu.findItem(R.id.install).setVisible(Global.Info.remoteMagiskVersion > 0 &&
|
||||
Shell.rootAccess());
|
||||
} else if (event == Global.Events.reloadMainActivity) {
|
||||
recreate();
|
||||
}
|
||||
public void onTrigger(CallbackEvent<Void> event) {
|
||||
recreate();
|
||||
}
|
||||
|
||||
private void checkHideSection() {
|
||||
public void checkHideSection() {
|
||||
Menu menu = navigationView.getMenu();
|
||||
if (Shell.rootAccess()) {
|
||||
menu.findItem(R.id.magiskhide).setVisible(
|
||||
Global.Info.magiskVersion >= 8 && prefs.getBoolean("magiskhide", false));
|
||||
menu.findItem(R.id.modules).setVisible(Global.Info.magiskVersion >= 4);
|
||||
menu.findItem(R.id.downloads).setVisible(Global.Info.magiskVersion >= 4);
|
||||
menu.findItem(R.id.log).setVisible(true);
|
||||
menu.findItem(R.id.superuser).setVisible(Global.Info.isSuClient);
|
||||
menu.findItem(R.id.magiskhide).setVisible(
|
||||
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 1300
|
||||
&& prefs.getBoolean("magiskhide", false));
|
||||
menu.findItem(R.id.modules).setVisible(
|
||||
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 0);
|
||||
menu.findItem(R.id.downloads).setVisible(Utils.checkNetworkStatus(this) &&
|
||||
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 0);
|
||||
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
|
||||
menu.findItem(R.id.superuser).setVisible(
|
||||
Shell.rootAccess() && getApplicationContext().isSuClient);
|
||||
}
|
||||
|
||||
public void navigate(String item) {
|
||||
int itemId = R.id.magisk;
|
||||
if (item != null) {
|
||||
switch (item) {
|
||||
case "magisk":
|
||||
case "install":
|
||||
itemId = R.id.magisk;
|
||||
break;
|
||||
case "superuser":
|
||||
itemId = R.id.superuser;
|
||||
break;
|
||||
case "modules":
|
||||
itemId = R.id.modules;
|
||||
break;
|
||||
case "downloads":
|
||||
itemId = R.id.downloads;
|
||||
break;
|
||||
case "magiskhide":
|
||||
itemId = R.id.magiskhide;
|
||||
break;
|
||||
case "log":
|
||||
itemId = R.id.log;
|
||||
break;
|
||||
case "settings":
|
||||
itemId = R.id.settings;
|
||||
break;
|
||||
case "about":
|
||||
itemId = R.id.app_about;
|
||||
break;
|
||||
}
|
||||
}
|
||||
navigate(itemId);
|
||||
}
|
||||
|
||||
public void navigate(int itemId) {
|
||||
int bak = mDrawerItem;
|
||||
mDrawerItem = itemId;
|
||||
navigationView.setCheckedItem(itemId);
|
||||
switch (itemId) {
|
||||
case R.id.status:
|
||||
displayFragment(new StatusFragment(), "status", true);
|
||||
break;
|
||||
case R.id.install:
|
||||
displayFragment(new InstallFragment(), "install", true);
|
||||
case R.id.magisk:
|
||||
displayFragment(new MagiskFragment(), "magisk", true);
|
||||
break;
|
||||
case R.id.superuser:
|
||||
displayFragment(new SuperuserFragment(), "superuser", true);
|
||||
@@ -165,13 +191,14 @@ public class MainActivity extends AppCompatActivity
|
||||
break;
|
||||
case R.id.log:
|
||||
displayFragment(new LogFragment(), "log", false);
|
||||
toolbar.setElevation(0);
|
||||
break;
|
||||
case R.id.settings:
|
||||
startActivity(new Intent(this, SettingsActivity.class));
|
||||
mDrawerItem = bak;
|
||||
break;
|
||||
case R.id.app_about:
|
||||
startActivity(new Intent(this, AboutActivity.class));
|
||||
mDrawerItem = bak;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -182,5 +209,6 @@ public class MainActivity extends AppCompatActivity
|
||||
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
|
||||
transaction.replace(R.id.content_frame, navFragment, tag).commitNow();
|
||||
if (setElevation) toolbar.setElevation(toolbarElevation);
|
||||
else toolbar.setElevation(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -13,12 +13,12 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.clans.fab.FloatingActionButton;
|
||||
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
||||
import com.topjohnwu.magisk.asyncs.FlashZip;
|
||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.module.ModuleHelper;
|
||||
import com.topjohnwu.magisk.utils.Async;
|
||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -28,7 +28,7 @@ import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class ModulesFragment extends Fragment implements CallbackHandler.EventListener {
|
||||
public class ModulesFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
||||
|
||||
private static final int FETCH_ZIP_CODE = 2;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
||||
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
new Async.LoadModules().exec();
|
||||
new LoadModules(getActivity()).exec();
|
||||
});
|
||||
|
||||
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@@ -69,7 +69,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
||||
}
|
||||
});
|
||||
|
||||
if (Global.Events.moduleLoadDone.isTriggered) {
|
||||
if (getApplication().moduleLoadDone.isTriggered) {
|
||||
updateUI();
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackHandler.Event event) {
|
||||
public void onTrigger(CallbackEvent<Void> event) {
|
||||
Logger.dev("ModulesFragment: UI refresh triggered");
|
||||
updateUI();
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
||||
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||
// Get the URI of the selected file
|
||||
final Uri uri = data.getData();
|
||||
new Async.FlashZIP(getActivity(), uri).exec();
|
||||
new FlashZip(getActivity(), uri).exec();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -95,13 +95,13 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
CallbackHandler.register(Global.Events.moduleLoadDone, this);
|
||||
getApplication().moduleLoadDone.register(this);
|
||||
getActivity().setTitle(R.string.modules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
CallbackHandler.unRegister(Global.Events.moduleLoadDone, this);
|
||||
getApplication().moduleLoadDone.unRegister(this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@@ -112,7 +112,8 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
ModuleHelper.getModuleList(listModules);
|
||||
listModules.clear();
|
||||
listModules.addAll(getApplication().moduleMap.values());
|
||||
if (listModules.size() == 0) {
|
||||
emptyRv.setVisibility(View.VISIBLE);
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
@@ -16,10 +15,12 @@ import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||
import com.topjohnwu.magisk.adapters.SimpleSectionedRecyclerViewAdapter;
|
||||
import com.topjohnwu.magisk.module.ModuleHelper;
|
||||
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.utils.Async;
|
||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -29,7 +30,7 @@ import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class ReposFragment extends Fragment implements CallbackHandler.EventListener {
|
||||
public class ReposFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
||||
|
||||
private Unbinder unbinder;
|
||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||
@@ -68,10 +69,10 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
||||
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
new Async.LoadRepos(getActivity()).exec();
|
||||
new LoadRepos(getActivity()).exec();
|
||||
});
|
||||
|
||||
if (Global.Events.repoLoadDone.isTriggered) {
|
||||
if (getApplication().repoLoadDone.isTriggered) {
|
||||
reloadRepos();
|
||||
updateUI();
|
||||
}
|
||||
@@ -93,7 +94,7 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackHandler.Event event) {
|
||||
public void onTrigger(CallbackEvent<Void> event) {
|
||||
Logger.dev("ReposFragment: UI refresh triggered");
|
||||
reloadRepos();
|
||||
updateUI();
|
||||
@@ -109,13 +110,13 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
CallbackHandler.register(Global.Events.repoLoadDone, this);
|
||||
getApplication().repoLoadDone.register(this);
|
||||
getActivity().setTitle(R.string.downloads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
CallbackHandler.unRegister(Global.Events.repoLoadDone, this);
|
||||
getApplication().repoLoadDone.unRegister(this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@@ -126,7 +127,21 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
||||
}
|
||||
|
||||
private void reloadRepos() {
|
||||
ModuleHelper.getRepoLists(mUpdateRepos, mInstalledRepos, mOthersRepos);
|
||||
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();
|
||||
@@ -158,7 +173,7 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
|
||||
private class FilterApps extends Async.NormalTask<String, Void, Void> {
|
||||
private class FilterApps extends ParallelTask<String, Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground(String... strings) {
|
||||
String newText = strings[0];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,24 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.utils.Async;
|
||||
import com.topjohnwu.magisk.asyncs.GetBootBlocks;
|
||||
import com.topjohnwu.magisk.asyncs.LoadApps;
|
||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
public class SplashActivity extends AppCompatActivity {
|
||||
public class SplashActivity extends Activity{
|
||||
|
||||
private static final int UPDATE_SERVICE_ID = 1;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -14,22 +26,32 @@ public class SplashActivity extends AppCompatActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Init the info and configs and root shell
|
||||
Global.init(getApplicationContext());
|
||||
getApplicationContext().init();
|
||||
|
||||
// Now fire all async tasks
|
||||
new Async.CheckUpdates().exec();
|
||||
new Async.GetBootBlocks().exec();
|
||||
new Async.LoadModules() {
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
super.onPostExecute(v);
|
||||
new Async.LoadRepos(getApplicationContext()).exec();
|
||||
}
|
||||
}.exec();
|
||||
new Async.LoadApps(getPackageManager()).exec();
|
||||
new GetBootBlocks(this).exec();
|
||||
new LoadModules(this).setCallBack(() -> new LoadRepos(this).exec()).exec();
|
||||
new LoadApps(this).exec();
|
||||
|
||||
// Preparation done, now start main activity
|
||||
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
|
||||
if (Utils.checkNetworkStatus(this)) {
|
||||
// Initialize the update check service, notify every 8 hours
|
||||
if (!TextUtils.equals("install", getIntent().getStringExtra(MagiskManager.INTENT_SECTION))) {
|
||||
ComponentName service = new ComponentName(this, UpdateCheckService.class);
|
||||
JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service)
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
||||
.setPersisted(true)
|
||||
.setPeriodic(8 * 60 * 60 * 1000)
|
||||
.build();
|
||||
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
scheduler.schedule(jobInfo);
|
||||
}
|
||||
}
|
||||
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION);
|
||||
if (section != null) {
|
||||
intent.putExtra(MagiskManager.INTENT_SECTION, section);
|
||||
}
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -13,7 +12,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.SuLogAdapter;
|
||||
import com.topjohnwu.magisk.superuser.SuLogDatabaseHelper;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||
|
||||
import java.util.List;
|
||||
@@ -28,7 +27,7 @@ public class SuLogFragment extends Fragment {
|
||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||
|
||||
private Unbinder unbinder;
|
||||
private SuLogDatabaseHelper dbHelper;
|
||||
private MagiskManager magiskManager;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
@@ -48,8 +47,7 @@ public class SuLogFragment extends Fragment {
|
||||
// Inflate the layout for this fragment
|
||||
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
||||
unbinder = ButterKnife.bind(this, v);
|
||||
|
||||
dbHelper = new SuLogDatabaseHelper(getActivity());
|
||||
magiskManager = getApplication();
|
||||
|
||||
updateList();
|
||||
|
||||
@@ -57,7 +55,7 @@ public class SuLogFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
List<SuLogEntry> logs = dbHelper.getLogList();
|
||||
List<SuLogEntry> logs = magiskManager.suDB.getLogList();
|
||||
|
||||
if (logs.size() == 0) {
|
||||
emptyRv.setVisibility(View.VISIBLE);
|
||||
@@ -76,7 +74,7 @@ public class SuLogFragment extends Fragment {
|
||||
updateList();
|
||||
return true;
|
||||
case R.id.menu_clear:
|
||||
dbHelper.clearLogs();
|
||||
magiskManager.suDB.clearLogs();
|
||||
updateList();
|
||||
return true;
|
||||
default:
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -11,8 +10,8 @@ import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.superuser.Policy;
|
||||
import com.topjohnwu.magisk.superuser.SuDatabaseHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -33,15 +32,15 @@ public class SuperuserFragment extends Fragment {
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
PackageManager pm = getActivity().getPackageManager();
|
||||
MagiskManager magiskManager = getApplication();
|
||||
|
||||
SuDatabaseHelper dbHelper = new SuDatabaseHelper(getActivity());
|
||||
List<Policy> policyList = dbHelper.getPolicyList(pm);
|
||||
List<Policy> policyList = magiskManager.suDB.getPolicyList(pm);
|
||||
|
||||
if (policyList.size() == 0) {
|
||||
emptyRv.setVisibility(View.VISIBLE);
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
} else {
|
||||
recyclerView.setAdapter(new PolicyAdapter(policyList, dbHelper, pm));
|
||||
recyclerView.setAdapter(new PolicyAdapter(policyList, magiskManager.suDB, pm));
|
||||
emptyRv.setVisibility(View.GONE);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.Async;
|
||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -50,8 +51,8 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
||||
}
|
||||
|
||||
public void setLists(List<ApplicationInfo> listApps, List<String> hideList) {
|
||||
mOriginalList = mList = Collections.unmodifiableList(listApps);
|
||||
mHideList = new ArrayList<>(hideList);
|
||||
mOriginalList = mList = listApps;
|
||||
mHideList = hideList;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@@ -76,20 +77,19 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
||||
if (SNLIST.contains(info.packageName)) {
|
||||
holder.checkBox.setChecked(true);
|
||||
holder.checkBox.setEnabled(false);
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
Snackbar snackbar = Snackbar.make(holder.itemView, R.string.safetyNet_hide_notice, Snackbar.LENGTH_LONG);
|
||||
((TextView) snackbar.getView().findViewById(android.support.design.R.id.snackbar_text)).setMaxLines(2);
|
||||
snackbar.show();
|
||||
});
|
||||
holder.itemView.setOnClickListener(v ->
|
||||
SnackbarMaker.make(holder.itemView,
|
||||
R.string.safetyNet_hide_notice, Snackbar.LENGTH_LONG).show()
|
||||
);
|
||||
} else {
|
||||
holder.checkBox.setEnabled(true);
|
||||
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||
if (isChecked) {
|
||||
new Async.MagiskHide().add(info.packageName);
|
||||
new MagiskHide().add(info.packageName);
|
||||
mHideList.add(info.packageName);
|
||||
} else {
|
||||
new Async.MagiskHide().rm(info.packageName);
|
||||
new MagiskHide().rm(info.packageName);
|
||||
mHideList.remove(info.packageName);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -12,8 +12,8 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.utils.Async;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
|
||||
import java.util.List;
|
||||
@@ -52,44 +52,31 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
||||
|
||||
holder.checkBox.setOnCheckedChangeListener(null);
|
||||
holder.checkBox.setChecked(module.isEnabled());
|
||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> new Async.RootTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
if (isChecked) {
|
||||
module.removeDisableFile();
|
||||
} else {
|
||||
module.createDisableFile();
|
||||
}
|
||||
return null;
|
||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||
int snack;
|
||||
if (isChecked) {
|
||||
module.removeDisableFile();
|
||||
snack = R.string.disable_file_removed;
|
||||
} else {
|
||||
module.createDisableFile();
|
||||
snack = R.string.disable_file_created;
|
||||
}
|
||||
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||
});
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
int snack = isChecked ? R.string.disable_file_removed : R.string.disable_file_created;
|
||||
Snackbar.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||
holder.delete.setOnClickListener(v -> {
|
||||
boolean removed = module.willBeRemoved();
|
||||
int snack;
|
||||
if (removed) {
|
||||
module.deleteRemoveFile();
|
||||
snack = R.string.remove_file_deleted;
|
||||
} else {
|
||||
module.createRemoveFile();
|
||||
snack = R.string.remove_file_created;
|
||||
}
|
||||
}.exec());
|
||||
|
||||
holder.delete.setOnClickListener(v -> new Async.RootTask<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;
|
||||
Snackbar.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||
updateDeleteButton(holder, module);
|
||||
}
|
||||
}.exec());
|
||||
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||
updateDeleteButton(holder, module);
|
||||
});
|
||||
|
||||
if (module.isUpdated()) {
|
||||
holder.notice.setVisibility(View.VISIBLE);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +1,26 @@
|
||||
package com.topjohnwu.magisk.adapters;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
import com.topjohnwu.magisk.components.MarkDownWindow;
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.receivers.RepoDlReceiver;
|
||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.WebWindow;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
@@ -32,7 +28,7 @@ import butterknife.ButterKnife;
|
||||
public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> {
|
||||
|
||||
private List<Repo> mUpdateRepos, mInstalledRepos, mOthersRepos;
|
||||
private Set<Repo> expandList = new HashSet<>();
|
||||
private Context mContext;
|
||||
|
||||
public ReposAdapter(List<Repo> update, List<Repo> installed, List<Repo> others) {
|
||||
mUpdateRepos = update;
|
||||
@@ -42,61 +38,54 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false);
|
||||
mContext = parent.getContext();
|
||||
View v = LayoutInflater.from(mContext).inflate(R.layout.list_item_repo, parent, false);
|
||||
return new ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
Context context = holder.itemView.getContext();
|
||||
Repo repo = getItem(position);
|
||||
|
||||
holder.title.setText(repo.getName());
|
||||
holder.versionName.setText(repo.getVersion());
|
||||
String author = repo.getAuthor();
|
||||
holder.author.setText(TextUtils.isEmpty(author) ? null : context.getString(R.string.author, author));
|
||||
holder.author.setText(TextUtils.isEmpty(author) ? null : mContext.getString(R.string.author, author));
|
||||
holder.description.setText(repo.getDescription());
|
||||
|
||||
holder.setExpanded(expandList.contains(repo));
|
||||
holder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), mContext));
|
||||
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
if (holder.mExpanded) {
|
||||
holder.collapse();
|
||||
expandList.remove(repo);
|
||||
} else {
|
||||
holder.expand();
|
||||
expandList.add(repo);
|
||||
}
|
||||
});
|
||||
holder.changeLog.setOnClickListener(view -> {
|
||||
if (!TextUtils.isEmpty(repo.getLogUrl())) {
|
||||
new WebWindow(context.getString(R.string.changelog), repo.getLogUrl(), context);
|
||||
}
|
||||
});
|
||||
holder.updateImage.setOnClickListener(view -> {
|
||||
holder.downloadImage.setOnClickListener(v -> {
|
||||
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
|
||||
Utils.getAlertDialogBuilder(context)
|
||||
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
|
||||
.setMessage(context.getString(R.string.repo_install_msg, filename))
|
||||
new AlertDialogBuilder(mContext)
|
||||
.setTitle(mContext.getString(R.string.repo_install_title, repo.getName()))
|
||||
.setMessage(mContext.getString(R.string.repo_install_msg, filename))
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive(
|
||||
context,
|
||||
new RepoDlReceiver(),
|
||||
.setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive(
|
||||
mContext,
|
||||
new DownloadReceiver() {
|
||||
@Override
|
||||
public void onDownloadDone(Uri uri) {
|
||||
Activity activity = (Activity) mContext;
|
||||
new ProcessRepoZip(activity, uri, true).exec();
|
||||
}
|
||||
},
|
||||
repo.getZipUrl(),
|
||||
Utils.getLegalFilename(filename)))
|
||||
.setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive(
|
||||
mContext,
|
||||
new DownloadReceiver() {
|
||||
@Override
|
||||
public void onDownloadDone(Uri uri) {
|
||||
Activity activity = (Activity) mContext;
|
||||
new ProcessRepoZip(activity, uri, false).exec();
|
||||
}
|
||||
},
|
||||
repo.getZipUrl(),
|
||||
Utils.getLegalFilename(filename)))
|
||||
.setNegativeButton(R.string.no_thanks, null)
|
||||
.show();
|
||||
});
|
||||
holder.authorLink.setOnClickListener(view -> {
|
||||
if (!TextUtils.isEmpty(repo.getDonateUrl())) {
|
||||
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(repo.getDonateUrl())));
|
||||
}
|
||||
});
|
||||
holder.supportLink.setOnClickListener(view -> {
|
||||
if (!TextUtils.isEmpty(repo.getSupportUrl())) {
|
||||
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(repo.getSupportUrl())));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,97 +113,12 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
|
||||
@BindView(R.id.version_name) TextView versionName;
|
||||
@BindView(R.id.description) TextView description;
|
||||
@BindView(R.id.author) TextView author;
|
||||
@BindView(R.id.expand_layout) LinearLayout expandLayout;
|
||||
@BindView(R.id.update) ImageView updateImage;
|
||||
@BindView(R.id.changeLog) ImageView changeLog;
|
||||
@BindView(R.id.authorLink) ImageView authorLink;
|
||||
@BindView(R.id.supportLink) ImageView supportLink;
|
||||
|
||||
private ValueAnimator mAnimator;
|
||||
private ObjectAnimator animY2;
|
||||
private boolean mExpanded = false;
|
||||
private static int expandHeight = 0;
|
||||
@BindView(R.id.info_layout) LinearLayout infoLayout;
|
||||
@BindView(R.id.download) ImageView downloadImage;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
expandLayout.getViewTreeObserver().addOnPreDrawListener(
|
||||
new ViewTreeObserver.OnPreDrawListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
if (expandHeight == 0) {
|
||||
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
expandLayout.measure(widthSpec, heightSpec);
|
||||
expandHeight = expandLayout.getMeasuredHeight();
|
||||
}
|
||||
|
||||
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
expandLayout.setVisibility(View.GONE);
|
||||
mAnimator = slideAnimator(0, expandHeight);
|
||||
animY2 = ObjectAnimator.ofFloat(updateImage, "translationY", expandHeight / 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void setExpanded(boolean expanded) {
|
||||
mExpanded = expanded;
|
||||
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
|
||||
layoutParams.height = expanded ? expandHeight : 0;
|
||||
expandLayout.setLayoutParams(layoutParams);
|
||||
expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
|
||||
if (expanded) {
|
||||
updateImage.setTranslationY(expandHeight / 2);
|
||||
} else {
|
||||
updateImage.setTranslationY(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void expand() {
|
||||
expandLayout.setVisibility(View.VISIBLE);
|
||||
mAnimator.start();
|
||||
animY2.start();
|
||||
mExpanded = true;
|
||||
}
|
||||
|
||||
private void collapse() {
|
||||
if (!mExpanded) return;
|
||||
int finalHeight = expandLayout.getHeight();
|
||||
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
|
||||
mAnimator.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
expandLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animator) {}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animator) {}
|
||||
});
|
||||
mAnimator.start();
|
||||
animY2.reverse();
|
||||
mExpanded = false;
|
||||
}
|
||||
|
||||
private ValueAnimator slideAnimator(int start, int end) {
|
||||
|
||||
ValueAnimator animator = ValueAnimator.ofInt(start, end);
|
||||
|
||||
animator.addUpdateListener(valueAnimator -> {
|
||||
int value = (Integer) valueAnimator.getAnimatedValue();
|
||||
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
|
||||
layoutParams.height = value;
|
||||
expandLayout.setLayoutParams(layoutParams);
|
||||
});
|
||||
return animator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
package com.topjohnwu.magisk.adapters;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.RotateAnimation;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.thoughtbot.expandablerecyclerview.ExpandableRecyclerViewAdapter;
|
||||
@@ -19,6 +15,7 @@ import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;
|
||||
import com.thoughtbot.expandablerecyclerview.viewholders.ChildViewHolder;
|
||||
import com.thoughtbot.expandablerecyclerview.viewholders.GroupViewHolder;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.components.ExpandableViewHolder;
|
||||
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -90,7 +87,7 @@ public class SuLogAdapter {
|
||||
SuLogEntry logEntry = (SuLogEntry) group.getItems().get(childIndex);
|
||||
holder.setExpanded(expandList.contains(logEntry));
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
if (holder.mExpanded) {
|
||||
if (holder.getExpanded()) {
|
||||
holder.collapse();
|
||||
expandList.remove(logEntry);
|
||||
} else {
|
||||
@@ -109,7 +106,9 @@ public class SuLogAdapter {
|
||||
@Override
|
||||
public void onBindGroupViewHolder(LogGroupViewHolder holder, int flatPosition, ExpandableGroup group) {
|
||||
holder.date.setText(group.getTitle());
|
||||
if (isGroupExpanded(flatPosition)) holder.expand();
|
||||
if (isGroupExpanded(flatPosition)) {
|
||||
holder.expand();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,92 +147,50 @@ public class SuLogAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper class
|
||||
static class LogViewHolder extends ChildViewHolder {
|
||||
|
||||
private InternalViewHolder expandableViewHolder;
|
||||
|
||||
@BindView(R.id.app_name) TextView appName;
|
||||
@BindView(R.id.action) TextView action;
|
||||
@BindView(R.id.time) TextView time;
|
||||
@BindView(R.id.fromPid) TextView fromPid;
|
||||
@BindView(R.id.toUid) TextView toUid;
|
||||
@BindView(R.id.command) TextView command;
|
||||
@BindView(R.id.expand_layout) LinearLayout expandLayout;
|
||||
|
||||
private ValueAnimator mAnimator;
|
||||
private boolean mExpanded = false;
|
||||
private static int expandHeight = 0;
|
||||
|
||||
public LogViewHolder(View itemView) {
|
||||
LogViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
expandLayout.getViewTreeObserver().addOnPreDrawListener(
|
||||
new ViewTreeObserver.OnPreDrawListener() {
|
||||
expandableViewHolder = new InternalViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
if (expandHeight == 0) {
|
||||
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
expandLayout.measure(widthSpec, heightSpec);
|
||||
expandHeight = expandLayout.getMeasuredHeight();
|
||||
}
|
||||
private class InternalViewHolder extends ExpandableViewHolder {
|
||||
|
||||
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
expandLayout.setVisibility(View.GONE);
|
||||
mAnimator = slideAnimator(0, expandHeight);
|
||||
return true;
|
||||
}
|
||||
InternalViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
});
|
||||
@Override
|
||||
public void setExpandLayout(View itemView) {
|
||||
expandLayout = itemView.findViewById(R.id.expand_layout);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getExpanded() {
|
||||
return expandableViewHolder.mExpanded;
|
||||
}
|
||||
|
||||
private void setExpanded(boolean expanded) {
|
||||
mExpanded = expanded;
|
||||
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
|
||||
layoutParams.height = expanded ? expandHeight : 0;
|
||||
expandLayout.setLayoutParams(layoutParams);
|
||||
expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
|
||||
expandableViewHolder.setExpanded(expanded);
|
||||
}
|
||||
|
||||
private void expand() {
|
||||
expandLayout.setVisibility(View.VISIBLE);
|
||||
mAnimator.start();
|
||||
mExpanded = true;
|
||||
expandableViewHolder.expand();
|
||||
}
|
||||
|
||||
private void collapse() {
|
||||
if (!mExpanded) return;
|
||||
int finalHeight = expandLayout.getHeight();
|
||||
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
|
||||
mAnimator.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
expandLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animator) {}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animator) {}
|
||||
});
|
||||
mAnimator.start();
|
||||
mExpanded = false;
|
||||
}
|
||||
|
||||
private ValueAnimator slideAnimator(int start, int end) {
|
||||
|
||||
ValueAnimator animator = ValueAnimator.ofInt(start, end);
|
||||
|
||||
animator.addUpdateListener(valueAnimator -> {
|
||||
int value = (Integer) valueAnimator.getAnimatedValue();
|
||||
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
|
||||
layoutParams.height = value;
|
||||
expandLayout.setLayoutParams(layoutParams);
|
||||
});
|
||||
return animator;
|
||||
expandableViewHolder.collapse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.topjohnwu.magisk.BuildConfig;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
private static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/magisk_update.json";
|
||||
|
||||
|
||||
private boolean showNotification = false;
|
||||
|
||||
public CheckUpdates(Context context, boolean b) {
|
||||
this(context);
|
||||
showNotification = b;
|
||||
}
|
||||
|
||||
public CheckUpdates(Context context) {
|
||||
magiskManager = Utils.getMagiskManager(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
String jsonStr = WebService.request(UPDATE_JSON, WebService.GET);
|
||||
try {
|
||||
JSONObject json = new JSONObject(jsonStr);
|
||||
JSONObject magisk = json.getJSONObject("magisk");
|
||||
magiskManager.remoteMagiskVersionString = magisk.getString("version");
|
||||
magiskManager.remoteMagiskVersionCode = magisk.getInt("versionCode");
|
||||
magiskManager.magiskLink = magisk.getString("link");
|
||||
magiskManager.releaseNoteLink = magisk.getString("note");
|
||||
JSONObject manager = json.getJSONObject("app");
|
||||
magiskManager.remoteManagerVersionString = manager.getString("version");
|
||||
magiskManager.remoteManagerVersionCode = manager.getInt("versionCode");
|
||||
magiskManager.managerLink = manager.getString("link");
|
||||
} catch (JSONException ignored) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
if (showNotification && magiskManager.updateNotification) {
|
||||
if (magiskManager.magiskVersionCode < magiskManager.remoteMagiskVersionCode) {
|
||||
Utils.showMagiskUpdate(magiskManager);
|
||||
}
|
||||
if (BuildConfig.VERSION_CODE < magiskManager.remoteManagerVersionCode) {
|
||||
Utils.showManagerUpdate(magiskManager);
|
||||
}
|
||||
}
|
||||
magiskManager.updateCheckDone.trigger();
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user