mirror of
https://github.com/topjohnwu/Magisk
synced 2025-11-10 02:12:30 +01:00
Compare commits
61 Commits
manager-v4
...
manager-v4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -8,8 +8,8 @@ android {
|
|||||||
applicationId "com.topjohnwu.magisk"
|
applicationId "com.topjohnwu.magisk"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 20
|
versionCode 28
|
||||||
versionName "4.0"
|
versionName "4.3.1"
|
||||||
jackOptions {
|
jackOptions {
|
||||||
enabled true
|
enabled true
|
||||||
jackInProcess true
|
jackInProcess true
|
||||||
@@ -47,15 +47,14 @@ repositories {
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
|
||||||
compile 'com.android.support:recyclerview-v7:25.1.1'
|
compile 'com.android.support:recyclerview-v7:25.3.1'
|
||||||
compile 'com.android.support:cardview-v7:25.1.1'
|
compile 'com.android.support:cardview-v7:25.3.1'
|
||||||
compile 'com.android.support:design:25.1.1'
|
compile 'com.android.support:design:25.3.1'
|
||||||
compile 'com.android.support:support-v4:25.1.1'
|
compile 'com.android.support:support-v4:25.3.1'
|
||||||
compile 'com.android.support:support-v13:25.1.1'
|
|
||||||
compile 'com.jakewharton:butterknife:8.5.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.github.clans:fab:1.6.4'
|
||||||
compile 'com.thoughtbot:expandablerecyclerview:1.4'
|
compile 'com.thoughtbot:expandablerecyclerview:1.4'
|
||||||
|
compile 'us.feras.mdv:markdownview:1.1.0'
|
||||||
compile 'com.madgag.spongycastle:core:1.54.0.0'
|
compile 'com.madgag.spongycastle:core:1.54.0.0'
|
||||||
compile 'com.madgag.spongycastle:prov: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:pkix:1.54.0.0'
|
||||||
|
|||||||
21
app/proguard-rules.pro
vendored
21
app/proguard-rules.pro
vendored
@@ -16,27 +16,6 @@
|
|||||||
# public *;
|
# 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 class android.support.v7.internal.** { *; }
|
||||||
-keep interface android.support.v7.internal.** { *; }
|
-keep interface android.support.v7.internal.** { *; }
|
||||||
-keep class android.support.v7.** { *; }
|
-keep class android.support.v7.** { *; }
|
||||||
|
|||||||
@@ -8,8 +8,10 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name=".MagiskManager"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
@@ -59,6 +61,13 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<service android:name=".services.BootupIntentService" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".services.UpdateCheckService"
|
||||||
|
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||||
|
android:exported="true" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="android.support.v4.content.FileProvider"
|
android:name="android.support.v4.content.FileProvider"
|
||||||
android:authorities="com.topjohnwu.magisk.provider"
|
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
@@ -1,21 +1,20 @@
|
|||||||
#!/system/bin/sh
|
|
||||||
|
|
||||||
[ -z $BOOTMODE ] && BOOTMODE=false
|
[ -z $BOOTMODE ] && BOOTMODE=false
|
||||||
TMPDIR=/tmp
|
|
||||||
($BOOTMODE) && TMPDIR=/dev/tmp
|
|
||||||
|
|
||||||
BINDIR=/data/magisk
|
# This path should work in any cases
|
||||||
CHROMEDIR=$BINDIR/chromeos
|
TMPDIR=/dev/tmp
|
||||||
|
|
||||||
NEWBOOT=$TMPDIR/boottmp/new-boot.img
|
BOOTTMP=$TMPDIR/boottmp
|
||||||
UNPACKDIR=$TMPDIR/boottmp/bootunpack
|
MAGISKBIN=/data/magisk
|
||||||
RAMDISK=$TMPDIR/boottmp/ramdisk
|
CHROMEDIR=$MAGISKBIN/chromeos
|
||||||
|
|
||||||
SYSTEMLIB=/system/lib
|
SYSTEMLIB=/system/lib
|
||||||
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64
|
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64
|
||||||
|
|
||||||
ui_print() {
|
# Default permissions
|
||||||
echo "$1"
|
umask 022
|
||||||
|
|
||||||
|
ui_print_wrapper() {
|
||||||
|
type ui_print >/dev/null && ui_print "$1" || echo "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
grep_prop() {
|
grep_prop() {
|
||||||
@@ -25,7 +24,7 @@ grep_prop() {
|
|||||||
if [ -z "$FILES" ]; then
|
if [ -z "$FILES" ]; then
|
||||||
FILES='/system/build.prop'
|
FILES='/system/build.prop'
|
||||||
fi
|
fi
|
||||||
cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1
|
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
|
||||||
}
|
}
|
||||||
|
|
||||||
find_boot_image() {
|
find_boot_image() {
|
||||||
@@ -42,109 +41,93 @@ find_boot_image() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
unpack_boot() {
|
# Environments
|
||||||
rm -rf $UNPACKDIR $RAMDISK 2>/dev/null
|
|
||||||
mkdir -p $UNPACKDIR
|
|
||||||
mkdir -p $RAMDISK
|
|
||||||
cd $UNPACKDIR
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/bootimgtools --extract $1
|
|
||||||
|
|
||||||
cd $RAMDISK
|
|
||||||
$BINDIR/busybox gunzip -c < $UNPACKDIR/ramdisk.gz | cpio -i
|
|
||||||
}
|
|
||||||
|
|
||||||
repack_boot() {
|
|
||||||
cd $RAMDISK
|
|
||||||
find . | cpio -o -H newc 2>/dev/null | gzip -9 > $UNPACKDIR/ramdisk.gz
|
|
||||||
cd $UNPACKDIR
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/bootimgtools --repack $BOOTIMAGE
|
|
||||||
if [ -f chromeos ]; then
|
|
||||||
echo " " > config
|
|
||||||
echo " " > bootloader
|
|
||||||
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz new-boot.img --config config --arch arm --bootloader bootloader --flags 0x1
|
|
||||||
rm -f new-boot.img
|
|
||||||
mv new-boot.img.signed new-boot.img
|
|
||||||
fi
|
|
||||||
if ($SAMSUNG); then
|
|
||||||
SAMSUNG_CHECK=$(cat new-boot.img | grep SEANDROIDENFORCE)
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -n "SEANDROIDENFORCE" >> new-boot.img
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if ($LGE_G); then
|
|
||||||
# Prevent secure boot error on LG G2/G3.
|
|
||||||
# Just for know, It's a pattern which bootloader verifies at boot. Thanks to LG hackers.
|
|
||||||
echo -n -e "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79" >> new-boot.img
|
|
||||||
fi
|
|
||||||
mv new-boot.img $NEWBOOT
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set permissions
|
# Set permissions
|
||||||
chmod -R 755 $CHROMEDIR/futility $BINDIR
|
chmod -R 755 $CHROMEDIR/futility $MAGISKBIN 2>/dev/null
|
||||||
|
# Temporary busybox for installation
|
||||||
|
mkdir -p $TMPDIR/busybox
|
||||||
|
$MAGISKBIN/busybox --install -s $TMPDIR/busybox
|
||||||
|
rm -f $TMPDIR/busybox/su $TMPDIR/busybox/sh $TMPDIR/busybox/reboot
|
||||||
|
PATH=$TMPDIR/busybox:$PATH
|
||||||
|
|
||||||
# Find the boot image
|
# Find the boot image
|
||||||
find_boot_image
|
find_boot_image
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
if [ -z "$BOOTIMAGE" ]; then
|
||||||
ui_print "! Unable to detect boot image"
|
ui_print_wrapper "! Unable to detect boot image"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ui_print "- Found Boot Image: $BOOTIMAGE"
|
ui_print_wrapper "- Found Boot Image: $BOOTIMAGE"
|
||||||
|
|
||||||
# Detect special vendors
|
rm -rf $BOOTTMP 2>/dev/null
|
||||||
SAMSUNG=false
|
mkdir -p $BOOTTMP
|
||||||
SAMSUNG_CHECK=$(cat /system/build.prop | grep "ro.build.fingerprint=" | grep -i "samsung")
|
cd $BOOTTMP
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
SAMSUNG=true
|
ui_print_wrapper "- Unpacking boot image"
|
||||||
fi
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --unpack $BOOTIMAGE
|
||||||
LGE_G=false
|
if [ $? -ne 0 ]; then
|
||||||
RBRAND=$(grep_prop ro.product.brand)
|
ui_print_wrapper "! Unable to unpack boot image"
|
||||||
RMODEL=$(grep_prop ro.product.device)
|
exit 1
|
||||||
if [ "$RBRAND" = "lge" ] || [ "$RBRAND" = "LGE" ]; then
|
|
||||||
if [ "$RMODEL" = "*D80*" ] ||
|
|
||||||
[ "$RMODEL" = "*S98*" ] ||
|
|
||||||
[ "$RMODEL" = "*D85*" ] ||
|
|
||||||
[ "$RMODEL" = "*F40*" ]; then
|
|
||||||
LGE_G=true
|
|
||||||
ui_print "! Bump device detected"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# First unpack the boot image
|
# Update our previous backup to new format if exists
|
||||||
unpack_boot $BOOTIMAGE
|
if [ -f /data/stock_boot.img ]; then
|
||||||
|
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --sha1 /data/stock_boot.img | tail -n 1`
|
||||||
|
STOCKDUMP=/data/stock_boot_${SHA1}.img
|
||||||
|
mv /data/stock_boot.img $STOCKDUMP
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --compress $STOCKDUMP
|
||||||
|
fi
|
||||||
|
|
||||||
SUPERSU=false
|
# Detect boot image state
|
||||||
[ -f sbin/launch_daemonsu.sh ] && SUPERSU=true
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-test ramdisk.cpio
|
||||||
|
case $? in
|
||||||
if ($SUPERSU); then
|
0 )
|
||||||
ui_print "- SuperSU patched image detected"
|
ui_print_wrapper "! Magisk is not installed!"
|
||||||
rm -f magisk sbin/init.magisk.rc sbin/magic_mask.sh
|
ui_print_wrapper "! Nothing to uninstall"
|
||||||
repack_boot
|
exit
|
||||||
else
|
;;
|
||||||
if [ -f /data/stock_boot.img ]; then
|
1 )
|
||||||
ui_print "- Boot image backup found!"
|
# Find SHA1 of stock boot image
|
||||||
NEWBOOT=/data/stock_boot.img
|
if [ -z $SHA1 ]; then
|
||||||
else
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc
|
||||||
ui_print "! Boot image backup unavailable"
|
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc`
|
||||||
if [ -d ".backup" ]; then
|
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
|
||||||
ui_print "- Restoring ramdisk with backup"
|
rm -f init.magisk.rc
|
||||||
cp -af .backup/. .
|
|
||||||
fi
|
fi
|
||||||
rm -f magisk sbin/init.magisk.rc sbin/magic_mask.sh
|
if [ -f ${STOCKDUMP}.gz ]; then
|
||||||
repack_boot
|
ui_print_wrapper "- Boot image backup found!"
|
||||||
fi
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
|
||||||
|
else
|
||||||
|
ui_print_wrapper "! Boot image backup unavailable"
|
||||||
|
ui_print_wrapper "- Restoring ramdisk with backup"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
2 )
|
||||||
|
ui_print_wrapper "- SuperSU patched image detected"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Sign chromeos boot
|
||||||
|
if [ -f chromeos ]; then
|
||||||
|
echo > config
|
||||||
|
echo > bootloader
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack stock_boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz stock_boot.img --config config --arch arm --bootloader bootloader --flags 0x1
|
||||||
|
rm -f stock_boot.img
|
||||||
|
mv stock_boot.img.signed stock_boot.img
|
||||||
fi
|
fi
|
||||||
|
|
||||||
chmod 644 $NEWBOOT
|
ui_print_wrapper "- Flashing stock/reverted image"
|
||||||
|
|
||||||
ui_print "- Flashing stock/reverted image"
|
|
||||||
[ ! -L "$BOOTIMAGE" ] && dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
|
[ ! -L "$BOOTIMAGE" ] && dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
|
||||||
dd if=$NEWBOOT of=$BOOTIMAGE bs=4096
|
dd if=stock_boot.img of=$BOOTIMAGE bs=4096
|
||||||
|
|
||||||
ui_print "- Removing Magisk files"
|
ui_print_wrapper "- Removing Magisk files"
|
||||||
rm -rf /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \
|
rm -rf /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \
|
||||||
/cache/magisk /cache/magisk_merge /cache/magisk_mount /cache/unblock /cache/magisk_uninstaller.sh \
|
/cache/magisk /cache/magisk_merge /cache/magisk_mount /cache/unblock /cache/magisk_uninstaller.sh \
|
||||||
/data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img \
|
/data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img \
|
||||||
/data/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null
|
/data/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null
|
||||||
|
|
||||||
($BOOTMODE) && reboot
|
$BOOTMODE && reboot
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 73 KiB |
@@ -1,13 +1,12 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
@@ -17,8 +16,10 @@ import android.view.View;
|
|||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||||
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -26,7 +27,7 @@ import java.io.InputStream;
|
|||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
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 = "http://topjohnwu.github.io/donate";
|
||||||
private static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
|
private static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
|
||||||
@@ -46,8 +47,8 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
String theme = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("theme", "");
|
String theme = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("theme", "");
|
||||||
Logger.dev("AboutActivity: Theme is " + theme);
|
Logger.dev("AboutActivity: Theme is " + theme);
|
||||||
if (Global.Configs.isDarkTheme) {
|
if (getApplicationContext().isDarkTheme) {
|
||||||
setTheme(R.style.AppTheme_dh);
|
setTheme(R.style.AppTheme_Dark);
|
||||||
}
|
}
|
||||||
setContentView(R.layout.activity_about);
|
setContentView(R.layout.activity_about);
|
||||||
ButterKnife.bind(this);
|
ButterKnife.bind(this);
|
||||||
@@ -85,7 +86,7 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
result = Html.fromHtml(changes);
|
result = Html.fromHtml(changes);
|
||||||
}
|
}
|
||||||
appChangelog.setOnClickListener(v -> {
|
appChangelog.setOnClickListener(v -> {
|
||||||
AlertDialog d = Utils.getAlertDialogBuilder(this)
|
AlertDialog d = new AlertDialogBuilder(this)
|
||||||
.setTitle(R.string.app_changelog)
|
.setTitle(R.string.app_changelog)
|
||||||
.setMessage(result)
|
.setMessage(result)
|
||||||
.setPositiveButton(android.R.string.ok, null)
|
.setPositiveButton(android.R.string.ok, null)
|
||||||
@@ -104,7 +105,7 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
} else {
|
} else {
|
||||||
result = Html.fromHtml(getString(R.string.app_developers_));
|
result = Html.fromHtml(getString(R.string.app_developers_));
|
||||||
}
|
}
|
||||||
AlertDialog d = Utils.getAlertDialogBuilder(this)
|
AlertDialog d = new AlertDialogBuilder(this)
|
||||||
.setTitle(R.string.app_developers)
|
.setTitle(R.string.app_developers)
|
||||||
.setMessage(result)
|
.setMessage(result)
|
||||||
.setPositiveButton(android.R.string.ok, null)
|
.setPositiveButton(android.R.string.ok, null)
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,13 @@ package com.topjohnwu.magisk;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.TabLayout;
|
import android.support.design.widget.TabLayout;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.view.ViewPager;
|
import android.support.v4.view.ViewPager;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.TabFragmentAdapter;
|
import com.topjohnwu.magisk.adapters.TabFragmentAdapter;
|
||||||
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@@ -33,7 +33,7 @@ public class LogFragment extends Fragment {
|
|||||||
|
|
||||||
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
||||||
|
|
||||||
if (Global.Info.isSuClient) {
|
if (getApplication().isSuClient) {
|
||||||
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
|
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
|
||||||
tab.setupWithViewPager(viewPager);
|
tab.setupWithViewPager(viewPager);
|
||||||
tab.setVisibility(View.VISIBLE);
|
tab.setVisibility(View.VISIBLE);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.view.MenuItemCompat;
|
import android.support.v4.view.MenuItemCompat;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
@@ -16,15 +15,16 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.SearchView;
|
import android.widget.SearchView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
|
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import butterknife.Unbinder;
|
import butterknife.Unbinder;
|
||||||
|
|
||||||
public class MagiskHideFragment extends Fragment implements CallbackHandler.EventListener {
|
public class MagiskHideFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||||
@@ -50,7 +50,7 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
|||||||
PackageManager packageManager = getActivity().getPackageManager();
|
PackageManager packageManager = getActivity().getPackageManager();
|
||||||
|
|
||||||
mSwipeRefreshLayout.setRefreshing(true);
|
mSwipeRefreshLayout.setRefreshing(true);
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> new Async.LoadApps(packageManager).exec());
|
mSwipeRefreshLayout.setOnRefreshListener(() -> new MagiskHide(getActivity()).list());
|
||||||
|
|
||||||
appAdapter = new ApplicationAdapter(packageManager);
|
appAdapter = new ApplicationAdapter(packageManager);
|
||||||
recyclerView.setAdapter(appAdapter);
|
recyclerView.setAdapter(appAdapter);
|
||||||
@@ -71,6 +71,10 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (getApplication().magiskHideDone.isTriggered) {
|
||||||
|
onTrigger(getApplication().magiskHideDone);
|
||||||
|
}
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,15 +89,12 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
getActivity().setTitle(R.string.magiskhide);
|
getActivity().setTitle(R.string.magiskhide);
|
||||||
CallbackHandler.register(Global.Events.packageLoadDone, this);
|
getApplication().magiskHideDone.register(this);
|
||||||
if (Global.Events.packageLoadDone.isTriggered) {
|
|
||||||
onTrigger(Global.Events.packageLoadDone);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
CallbackHandler.unRegister(Global.Events.packageLoadDone, this);
|
getApplication().magiskHideDone.unRegister(this);
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,9 +105,9 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrigger(CallbackHandler.Event event) {
|
public void onTrigger(CallbackEvent<Void> event) {
|
||||||
Logger.dev("MagiskHideFragment: UI refresh");
|
Logger.dev("MagiskHideFragment: UI refresh");
|
||||||
appAdapter.setLists(Global.Data.appList, Global.Data.magiskHideList);
|
appAdapter.setLists(getApplication().appList, getApplication().magiskHideList);
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
if (!TextUtils.isEmpty(lastFilter)) {
|
if (!TextUtils.isEmpty(lastFilter)) {
|
||||||
appAdapter.filter(lastFilter);
|
appAdapter.filter(lastFilter);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -25,7 +24,9 @@ import android.widget.ScrollView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
import com.topjohnwu.magisk.asyncs.SerialTask;
|
||||||
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
@@ -121,12 +122,12 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||||
}
|
}
|
||||||
} else {
|
} 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> {
|
public class LogManager extends SerialTask<Object, Void, Object> {
|
||||||
|
|
||||||
int mode;
|
int mode;
|
||||||
File targetFile;
|
File targetFile;
|
||||||
@@ -150,7 +151,7 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
Shell.su("echo > " + MAGISK_LOG);
|
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 "";
|
return "";
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
@@ -161,8 +162,9 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Calendar now = Calendar.getInstance();
|
Calendar now = Calendar.getInstance();
|
||||||
String filename = String.format(
|
String filename = String.format(
|
||||||
@@ -174,8 +176,9 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
targetFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/MagiskManager/" + filename);
|
targetFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/MagiskManager/" + filename);
|
||||||
|
|
||||||
if ((!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs())
|
if ((!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs())
|
||||||
|| (targetFile.exists() && !targetFile.delete()))
|
|| (targetFile.exists() && !targetFile.delete())) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
List<String> in = Utils.readFile(MAGISK_LOG);
|
List<String> in = Utils.readFile(MAGISK_LOG);
|
||||||
|
|
||||||
@@ -213,10 +216,11 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
bool = (boolean) o;
|
bool = (boolean) o;
|
||||||
if (bool)
|
if (bool) {
|
||||||
Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG).show();
|
||||||
else
|
} else {
|
||||||
Toast.makeText(getActivity(), getString(R.string.logs_save_failed), Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), getString(R.string.logs_save_failed), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
179
app/src/main/java/com/topjohnwu/magisk/MagiskManager.java
Normal file
179
app/src/main/java/com/topjohnwu/magisk/MagiskManager.java
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
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.util.SparseArray;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.module.Module;
|
||||||
|
import com.topjohnwu.magisk.module.Repo;
|
||||||
|
import com.topjohnwu.magisk.superuser.Policy;
|
||||||
|
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||||
|
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 MAGISK_HIDE_PATH = "/magisk/.core/magiskhide/";
|
||||||
|
public static final String TMP_FOLDER_PATH = "/dev/tmp";
|
||||||
|
public static final String MAGISK_PATH = "/magisk";
|
||||||
|
public static final String INTENT_SECTION = "section";
|
||||||
|
|
||||||
|
// 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<>();
|
||||||
|
public final SparseArray<CallbackEvent<Policy>> uidSuRequest = new SparseArray<>();
|
||||||
|
|
||||||
|
// Info
|
||||||
|
public double magiskVersion;
|
||||||
|
public String magiskVersionString;
|
||||||
|
public double remoteMagiskVersion = -1;
|
||||||
|
public String magiskLink;
|
||||||
|
public String releaseNoteLink;
|
||||||
|
public int SNCheckResult = -1;
|
||||||
|
public String bootBlock = null;
|
||||||
|
public boolean isSuClient = false;
|
||||||
|
public String suVersion = null;
|
||||||
|
public boolean disabled;
|
||||||
|
public boolean magiskHideStarted;
|
||||||
|
|
||||||
|
// 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 busybox;
|
||||||
|
public int suRequestTimeout;
|
||||||
|
public int suLogTimeout = 14;
|
||||||
|
public int suAccessState;
|
||||||
|
public int suResponseType;
|
||||||
|
public int suNotificationType;
|
||||||
|
|
||||||
|
public SharedPreferences prefs;
|
||||||
|
|
||||||
|
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);
|
||||||
|
devLogging = prefs.getBoolean("developer_logging", false);
|
||||||
|
shellLogging = prefs.getBoolean("shell_logging", false);
|
||||||
|
magiskHide = prefs.getBoolean("magiskhide", false);
|
||||||
|
updateNotification = prefs.getBoolean("notification", true);
|
||||||
|
// Always start a new root shell manually, just for safety
|
||||||
|
Shell.init();
|
||||||
|
updateMagiskInfo();
|
||||||
|
initSuAccess();
|
||||||
|
initSuConfigs();
|
||||||
|
// Initialize prefs
|
||||||
|
prefs.edit()
|
||||||
|
.putBoolean("dark_theme", isDarkTheme)
|
||||||
|
.putBoolean("magiskhide", magiskHide)
|
||||||
|
.putBoolean("notification", updateNotification)
|
||||||
|
.putBoolean("busybox", busybox)
|
||||||
|
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
|
||||||
|
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
|
||||||
|
.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))
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initSuConfigs() {
|
||||||
|
suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
|
||||||
|
suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
|
||||||
|
suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initSuAccess() {
|
||||||
|
List<String> ret = Shell.sh("su -v");
|
||||||
|
if (Utils.isValidShellResponse(ret)) {
|
||||||
|
suVersion = ret.get(0);
|
||||||
|
isSuClient = suVersion.toUpperCase().contains("MAGISK");
|
||||||
|
}
|
||||||
|
if (isSuClient) {
|
||||||
|
ret = Shell.sh("getprop persist.sys.root_access");
|
||||||
|
if (Utils.isValidShellResponse(ret)) {
|
||||||
|
suAccessState = Integer.parseInt(ret.get(0));
|
||||||
|
} else {
|
||||||
|
Shell.su(true, "setprop persist.sys.root_access 3");
|
||||||
|
suAccessState = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateMagiskInfo() {
|
||||||
|
List<String> ret = Shell.sh("getprop magisk.version");
|
||||||
|
if (!Utils.isValidShellResponse(ret)) {
|
||||||
|
magiskVersion = -1;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
magiskVersionString = ret.get(0);
|
||||||
|
magiskVersion = Double.parseDouble(ret.get(0));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// Custom version don't need to receive updates
|
||||||
|
magiskVersion = Double.POSITIVE_INFINITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = Shell.sh("getprop persist.magisk.busybox");
|
||||||
|
try {
|
||||||
|
busybox = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
busybox = false;
|
||||||
|
}
|
||||||
|
ret = Shell.sh("getprop ro.magisk.disable");
|
||||||
|
try {
|
||||||
|
disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
disabled = false;
|
||||||
|
}
|
||||||
|
ret = Shell.sh("getprop persist.magisk.hide");
|
||||||
|
try {
|
||||||
|
magiskHideStarted = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
magiskHideStarted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (magiskHideStarted) {
|
||||||
|
magiskHide = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ import android.content.pm.PackageManager;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.NavigationView;
|
import android.support.design.widget.NavigationView;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
@@ -15,23 +14,24 @@ import android.support.v4.app.Fragment;
|
|||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
import android.support.v4.widget.DrawerLayout;
|
import android.support.v4.widget.DrawerLayout;
|
||||||
import android.support.v7.app.ActionBarDrawerToggle;
|
import android.support.v7.app.ActionBarDrawerToggle;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
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.Shell;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity
|
public class MainActivity extends Activity
|
||||||
implements NavigationView.OnNavigationItemSelectedListener, CallbackHandler.EventListener {
|
implements NavigationView.OnNavigationItemSelectedListener, CallbackEvent.Listener<Void> {
|
||||||
|
|
||||||
private final Handler mDrawerHandler = new Handler();
|
private final Handler mDrawerHandler = new Handler();
|
||||||
private SharedPreferences prefs;
|
private SharedPreferences prefs;
|
||||||
|
private int mDrawerItem;
|
||||||
|
|
||||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||||
@BindView(R.id.drawer_layout) DrawerLayout drawer;
|
@BindView(R.id.drawer_layout) DrawerLayout drawer;
|
||||||
@@ -42,10 +42,10 @@ public class MainActivity extends AppCompatActivity
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
|
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
prefs = getApplicationContext().prefs;
|
||||||
|
|
||||||
if (Global.Configs.isDarkTheme) {
|
if (getApplicationContext().isDarkTheme) {
|
||||||
setTheme(R.style.AppTheme_dh);
|
setTheme(R.style.AppTheme_Dark);
|
||||||
}
|
}
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
@@ -76,31 +76,37 @@ public class MainActivity extends AppCompatActivity
|
|||||||
drawer.addDrawerListener(toggle);
|
drawer.addDrawerListener(toggle);
|
||||||
toggle.syncState();
|
toggle.syncState();
|
||||||
|
|
||||||
navigate(R.id.status);
|
if (savedInstanceState == null)
|
||||||
|
navigate(getIntent().getStringExtra(MagiskManager.INTENT_SECTION));
|
||||||
|
|
||||||
navigationView.setNavigationItemSelectedListener(this);
|
navigationView.setNavigationItemSelectedListener(this);
|
||||||
CallbackHandler.register(Global.Events.reloadMainActivity, this);
|
getApplicationContext().reloadMainActivity.register(this);
|
||||||
|
getApplicationContext().updateCheckDone.register(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
CallbackHandler.register(Global.Events.updateCheckDone, this);
|
|
||||||
if (Global.Events.updateCheckDone.isTriggered)
|
|
||||||
onTrigger(Global.Events.updateCheckDone);
|
|
||||||
checkHideSection();
|
checkHideSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
CallbackHandler.unRegister(Global.Events.updateCheckDone, this);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
super.onPause();
|
navigate(savedInstanceState.getInt(MagiskManager.INTENT_SECTION, R.id.status));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putInt(MagiskManager.INTENT_SECTION, mDrawerItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
CallbackHandler.unRegister(Global.Events.reloadMainActivity, this);
|
getApplicationContext().reloadMainActivity.unRegister(this);
|
||||||
|
getApplicationContext().updateCheckDone.unRegister(this);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,29 +127,69 @@ public class MainActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrigger(CallbackHandler.Event event) {
|
public void onTrigger(CallbackEvent<Void> event) {
|
||||||
if (event == Global.Events.updateCheckDone) {
|
if (event == getApplicationContext().reloadMainActivity) {
|
||||||
Menu menu = navigationView.getMenu();
|
|
||||||
menu.findItem(R.id.install).setVisible(Global.Info.remoteMagiskVersion > 0 &&
|
|
||||||
Shell.rootAccess());
|
|
||||||
} else if (event == Global.Events.reloadMainActivity) {
|
|
||||||
recreate();
|
recreate();
|
||||||
|
} else if (event == getApplicationContext().updateCheckDone) {
|
||||||
|
checkHideSection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkHideSection() {
|
private void checkHideSection() {
|
||||||
Menu menu = navigationView.getMenu();
|
Menu menu = navigationView.getMenu();
|
||||||
if (Shell.rootAccess()) {
|
menu.findItem(R.id.magiskhide).setVisible(
|
||||||
menu.findItem(R.id.magiskhide).setVisible(
|
Shell.rootAccess() && getApplicationContext().magiskVersion >= 8
|
||||||
Global.Info.magiskVersion >= 8 && prefs.getBoolean("magiskhide", false));
|
&& prefs.getBoolean("magiskhide", false));
|
||||||
menu.findItem(R.id.modules).setVisible(Global.Info.magiskVersion >= 4);
|
menu.findItem(R.id.modules).setVisible(
|
||||||
menu.findItem(R.id.downloads).setVisible(Global.Info.magiskVersion >= 4);
|
Shell.rootAccess() && getApplicationContext().magiskVersion >= 4);
|
||||||
menu.findItem(R.id.log).setVisible(true);
|
menu.findItem(R.id.downloads).setVisible(
|
||||||
menu.findItem(R.id.superuser).setVisible(Global.Info.isSuClient);
|
Shell.rootAccess() && getApplicationContext().magiskVersion >= 4);
|
||||||
|
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
|
||||||
|
menu.findItem(R.id.superuser).setVisible(
|
||||||
|
Shell.rootAccess() && getApplicationContext().isSuClient);
|
||||||
|
menu.findItem(R.id.install).setVisible(getApplicationContext().remoteMagiskVersion > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void navigate(String item) {
|
||||||
|
int itemId = R.id.status;
|
||||||
|
if (item != null) {
|
||||||
|
switch (item) {
|
||||||
|
case "status":
|
||||||
|
itemId = R.id.status;
|
||||||
|
break;
|
||||||
|
case "install":
|
||||||
|
itemId = R.id.install;
|
||||||
|
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) {
|
public void navigate(int itemId) {
|
||||||
|
int bak = mDrawerItem;
|
||||||
|
mDrawerItem = itemId;
|
||||||
|
navigationView.setCheckedItem(itemId);
|
||||||
switch (itemId) {
|
switch (itemId) {
|
||||||
case R.id.status:
|
case R.id.status:
|
||||||
displayFragment(new StatusFragment(), "status", true);
|
displayFragment(new StatusFragment(), "status", true);
|
||||||
@@ -165,13 +211,14 @@ public class MainActivity extends AppCompatActivity
|
|||||||
break;
|
break;
|
||||||
case R.id.log:
|
case R.id.log:
|
||||||
displayFragment(new LogFragment(), "log", false);
|
displayFragment(new LogFragment(), "log", false);
|
||||||
toolbar.setElevation(0);
|
|
||||||
break;
|
break;
|
||||||
case R.id.settings:
|
case R.id.settings:
|
||||||
startActivity(new Intent(this, SettingsActivity.class));
|
startActivity(new Intent(this, SettingsActivity.class));
|
||||||
|
mDrawerItem = bak;
|
||||||
break;
|
break;
|
||||||
case R.id.app_about:
|
case R.id.app_about:
|
||||||
startActivity(new Intent(this, AboutActivity.class));
|
startActivity(new Intent(this, AboutActivity.class));
|
||||||
|
mDrawerItem = bak;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,5 +229,6 @@ public class MainActivity extends AppCompatActivity
|
|||||||
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
|
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
|
||||||
transaction.replace(R.id.content_frame, navFragment, tag).commitNow();
|
transaction.replace(R.id.content_frame, navFragment, tag).commitNow();
|
||||||
if (setElevation) toolbar.setElevation(toolbarElevation);
|
if (setElevation) toolbar.setElevation(toolbarElevation);
|
||||||
|
else toolbar.setElevation(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.content.Intent;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -15,10 +14,11 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.github.clans.fab.FloatingActionButton;
|
import com.github.clans.fab.FloatingActionButton;
|
||||||
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
||||||
|
import com.topjohnwu.magisk.asyncs.FlashZip;
|
||||||
|
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||||
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.module.Module;
|
||||||
import com.topjohnwu.magisk.module.ModuleHelper;
|
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
|
||||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -28,7 +28,7 @@ import butterknife.BindView;
|
|||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import butterknife.Unbinder;
|
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;
|
private static final int FETCH_ZIP_CODE = 2;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
|||||||
|
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
new Async.LoadModules().exec();
|
new LoadModules(getActivity()).exec();
|
||||||
});
|
});
|
||||||
|
|
||||||
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
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();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrigger(CallbackHandler.Event event) {
|
public void onTrigger(CallbackEvent<Void> event) {
|
||||||
Logger.dev("ModulesFragment: UI refresh triggered");
|
Logger.dev("ModulesFragment: UI refresh triggered");
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
|||||||
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||||
// Get the URI of the selected file
|
// Get the URI of the selected file
|
||||||
final Uri uri = data.getData();
|
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
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
CallbackHandler.register(Global.Events.moduleLoadDone, this);
|
getApplication().moduleLoadDone.register(this);
|
||||||
getActivity().setTitle(R.string.modules);
|
getActivity().setTitle(R.string.modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
CallbackHandler.unRegister(Global.Events.moduleLoadDone, this);
|
getApplication().moduleLoadDone.unRegister(this);
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,8 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
ModuleHelper.getModuleList(listModules);
|
listModules.clear();
|
||||||
|
listModules.addAll(getApplication().moduleMap.values());
|
||||||
if (listModules.size() == 0) {
|
if (listModules.size() == 0) {
|
||||||
emptyRv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.view.MenuItemCompat;
|
import android.support.v4.view.MenuItemCompat;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
@@ -16,10 +15,12 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||||
import com.topjohnwu.magisk.adapters.SimpleSectionedRecyclerViewAdapter;
|
import com.topjohnwu.magisk.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.module.Repo;
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -29,7 +30,7 @@ import butterknife.BindView;
|
|||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import butterknife.Unbinder;
|
import butterknife.Unbinder;
|
||||||
|
|
||||||
public class ReposFragment extends Fragment implements CallbackHandler.EventListener {
|
public class ReposFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
@@ -68,10 +69,10 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
|||||||
|
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
new Async.LoadRepos(getActivity()).exec();
|
new LoadRepos(getActivity()).exec();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Global.Events.repoLoadDone.isTriggered) {
|
if (getApplication().repoLoadDone.isTriggered) {
|
||||||
reloadRepos();
|
reloadRepos();
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
@@ -93,7 +94,7 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrigger(CallbackHandler.Event event) {
|
public void onTrigger(CallbackEvent<Void> event) {
|
||||||
Logger.dev("ReposFragment: UI refresh triggered");
|
Logger.dev("ReposFragment: UI refresh triggered");
|
||||||
reloadRepos();
|
reloadRepos();
|
||||||
updateUI();
|
updateUI();
|
||||||
@@ -109,13 +110,13 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
|||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
CallbackHandler.register(Global.Events.repoLoadDone, this);
|
getApplication().repoLoadDone.register(this);
|
||||||
getActivity().setTitle(R.string.downloads);
|
getActivity().setTitle(R.string.downloads);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
CallbackHandler.unRegister(Global.Events.repoLoadDone, this);
|
getApplication().repoLoadDone.unRegister(this);
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +127,21 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void reloadRepos() {
|
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();
|
fUpdateRepos.clear();
|
||||||
fInstalledRepos.clear();
|
fInstalledRepos.clear();
|
||||||
fOthersRepos.clear();
|
fOthersRepos.clear();
|
||||||
@@ -158,7 +173,7 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
|||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FilterApps extends Async.NormalTask<String, Void, Void> {
|
private class FilterApps extends ParallelTask<String, Void, Void> {
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(String... strings) {
|
protected Void doInBackground(String... strings) {
|
||||||
String newText = strings[0];
|
String newText = strings[0];
|
||||||
|
|||||||
@@ -9,13 +9,14 @@ import android.preference.PreferenceManager;
|
|||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.preference.SwitchPreference;
|
import android.preference.SwitchPreference;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.module.ModuleHelper;
|
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
import com.topjohnwu.magisk.asyncs.SerialTask;
|
||||||
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
@@ -23,15 +24,15 @@ import com.topjohnwu.magisk.utils.Utils;
|
|||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class SettingsActivity extends AppCompatActivity {
|
public class SettingsActivity extends Activity {
|
||||||
|
|
||||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if (Global.Configs.isDarkTheme) {
|
if (getApplicationContext().isDarkTheme) {
|
||||||
setTheme(R.style.AppTheme_dh);
|
setTheme(R.style.AppTheme_Dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(R.layout.activity_container);
|
setContentView(R.layout.activity_container);
|
||||||
@@ -77,6 +78,10 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private ListPreference suAccess, autoRes, suNotification, requestTimeout;
|
private ListPreference suAccess, autoRes, suNotification, requestTimeout;
|
||||||
|
|
||||||
|
private MagiskManager getApplication() {
|
||||||
|
return Utils.getMagiskManager(getActivity());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -84,10 +89,6 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||||
prefScreen = getPreferenceScreen();
|
prefScreen = getPreferenceScreen();
|
||||||
|
|
||||||
SwitchPreference busybox = (SwitchPreference) findPreference("busybox");
|
|
||||||
SwitchPreference magiskHide = (SwitchPreference) findPreference("magiskhide");
|
|
||||||
SwitchPreference hosts = (SwitchPreference) findPreference("hosts");
|
|
||||||
|
|
||||||
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
|
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
|
||||||
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
|
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
|
||||||
|
|
||||||
@@ -99,7 +100,7 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
setSummary();
|
setSummary();
|
||||||
|
|
||||||
findPreference("clear").setOnPreferenceClickListener((pref) -> {
|
findPreference("clear").setOnPreferenceClickListener((pref) -> {
|
||||||
ModuleHelper.clearRepoCache(getActivity());
|
Utils.clearRepoCache(getActivity());
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -107,14 +108,11 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
prefScreen.removePreference(magiskCategory);
|
prefScreen.removePreference(magiskCategory);
|
||||||
prefScreen.removePreference(suCategory);
|
prefScreen.removePreference(suCategory);
|
||||||
} else {
|
} else {
|
||||||
if (!Global.Info.isSuClient)
|
if (!getApplication().isSuClient) {
|
||||||
prefScreen.removePreference(suCategory);
|
prefScreen.removePreference(suCategory);
|
||||||
if (Global.Info.magiskVersion < 11)
|
}
|
||||||
|
if (getApplication().magiskVersion < 11) {
|
||||||
prefScreen.removePreference(magiskCategory);
|
prefScreen.removePreference(magiskCategory);
|
||||||
if (Global.Info.disabled) {
|
|
||||||
busybox.setEnabled(false);
|
|
||||||
magiskHide.setEnabled(false);
|
|
||||||
hosts.setEnabled(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,22 +137,22 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
switch (key) {
|
switch (key) {
|
||||||
case "dark_theme":
|
case "dark_theme":
|
||||||
enabled = prefs.getBoolean("dark_theme", false);
|
enabled = prefs.getBoolean("dark_theme", false);
|
||||||
if (Global.Configs.isDarkTheme != enabled) {
|
if (getApplication().isDarkTheme != enabled) {
|
||||||
Global.Configs.isDarkTheme = enabled;
|
getApplication().isDarkTheme = enabled;
|
||||||
|
getApplication().reloadMainActivity.trigger();
|
||||||
getActivity().recreate();
|
getActivity().recreate();
|
||||||
Global.Events.reloadMainActivity.trigger();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "disable":
|
case "disable":
|
||||||
enabled = prefs.getBoolean("disable", false);
|
enabled = prefs.getBoolean("disable", false);
|
||||||
new Async.RootTask<Void, Void, Void>() {
|
new SerialTask<Void, Void, Void>() {
|
||||||
private boolean enable = enabled;
|
private boolean enable = enabled;
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
Utils.createFile(Global.MAGISK_DISABLE_FILE);
|
Utils.createFile(MagiskManager.MAGISK_DISABLE_FILE);
|
||||||
} else {
|
} else {
|
||||||
Utils.removeItem(Global.MAGISK_DISABLE_FILE);
|
Utils.removeItem(MagiskManager.MAGISK_DISABLE_FILE);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -163,7 +161,7 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
break;
|
break;
|
||||||
case "busybox":
|
case "busybox":
|
||||||
enabled = prefs.getBoolean("busybox", false);
|
enabled = prefs.getBoolean("busybox", false);
|
||||||
new Async.RootTask<Void, Void, Void>() {
|
new SerialTask<Void, Void, Void>() {
|
||||||
private boolean enable = enabled;
|
private boolean enable = enabled;
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
@@ -183,20 +181,23 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
case "magiskhide":
|
case "magiskhide":
|
||||||
enabled = prefs.getBoolean("magiskhide", false);
|
enabled = prefs.getBoolean("magiskhide", false);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (!Global.Info.isSuClient) {
|
if (!getApplication().isSuClient) {
|
||||||
Utils.getAlertDialogBuilder(getActivity())
|
new AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.no_magisksu_title)
|
.setTitle(R.string.no_magisksu_title)
|
||||||
.setMessage(R.string.no_magisksu_msg)
|
.setMessage(R.string.no_magisksu_msg)
|
||||||
.setPositiveButton(R.string.understand, (dialog, which) -> new Async.MagiskHide().enable())
|
.setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide().enable())
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.show();
|
.show();
|
||||||
} else new Async.MagiskHide().enable();
|
} else {
|
||||||
} else
|
new MagiskHide().enable();
|
||||||
new Async.MagiskHide().disable();
|
}
|
||||||
|
} else {
|
||||||
|
new MagiskHide().disable();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "hosts":
|
case "hosts":
|
||||||
enabled = prefs.getBoolean("hosts", false);
|
enabled = prefs.getBoolean("hosts", false);
|
||||||
new Async.RootTask<Void, Void, Void>() {
|
new SerialTask<Void, Void, Void>() {
|
||||||
private boolean enable = enabled;
|
private boolean enable = enabled;
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
@@ -212,23 +213,23 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
}.exec();
|
}.exec();
|
||||||
break;
|
break;
|
||||||
case "su_access":
|
case "su_access":
|
||||||
Global.Configs.suAccessState = Utils.getPrefsInt(prefs, "su_access", 0);
|
getApplication().suAccessState = Utils.getPrefsInt(prefs, "su_access", 0);
|
||||||
Shell.su("setprop persist.sys.root_access " + Global.Configs.suAccessState);
|
Shell.su("setprop persist.sys.root_access " + getApplication().suAccessState);
|
||||||
break;
|
break;
|
||||||
case "su_request_timeout":
|
case "su_request_timeout":
|
||||||
Global.Configs.suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
|
getApplication().suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
|
||||||
break;
|
break;
|
||||||
case "su_auto_response":
|
case "su_auto_response":
|
||||||
Global.Configs.suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
|
getApplication().suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
|
||||||
break;
|
break;
|
||||||
case "su_notification":
|
case "su_notification":
|
||||||
Global.Configs.suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
|
getApplication().suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
|
||||||
break;
|
break;
|
||||||
case "developer_logging":
|
case "developer_logging":
|
||||||
Global.Configs.devLogging = prefs.getBoolean("developer_logging", false);
|
MagiskManager.devLogging = prefs.getBoolean("developer_logging", false);
|
||||||
break;
|
break;
|
||||||
case "shell_logging":
|
case "shell_logging":
|
||||||
Global.Configs.shellLogging = prefs.getBoolean("shell_logging", false);
|
MagiskManager.shellLogging = prefs.getBoolean("shell_logging", false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
setSummary();
|
setSummary();
|
||||||
@@ -236,11 +237,11 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private void setSummary() {
|
private void setSummary() {
|
||||||
suAccess.setSummary(getResources()
|
suAccess.setSummary(getResources()
|
||||||
.getStringArray(R.array.su_access)[Global.Configs.suAccessState]);
|
.getStringArray(R.array.su_access)[getApplication().suAccessState]);
|
||||||
autoRes.setSummary(getResources()
|
autoRes.setSummary(getResources()
|
||||||
.getStringArray(R.array.auto_response)[Global.Configs.suResponseType]);
|
.getStringArray(R.array.auto_response)[getApplication().suResponseType]);
|
||||||
suNotification.setSummary(getResources()
|
suNotification.setSummary(getResources()
|
||||||
.getStringArray(R.array.su_notification)[Global.Configs.suNotificationType]);
|
.getStringArray(R.array.su_notification)[getApplication().suNotificationType]);
|
||||||
requestTimeout.setSummary(
|
requestTimeout.setSummary(
|
||||||
getString(R.string.request_timeout_summary, prefs.getString("su_request_timeout", "10")));
|
getString(R.string.request_timeout_summary, prefs.getString("su_request_timeout", "10")));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,73 @@
|
|||||||
package com.topjohnwu.magisk;
|
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.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
|
import com.topjohnwu.magisk.asyncs.GetBootBlocks;
|
||||||
|
import com.topjohnwu.magisk.asyncs.LoadApps;
|
||||||
|
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||||
|
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
||||||
|
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||||
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||||
|
|
||||||
public class SplashActivity extends AppCompatActivity {
|
public class SplashActivity extends Activity{
|
||||||
|
|
||||||
|
private static final int UPDATE_SERVICE_ID = 1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
MagiskManager magiskManager = getApplicationContext();
|
||||||
|
|
||||||
// Init the info and configs and root shell
|
// Init the info and configs and root shell
|
||||||
Global.init(getApplicationContext());
|
magiskManager.init();
|
||||||
|
|
||||||
|
// Initialize the update check service, notify every 3 hours
|
||||||
|
if (!"install".equals(getIntent().getStringExtra(MagiskManager.INTENT_SECTION))) {
|
||||||
|
ComponentName service = new ComponentName(magiskManager, UpdateCheckService.class);
|
||||||
|
JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service)
|
||||||
|
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
||||||
|
.setPersisted(true)
|
||||||
|
.setPeriodic(3 * 60 * 60 * 1000)
|
||||||
|
.build();
|
||||||
|
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||||
|
scheduler.schedule(jobInfo);
|
||||||
|
}
|
||||||
|
|
||||||
// Now fire all async tasks
|
// Now fire all async tasks
|
||||||
new Async.CheckUpdates().exec();
|
new GetBootBlocks(this).exec();
|
||||||
new Async.GetBootBlocks().exec();
|
if (magiskManager.magiskHide && magiskManager.magiskVersion > 11 &&
|
||||||
new Async.LoadModules() {
|
!magiskManager.magiskHideStarted) {
|
||||||
|
new MagiskHide().enable();
|
||||||
|
}
|
||||||
|
new LoadModules(this) {
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void v) {
|
protected void onPostExecute(Void v) {
|
||||||
super.onPostExecute(v);
|
super.onPostExecute(v);
|
||||||
new Async.LoadRepos(getApplicationContext()).exec();
|
new LoadRepos(activity).exec();
|
||||||
|
}
|
||||||
|
}.exec();
|
||||||
|
new LoadApps(this).exec();
|
||||||
|
new CheckUpdates(this, false){
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void v) {
|
||||||
|
super.onPostExecute(v);
|
||||||
|
String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION);
|
||||||
|
Intent intent = new Intent(magiskManager, MainActivity.class);
|
||||||
|
if (section != null) {
|
||||||
|
intent.putExtra(MagiskManager.INTENT_SECTION, section);
|
||||||
|
}
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
}
|
}
|
||||||
}.exec();
|
}.exec();
|
||||||
new Async.LoadApps(getPackageManager()).exec();
|
|
||||||
|
|
||||||
// Preparation done, now start main activity
|
|
||||||
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.FragmentTransaction;
|
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -15,8 +10,10 @@ import android.widget.ImageView;
|
|||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
|
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
@@ -24,9 +21,10 @@ import com.topjohnwu.magisk.utils.Utils;
|
|||||||
import butterknife.BindColor;
|
import butterknife.BindColor;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnClick;
|
||||||
import butterknife.Unbinder;
|
import butterknife.Unbinder;
|
||||||
|
|
||||||
public class StatusFragment extends Fragment implements CallbackHandler.EventListener {
|
public class StatusFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
||||||
|
|
||||||
private static boolean noDialog = false;
|
private static boolean noDialog = false;
|
||||||
|
|
||||||
@@ -55,9 +53,24 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
|
|||||||
@BindColor(R.color.grey500) int colorNeutral;
|
@BindColor(R.color.grey500) int colorNeutral;
|
||||||
@BindColor(R.color.blue500) int colorInfo;
|
@BindColor(R.color.blue500) int colorInfo;
|
||||||
@BindColor(android.R.color.transparent) int trans;
|
@BindColor(android.R.color.transparent) int trans;
|
||||||
int defaultColor;
|
|
||||||
|
|
||||||
private AlertDialog updateMagisk;
|
@OnClick(R.id.safetyNet_container)
|
||||||
|
public void safetyNet() {
|
||||||
|
safetyNetProgress.setVisibility(View.VISIBLE);
|
||||||
|
safetyNetContainer.setBackgroundColor(trans);
|
||||||
|
safetyNetIcon.setImageResource(0);
|
||||||
|
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
|
||||||
|
Utils.checkSafetyNet(getApplication());
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.magisk_status_container)
|
||||||
|
public void gotoInstall() {
|
||||||
|
if (getApplication().remoteMagiskVersion > 0) {
|
||||||
|
((MainActivity) getActivity()).navigate(R.id.install);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int defaultColor;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
@@ -80,50 +93,40 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
|
|||||||
safetyNetStatusText.setText(R.string.safetyNet_check_text);
|
safetyNetStatusText.setText(R.string.safetyNet_check_text);
|
||||||
safetyNetStatusText.setTextColor(defaultColor);
|
safetyNetStatusText.setTextColor(defaultColor);
|
||||||
|
|
||||||
Global.Events.safetyNetDone.isTriggered = false;
|
getApplication().safetyNetDone.isTriggered = false;
|
||||||
noDialog = false;
|
noDialog = false;
|
||||||
|
|
||||||
updateUI();
|
updateUI();
|
||||||
new Async.CheckUpdates().exec();
|
new CheckUpdates(getActivity()).exec();
|
||||||
});
|
});
|
||||||
|
|
||||||
safetyNetContainer.setOnClickListener(view -> {
|
if (getApplication().magiskVersion < 0 && Shell.rootAccess() && !noDialog) {
|
||||||
safetyNetProgress.setVisibility(View.VISIBLE);
|
|
||||||
safetyNetContainer.setBackgroundColor(trans);
|
|
||||||
safetyNetIcon.setImageResource(0);
|
|
||||||
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
|
|
||||||
Async.checkSafetyNet(getActivity());
|
|
||||||
});
|
|
||||||
|
|
||||||
if (Global.Info.magiskVersion < 0 && Shell.rootAccess() && !noDialog) {
|
|
||||||
noDialog = true;
|
noDialog = true;
|
||||||
Utils.getAlertDialogBuilder(getActivity())
|
new AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.no_magisk_title)
|
.setTitle(R.string.no_magisk_title)
|
||||||
.setMessage(R.string.no_magisk_msg)
|
.setMessage(R.string.no_magisk_msg)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setPositiveButton(R.string.goto_install, (dialogInterface, i) -> {
|
.setPositiveButton(R.string.goto_install, (d, i) -> gotoInstall())
|
||||||
((MainActivity) getActivity()).navigationView.setCheckedItem(R.id.install);
|
|
||||||
FragmentTransaction transaction = getFragmentManager().beginTransaction();
|
|
||||||
transaction.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
|
|
||||||
try {
|
|
||||||
transaction.replace(R.id.content_frame, new InstallFragment(), "install").commit();
|
|
||||||
} catch (IllegalStateException ignored) {}
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.no_thanks, null)
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUI();
|
updateUI();
|
||||||
|
|
||||||
|
if (getApplication().updateCheckDone.isTriggered)
|
||||||
|
updateCheckUI();
|
||||||
|
if (getApplication().safetyNetDone.isTriggered)
|
||||||
|
updateSafetyNetUI();
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrigger(CallbackHandler.Event event) {
|
public void onTrigger(CallbackEvent<Void> event) {
|
||||||
if (event == Global.Events.updateCheckDone) {
|
if (event == getApplication().updateCheckDone) {
|
||||||
Logger.dev("StatusFragment: Update Check UI refresh triggered");
|
Logger.dev("StatusFragment: Update Check UI refresh triggered");
|
||||||
updateCheckUI();
|
updateCheckUI();
|
||||||
} else if (event == Global.Events.safetyNetDone) {
|
} else if (event == getApplication().safetyNetDone) {
|
||||||
Logger.dev("StatusFragment: SafetyNet UI refresh triggered");
|
Logger.dev("StatusFragment: SafetyNet UI refresh triggered");
|
||||||
updateSafetyNetUI();
|
updateSafetyNetUI();
|
||||||
}
|
}
|
||||||
@@ -132,21 +135,15 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
|
|||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
CallbackHandler.register(Global.Events.updateCheckDone, this);
|
getApplication().updateCheckDone.register(this);
|
||||||
CallbackHandler.register(Global.Events.safetyNetDone, this);
|
getApplication().safetyNetDone.register(this);
|
||||||
if (Global.Events.updateCheckDone.isTriggered) {
|
|
||||||
updateCheckUI();
|
|
||||||
}
|
|
||||||
if (Global.Events.safetyNetDone.isTriggered) {
|
|
||||||
updateSafetyNetUI();
|
|
||||||
}
|
|
||||||
getActivity().setTitle(R.string.status);
|
getActivity().setTitle(R.string.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
CallbackHandler.unRegister(Global.Events.updateCheckDone, this);
|
getApplication().updateCheckDone.unRegister(this);
|
||||||
CallbackHandler.unRegister(Global.Events.safetyNetDone, this);
|
getApplication().safetyNetDone.unRegister(this);
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,14 +156,14 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
|
|||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
int image, color;
|
int image, color;
|
||||||
|
|
||||||
Global.updateMagiskInfo();
|
getApplication().updateMagiskInfo();
|
||||||
|
|
||||||
if (Global.Info.magiskVersion < 0) {
|
if (getApplication().magiskVersion < 0) {
|
||||||
magiskVersionText.setText(R.string.magisk_version_error);
|
magiskVersionText.setText(R.string.magisk_version_error);
|
||||||
} else if (Global.Info.disabled) {
|
} else if (getApplication().disabled) {
|
||||||
magiskVersionText.setText(getString(R.string.magisk_version_disable, Global.Info.magiskVersionString));
|
magiskVersionText.setText(getString(R.string.magisk_version_core_only, getApplication().magiskVersionString));
|
||||||
} else {
|
} else {
|
||||||
magiskVersionText.setText(getString(R.string.magisk_version, Global.Info.magiskVersionString));
|
magiskVersionText.setText(getString(R.string.magisk_version, getApplication().magiskVersionString));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Shell.rootStatus) {
|
switch (Shell.rootStatus) {
|
||||||
@@ -177,11 +174,11 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
|
|||||||
rootInfoText.setText(R.string.root_info_warning);
|
rootInfoText.setText(R.string.root_info_warning);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (Global.Info.suVersion != null) {
|
if (getApplication().suVersion != null) {
|
||||||
color = colorOK;
|
color = colorOK;
|
||||||
image = R.drawable.ic_check_circle;
|
image = R.drawable.ic_check_circle;
|
||||||
rootStatusText.setText(R.string.proper_root);
|
rootStatusText.setText(R.string.proper_root);
|
||||||
rootInfoText.setText(Global.Info.suVersion);
|
rootInfoText.setText(getApplication().suVersion);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case -1:
|
case -1:
|
||||||
@@ -200,26 +197,23 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
|
|||||||
private void updateCheckUI() {
|
private void updateCheckUI() {
|
||||||
int image, color;
|
int image, color;
|
||||||
|
|
||||||
if (Global.Info.remoteMagiskVersion < 0) {
|
if (getApplication().remoteMagiskVersion < 0) {
|
||||||
color = colorNeutral;
|
color = colorNeutral;
|
||||||
image = R.drawable.ic_help;
|
image = R.drawable.ic_help;
|
||||||
magiskUpdateText.setText(R.string.cannot_check_updates);
|
magiskUpdateText.setText(R.string.cannot_check_updates);
|
||||||
} else if (Global.Info.remoteMagiskVersion > Global.Info.magiskVersion) {
|
} else if (getApplication().remoteMagiskVersion > getApplication().magiskVersion) {
|
||||||
color = colorInfo;
|
color = colorInfo;
|
||||||
image = R.drawable.ic_update;
|
image = R.drawable.ic_update;
|
||||||
magiskUpdateText.setText(getString(R.string.magisk_update_available, Global.Info.remoteMagiskVersion));
|
magiskUpdateText.setText(getString(R.string.magisk_update_available, getApplication().remoteMagiskVersion));
|
||||||
} else {
|
} else {
|
||||||
color = colorOK;
|
color = colorOK;
|
||||||
image = R.drawable.ic_check_circle;
|
image = R.drawable.ic_check_circle;
|
||||||
magiskUpdateText.setText(getString(R.string.up_to_date, getString(R.string.magisk)));
|
magiskUpdateText.setText(getString(R.string.up_to_date, getString(R.string.magisk)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Global.Info.magiskVersion < 0) {
|
if (getApplication().magiskVersion < 0) {
|
||||||
color = colorBad;
|
color = colorBad;
|
||||||
image = R.drawable.ic_cancel;
|
image = R.drawable.ic_cancel;
|
||||||
} else if (Global.Info.disabled) {
|
|
||||||
color = colorNeutral;
|
|
||||||
image = R.drawable.ic_cancel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
magiskStatusContainer.setBackgroundColor(color);
|
magiskStatusContainer.setBackgroundColor(color);
|
||||||
@@ -229,38 +223,12 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
|
|||||||
|
|
||||||
magiskCheckUpdatesProgress.setVisibility(View.GONE);
|
magiskCheckUpdatesProgress.setVisibility(View.GONE);
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
|
|
||||||
updateMagisk = Utils.getAlertDialogBuilder(getActivity())
|
|
||||||
.setTitle(R.string.magisk_update_title)
|
|
||||||
.setMessage(getString(R.string.magisk_update_message, Global.Info.remoteMagiskVersion))
|
|
||||||
.setCancelable(true)
|
|
||||||
.setPositiveButton(R.string.goto_install, (dialogInterface, i) -> {
|
|
||||||
((MainActivity) getActivity()).navigationView.setCheckedItem(R.id.install);
|
|
||||||
FragmentTransaction transaction = getFragmentManager().beginTransaction();
|
|
||||||
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
|
|
||||||
try {
|
|
||||||
transaction.replace(R.id.content_frame, new InstallFragment(), "install").commit();
|
|
||||||
} catch (IllegalStateException ignored) {}
|
|
||||||
})
|
|
||||||
.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)
|
|
||||||
.create();
|
|
||||||
|
|
||||||
if (Global.Info.magiskVersion < Global.Info.remoteMagiskVersion && Shell.rootAccess()) {
|
|
||||||
magiskStatusContainer.setOnClickListener(view -> updateMagisk.show());
|
|
||||||
if (!noDialog) {
|
|
||||||
noDialog = true;
|
|
||||||
updateMagisk.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSafetyNetUI() {
|
private void updateSafetyNetUI() {
|
||||||
int image, color;
|
int image, color;
|
||||||
safetyNetProgress.setVisibility(View.GONE);
|
safetyNetProgress.setVisibility(View.GONE);
|
||||||
switch (Global.Info.SNCheckResult) {
|
switch (getApplication().SNCheckResult) {
|
||||||
case -3:
|
case -3:
|
||||||
color = colorNeutral;
|
color = colorNeutral;
|
||||||
image = R.drawable.ic_help;
|
image = R.drawable.ic_help;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -13,7 +12,8 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.SuLogAdapter;
|
import com.topjohnwu.magisk.adapters.SuLogAdapter;
|
||||||
import com.topjohnwu.magisk.superuser.SuLogDatabaseHelper;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
|
import com.topjohnwu.magisk.database.SuLogDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -11,8 +10,9 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
||||||
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
import com.topjohnwu.magisk.superuser.Policy;
|
||||||
import com.topjohnwu.magisk.superuser.SuDatabaseHelper;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||||
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -50,8 +51,8 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setLists(List<ApplicationInfo> listApps, List<String> hideList) {
|
public void setLists(List<ApplicationInfo> listApps, List<String> hideList) {
|
||||||
mOriginalList = mList = Collections.unmodifiableList(listApps);
|
mOriginalList = mList = listApps;
|
||||||
mHideList = new ArrayList<>(hideList);
|
mHideList = hideList;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,20 +77,19 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
if (SNLIST.contains(info.packageName)) {
|
if (SNLIST.contains(info.packageName)) {
|
||||||
holder.checkBox.setChecked(true);
|
holder.checkBox.setChecked(true);
|
||||||
holder.checkBox.setEnabled(false);
|
holder.checkBox.setEnabled(false);
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v ->
|
||||||
Snackbar snackbar = Snackbar.make(holder.itemView, R.string.safetyNet_hide_notice, Snackbar.LENGTH_LONG);
|
SnackbarMaker.make(holder.itemView,
|
||||||
((TextView) snackbar.getView().findViewById(android.support.design.R.id.snackbar_text)).setMaxLines(2);
|
R.string.safetyNet_hide_notice, Snackbar.LENGTH_LONG).show()
|
||||||
snackbar.show();
|
);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
holder.checkBox.setEnabled(true);
|
holder.checkBox.setEnabled(true);
|
||||||
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
||||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
new Async.MagiskHide().add(info.packageName);
|
new MagiskHide().add(info.packageName);
|
||||||
mHideList.add(info.packageName);
|
mHideList.add(info.packageName);
|
||||||
} else {
|
} else {
|
||||||
new Async.MagiskHide().rm(info.packageName);
|
new MagiskHide().rm(info.packageName);
|
||||||
mHideList.remove(info.packageName);
|
mHideList.remove(info.packageName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.asyncs.SerialTask;
|
||||||
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.module.Module;
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -52,7 +53,7 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
|||||||
|
|
||||||
holder.checkBox.setOnCheckedChangeListener(null);
|
holder.checkBox.setOnCheckedChangeListener(null);
|
||||||
holder.checkBox.setChecked(module.isEnabled());
|
holder.checkBox.setChecked(module.isEnabled());
|
||||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> new Async.RootTask<Void, Void, Void>() {
|
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> new SerialTask<Void, Void, Void>() {
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
@@ -66,11 +67,11 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
|||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void v) {
|
protected void onPostExecute(Void v) {
|
||||||
int snack = isChecked ? R.string.disable_file_removed : R.string.disable_file_created;
|
int snack = isChecked ? R.string.disable_file_removed : R.string.disable_file_created;
|
||||||
Snackbar.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}.exec());
|
}.exec());
|
||||||
|
|
||||||
holder.delete.setOnClickListener(v -> new Async.RootTask<Void, Void, Void>() {
|
holder.delete.setOnClickListener(v -> new SerialTask<Void, Void, Void>() {
|
||||||
private final boolean removed = module.willBeRemoved();
|
private final boolean removed = module.willBeRemoved();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -86,7 +87,7 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
|||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void v) {
|
protected void onPostExecute(Void v) {
|
||||||
int snack = removed ? R.string.remove_file_deleted : R.string.remove_file_created;
|
int snack = removed ? R.string.remove_file_deleted : R.string.remove_file_created;
|
||||||
Snackbar.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||||
updateDeleteButton(holder, module);
|
updateDeleteButton(holder, module);
|
||||||
}
|
}
|
||||||
}.exec());
|
}.exec());
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ import android.widget.Switch;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
import com.topjohnwu.magisk.superuser.Policy;
|
||||||
import com.topjohnwu.magisk.superuser.SuDatabaseHelper;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -70,7 +71,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
policy.policy = isChecked ? Policy.ALLOW : Policy.DENY;
|
policy.policy = isChecked ? Policy.ALLOW : Policy.DENY;
|
||||||
String message = v.getContext().getString(
|
String message = v.getContext().getString(
|
||||||
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
|
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
|
||||||
Snackbar.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.addPolicy(policy);
|
dbHelper.addPolicy(policy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -80,7 +81,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
policy.notification = isChecked;
|
policy.notification = isChecked;
|
||||||
String message = v.getContext().getString(
|
String message = v.getContext().getString(
|
||||||
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
|
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
|
||||||
Snackbar.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.addPolicy(policy);
|
dbHelper.addPolicy(policy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -90,18 +91,18 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
policy.logging = isChecked;
|
policy.logging = isChecked;
|
||||||
String message = v.getContext().getString(
|
String message = v.getContext().getString(
|
||||||
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
|
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
|
||||||
Snackbar.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.addPolicy(policy);
|
dbHelper.addPolicy(policy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
holder.delete.setOnClickListener(v -> Utils.getAlertDialogBuilder(v.getContext())
|
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
|
||||||
.setTitle(R.string.su_revoke_title)
|
.setTitle(R.string.su_revoke_title)
|
||||||
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
|
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
|
||||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||||
policyList.remove(position);
|
policyList.remove(position);
|
||||||
notifyItemRemoved(position);
|
notifyItemRemoved(position);
|
||||||
notifyItemRangeChanged(position, policyList.size());
|
notifyItemRangeChanged(position, policyList.size());
|
||||||
Snackbar.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
|
SnackbarMaker.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
|
||||||
Snackbar.LENGTH_SHORT).show();
|
Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.deletePolicy(policy.uid);
|
dbHelper.deletePolicy(policy.uid);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,30 +1,25 @@
|
|||||||
package com.topjohnwu.magisk.adapters;
|
package com.topjohnwu.magisk.adapters;
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.ObjectAnimator;
|
|
||||||
import android.animation.ValueAnimator;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewTreeObserver;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
|
import com.topjohnwu.magisk.components.MarkDownWindow;
|
||||||
import com.topjohnwu.magisk.module.Repo;
|
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.Utils;
|
||||||
import com.topjohnwu.magisk.utils.WebWindow;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@@ -32,7 +27,7 @@ import butterknife.ButterKnife;
|
|||||||
public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> {
|
public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> {
|
||||||
|
|
||||||
private List<Repo> mUpdateRepos, mInstalledRepos, mOthersRepos;
|
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) {
|
public ReposAdapter(List<Repo> update, List<Repo> installed, List<Repo> others) {
|
||||||
mUpdateRepos = update;
|
mUpdateRepos = update;
|
||||||
@@ -42,61 +37,52 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
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);
|
return new ViewHolder(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||||
Context context = holder.itemView.getContext();
|
|
||||||
Repo repo = getItem(position);
|
Repo repo = getItem(position);
|
||||||
|
|
||||||
holder.title.setText(repo.getName());
|
holder.title.setText(repo.getName());
|
||||||
holder.versionName.setText(repo.getVersion());
|
holder.versionName.setText(repo.getVersion());
|
||||||
String author = repo.getAuthor();
|
String author = repo.getAuthor();
|
||||||
holder.author.setText(TextUtils.isEmpty(author) ? null : 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.description.setText(repo.getDescription());
|
||||||
|
|
||||||
holder.setExpanded(expandList.contains(repo));
|
holder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), mContext));
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(view -> {
|
holder.downloadImage.setOnClickListener(v -> {
|
||||||
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 -> {
|
|
||||||
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
|
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
|
||||||
Utils.getAlertDialogBuilder(context)
|
new AlertDialogBuilder(mContext)
|
||||||
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
|
.setTitle(mContext.getString(R.string.repo_install_title, repo.getName()))
|
||||||
.setMessage(context.getString(R.string.repo_install_msg, filename))
|
.setMessage(mContext.getString(R.string.repo_install_msg, filename))
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive(
|
.setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive(
|
||||||
context,
|
mContext,
|
||||||
new RepoDlReceiver(),
|
new DownloadReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onDownloadDone(Uri uri) {
|
||||||
|
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) {
|
||||||
|
new ProcessRepoZip(activity, uri, false).exec();
|
||||||
|
}
|
||||||
|
},
|
||||||
repo.getZipUrl(),
|
repo.getZipUrl(),
|
||||||
Utils.getLegalFilename(filename)))
|
Utils.getLegalFilename(filename)))
|
||||||
.setNegativeButton(R.string.no_thanks, null)
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
.show();
|
.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
|
@Override
|
||||||
@@ -124,97 +110,12 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
|
|||||||
@BindView(R.id.version_name) TextView versionName;
|
@BindView(R.id.version_name) TextView versionName;
|
||||||
@BindView(R.id.description) TextView description;
|
@BindView(R.id.description) TextView description;
|
||||||
@BindView(R.id.author) TextView author;
|
@BindView(R.id.author) TextView author;
|
||||||
@BindView(R.id.expand_layout) LinearLayout expandLayout;
|
@BindView(R.id.info_layout) LinearLayout infoLayout;
|
||||||
@BindView(R.id.update) ImageView updateImage;
|
@BindView(R.id.download) ImageView downloadImage;
|
||||||
@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;
|
|
||||||
|
|
||||||
ViewHolder(View itemView) {
|
ViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
ButterKnife.bind(this, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,9 @@ public class SuLogAdapter {
|
|||||||
@Override
|
@Override
|
||||||
public void onBindGroupViewHolder(LogGroupViewHolder holder, int flatPosition, ExpandableGroup group) {
|
public void onBindGroupViewHolder(LogGroupViewHolder holder, int flatPosition, ExpandableGroup group) {
|
||||||
holder.date.setText(group.getTitle());
|
holder.date.setText(group.getTitle());
|
||||||
if (isGroupExpanded(flatPosition)) holder.expand();
|
if (isGroupExpanded(flatPosition)) {
|
||||||
|
holder.expand();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.support.v4.app.TaskStackBuilder;
|
||||||
|
import android.support.v7.app.NotificationCompat;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.SplashActivity;
|
||||||
|
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/updates/magisk_update.json";
|
||||||
|
private static final int NOTIFICATION_ID = 1;
|
||||||
|
|
||||||
|
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.remoteMagiskVersion = magisk.getDouble("versionCode");
|
||||||
|
magiskManager.magiskLink = magisk.getString("link");
|
||||||
|
magiskManager.releaseNoteLink = magisk.getString("note");
|
||||||
|
} catch (JSONException ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void v) {
|
||||||
|
if (magiskManager.magiskVersion < magiskManager.remoteMagiskVersion
|
||||||
|
&& showNotification && magiskManager.updateNotification) {
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(magiskManager);
|
||||||
|
builder.setSmallIcon(R.drawable.ic_magisk)
|
||||||
|
.setContentTitle(magiskManager.getString(R.string.magisk_update_title))
|
||||||
|
.setContentText(magiskManager.getString(R.string.magisk_update_available, magiskManager.remoteMagiskVersion))
|
||||||
|
.setVibrate(new long[]{0, 100, 100, 100})
|
||||||
|
.setAutoCancel(true);
|
||||||
|
Intent intent = new Intent(magiskManager, SplashActivity.class);
|
||||||
|
intent.putExtra(MagiskManager.INTENT_SECTION, "install");
|
||||||
|
TaskStackBuilder stackBuilder = TaskStackBuilder.create(magiskManager);
|
||||||
|
stackBuilder.addParentStack(SplashActivity.class);
|
||||||
|
stackBuilder.addNextIntent(intent);
|
||||||
|
PendingIntent pendingIntent = stackBuilder.getPendingIntent(NOTIFICATION_ID, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
builder.setContentIntent(pendingIntent);
|
||||||
|
NotificationManager notificationManager =
|
||||||
|
(NotificationManager) magiskManager.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
notificationManager.notify(NOTIFICATION_ID, builder.build());
|
||||||
|
}
|
||||||
|
magiskManager.updateCheckDone.trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
154
app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java
Normal file
154
app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FlashZip extends SerialTask<Void, String, Integer> {
|
||||||
|
|
||||||
|
private Uri mUri;
|
||||||
|
private File mCachedFile, mScriptFile, mCheckFile;
|
||||||
|
|
||||||
|
private String mFilename;
|
||||||
|
private ProgressDialog progress;
|
||||||
|
|
||||||
|
public FlashZip(Activity context, Uri uri) {
|
||||||
|
super(context);
|
||||||
|
mUri = uri;
|
||||||
|
|
||||||
|
mCachedFile = new File(magiskManager.getCacheDir(), "install.zip");
|
||||||
|
mScriptFile = new File(magiskManager.getCacheDir(), "/META-INF/com/google/android/update-binary");
|
||||||
|
mCheckFile = new File(mScriptFile.getParent(), "updater-script");
|
||||||
|
|
||||||
|
// Try to get the filename ourselves
|
||||||
|
mFilename = Utils.getNameFromUri(magiskManager, mUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyToCache() throws Throwable {
|
||||||
|
publishProgress(magiskManager.getString(R.string.copying_msg));
|
||||||
|
|
||||||
|
if (mCachedFile.exists() && !mCachedFile.delete()) {
|
||||||
|
Logger.error("FlashZip: Error while deleting already existing file");
|
||||||
|
throw new IOException();
|
||||||
|
}
|
||||||
|
try (
|
||||||
|
InputStream in = magiskManager.getContentResolver().openInputStream(mUri);
|
||||||
|
OutputStream outputStream = new FileOutputStream(mCachedFile)
|
||||||
|
) {
|
||||||
|
byte buffer[] = new byte[1024];
|
||||||
|
int length;
|
||||||
|
if (in == null) throw new FileNotFoundException();
|
||||||
|
while ((length = in.read(buffer)) > 0)
|
||||||
|
outputStream.write(buffer, 0, length);
|
||||||
|
|
||||||
|
Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath());
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Logger.error("FlashZip: Invalid Uri");
|
||||||
|
throw e;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logger.error("FlashZip: Error in creating file");
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean unzipAndCheck() throws Exception {
|
||||||
|
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android");
|
||||||
|
List<String> ret;
|
||||||
|
ret = Utils.readFile(mCheckFile.getPath());
|
||||||
|
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
|
||||||
|
}
|
||||||
|
|
||||||
|
private int cleanup(int ret) {
|
||||||
|
Shell.su(
|
||||||
|
"rm -rf " + mCachedFile.getParent() + "/*",
|
||||||
|
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
progress = new ProgressDialog(activity);
|
||||||
|
progress.setTitle(R.string.zip_install_progress_title);
|
||||||
|
progress.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onProgressUpdate(String... values) {
|
||||||
|
progress.setMessage(values[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer doInBackground(Void... voids) {
|
||||||
|
Logger.dev("FlashZip Running... " + mFilename);
|
||||||
|
List<String> ret;
|
||||||
|
try {
|
||||||
|
copyToCache();
|
||||||
|
if (!unzipAndCheck()) return cleanup(0);
|
||||||
|
publishProgress(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
|
||||||
|
ret = Shell.su(
|
||||||
|
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile,
|
||||||
|
"if [ $? -eq 0 ]; then echo true; else echo false; fi"
|
||||||
|
);
|
||||||
|
if (!Utils.isValidShellResponse(ret)) return -1;
|
||||||
|
Logger.dev("FlashZip: Console log:");
|
||||||
|
for (String line : ret) {
|
||||||
|
Logger.dev(line);
|
||||||
|
}
|
||||||
|
if (Boolean.parseBoolean(ret.get(ret.size() - 1)))
|
||||||
|
return cleanup(1);
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return cleanup(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Integer result) {
|
||||||
|
super.onPostExecute(result);
|
||||||
|
progress.dismiss();
|
||||||
|
switch (result) {
|
||||||
|
case -1:
|
||||||
|
Toast.makeText(magiskManager, magiskManager.getString(R.string.install_error), Toast.LENGTH_LONG).show();
|
||||||
|
Utils.showUriSnack(activity, mUri);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
Toast.makeText(magiskManager, magiskManager.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
onSuccess();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onSuccess() {
|
||||||
|
magiskManager.updateCheckDone.trigger();
|
||||||
|
new LoadModules(activity).exec();
|
||||||
|
|
||||||
|
new AlertDialogBuilder(activity)
|
||||||
|
.setTitle(R.string.reboot_title)
|
||||||
|
.setMessage(R.string.reboot_msg)
|
||||||
|
.setPositiveButton(R.string.reboot, (dialogInterface, i) -> Shell.su(true, "reboot"))
|
||||||
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
|
public class GetBootBlocks extends SerialTask<Void, Void, Void> {
|
||||||
|
|
||||||
|
public GetBootBlocks(Activity context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
magiskManager.blockList = Shell.su("ls /dev/block | grep mmc");
|
||||||
|
if (magiskManager.bootBlock == null) {
|
||||||
|
magiskManager.bootBlock = Utils.detectBootImage();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void v) {
|
||||||
|
magiskManager.blockDetectionDone.trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
39
app/src/main/java/com/topjohnwu/magisk/asyncs/LoadApps.java
Normal file
39
app/src/main/java/com/topjohnwu/magisk/asyncs/LoadApps.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class LoadApps extends ParallelTask<Void, Void, Void> {
|
||||||
|
|
||||||
|
public LoadApps(Activity context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... voids) {
|
||||||
|
PackageManager pm = magiskManager.getPackageManager();
|
||||||
|
List<ApplicationInfo> list = pm.getInstalledApplications(0);
|
||||||
|
for (Iterator<ApplicationInfo> i = list.iterator(); i.hasNext(); ) {
|
||||||
|
ApplicationInfo info = i.next();
|
||||||
|
if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) {
|
||||||
|
i.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(list, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
|
||||||
|
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
|
||||||
|
magiskManager.appList = Collections.unmodifiableList(list);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void v) {
|
||||||
|
new MagiskHide(activity).list();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.module.BaseModule;
|
||||||
|
import com.topjohnwu.magisk.module.Module;
|
||||||
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
import com.topjohnwu.magisk.utils.ValueSortedMap;
|
||||||
|
|
||||||
|
public class LoadModules extends SerialTask<Void, Void, Void> {
|
||||||
|
|
||||||
|
public LoadModules(Activity context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... voids) {
|
||||||
|
Logger.dev("LoadModules: Loading modules");
|
||||||
|
|
||||||
|
magiskManager.moduleMap = new ValueSortedMap<>();
|
||||||
|
|
||||||
|
for (String path : Utils.getModList(MagiskManager.MAGISK_PATH)) {
|
||||||
|
Logger.dev("LoadModules: Adding modules from " + path);
|
||||||
|
Module module;
|
||||||
|
try {
|
||||||
|
module = new Module(path);
|
||||||
|
magiskManager.moduleMap.put(module.getId(), module);
|
||||||
|
} catch (BaseModule.CacheModException ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.dev("LoadModules: Data load done");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void v) {
|
||||||
|
magiskManager.moduleLoadDone.trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user