mirror of
				https://github.com/topjohnwu/Magisk
				synced 2025-10-30 09:00:52 +01:00 
			
		
		
		
	Compare commits
	
		
			52 Commits
		
	
	
		
			manager-v5
			...
			manager-v5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | ea6552615d | ||
|   | 4bf3287fce | ||
|   | 832c2034c2 | ||
|   | b0aa26e1f1 | ||
|   | e52baeb967 | ||
|   | 8268eb9a83 | ||
|   | 3cc458abd9 | ||
|   | 337b4c4268 | ||
|   | 001f8657f6 | ||
|   | ea884e7fa1 | ||
|   | 1b1394cf5d | ||
|   | 1eef930dbb | ||
|   | 1e175e74ed | ||
|   | 75a46c365e | ||
|   | 8e7b8825f5 | ||
|   | 2ecbca303b | ||
|   | 8195a4d616 | ||
|   | 7ba40f925f | ||
|   | 345cd1795f | ||
|   | 959aaee045 | ||
|   | 53477f0f59 | ||
|   | 5716218f41 | ||
|   | 9df6b9d5c0 | ||
|   | ec46031d36 | ||
|   | 55b84d166a | ||
|   | 34ae8bacec | ||
|   | cb4e5ca0f7 | ||
|   | 0ba45468c4 | ||
|   | 710502784e | ||
|   | 0275a8558d | ||
|   | 58acc75cf6 | ||
|   | 874ababb9f | ||
|   | 3771e6b0cd | ||
|   | 33eaefa966 | ||
|   | cd7e236d57 | ||
|   | 54c0b7c7d5 | ||
|   | a2177daec2 | ||
|   | 628386b453 | ||
|   | b222bfb3e0 | ||
|   | ab199d883d | ||
|   | 356065d1ee | ||
|   | 76e7c5623d | ||
|   | 085fba050a | ||
|   | 295334d3ac | ||
|   | 36124ddca4 | ||
|   | bd6585765e | ||
|   | c325deb4ed | ||
|   | 73bb0b10ee | ||
|   | 72820b162c | ||
|   | 89e5b8d057 | ||
|   | da4f53ebbb | ||
|   | 8458553b74 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -6,3 +6,6 @@ | ||||
| app/release | ||||
| *.hprof | ||||
| app/.externalNativeBuild/ | ||||
| *.sh | ||||
| public.certificate.x509.pem | ||||
| private.key.pk8 | ||||
|   | ||||
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,6 +1,7 @@ | ||||
| # Magisk Manager  | ||||
| You need to install CMake and NDK to build the zipadjust library for zip preprocessing | ||||
| # Magisk Manager | ||||
| This is one of the submodules used in Magisk. The project is licensed under GPL v3 (or newer). | ||||
| More info are written in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk) | ||||
|  | ||||
| ## Pre-built Binaries | ||||
| Busybox (arm and x86) compiled by osm0sis (`libbusybox.so` under `app\src\main\jniLibs`)   | ||||
| Source and more info: [osm0sis' Odds and Ends](https://forum.xda-developers.com/showthread.php?t=2239421) | ||||
| ## Building Notes | ||||
| You need to install CMake and NDK to build the zipadjust library. | ||||
| There are several files required to let Magisk Manager work properly, and they can be copied by using the build script in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk). These files are: `magisk_uninstaller.sh`, `util_functions.sh`, `public.certificate.x509.pem`, and `private.key.pk8` under the `app/src/main/assets` folder. | ||||
|   | ||||
| @@ -2,17 +2,22 @@ apply plugin: 'com.android.application' | ||||
|  | ||||
| android { | ||||
|     compileSdkVersion 26 | ||||
|     buildToolsVersion "26.0.0" | ||||
|     buildToolsVersion "26.0.1" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "com.topjohnwu.magisk" | ||||
|         minSdkVersion 21 | ||||
|         targetSdkVersion 26 | ||||
|         versionCode 51 | ||||
|         versionName "5.1.1" | ||||
|         versionCode 52 | ||||
|         versionName "5.2.0" | ||||
|         ndk { | ||||
|             moduleName 'zipadjust' | ||||
|             abiFilters 'x86', 'armeabi-v7a' | ||||
|             abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' | ||||
|         } | ||||
|         javaCompileOptions { | ||||
|             annotationProcessorOptions { | ||||
|                 argument('butterknife.debuggable', 'false') | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -48,16 +53,14 @@ repositories { | ||||
|  | ||||
| dependencies { | ||||
|     implementation fileTree(include: ['*.jar'], dir: 'libs') | ||||
|     implementation 'com.android.support:recyclerview-v7:26.0.0-beta2' | ||||
|     implementation 'com.android.support:cardview-v7:26.0.0-beta2' | ||||
|     implementation 'com.android.support:design:26.0.0-beta2' | ||||
|     implementation 'com.android.support:support-v4:26.0.0-beta2' | ||||
|     implementation 'com.jakewharton:butterknife:8.7.0' | ||||
|     implementation 'com.thoughtbot:expandablerecyclerview:1.4' | ||||
|     implementation 'us.feras.mdv:markdownview:1.1.0' | ||||
|     implementation 'com.madgag.spongycastle:core:1.54.0.0' | ||||
|     implementation 'com.madgag.spongycastle:prov:1.54.0.0' | ||||
|     implementation 'com.madgag.spongycastle:pkix:1.54.0.0' | ||||
|     implementation 'com.android.support:recyclerview-v7:26.0.0' | ||||
|     implementation 'com.android.support:cardview-v7:26.0.0' | ||||
|     implementation 'com.android.support:design:26.0.0' | ||||
|     implementation 'com.android.support:support-v4:26.0.0' | ||||
|     implementation 'com.jakewharton:butterknife:8.8.1' | ||||
|     implementation 'com.atlassian.commonmark:commonmark:0.9.0' | ||||
|     implementation 'org.bouncycastle:bcprov-jdk15on:1.57' | ||||
|     implementation 'org.bouncycastle:bcpkix-jdk15on:1.57' | ||||
|     implementation 'com.google.android.gms:play-services-safetynet:9.0.1' | ||||
|     annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0' | ||||
|     annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							| @@ -16,8 +16,8 @@ | ||||
| #   public *; | ||||
| #} | ||||
|  | ||||
| # SpongyCastle | ||||
| -keep class org.spongycastle.** { *; } | ||||
| # BouncyCastle | ||||
| -keep class org.bouncycastle.** { *; } | ||||
| -dontwarn javax.naming.** | ||||
|  | ||||
| -dontwarn android.content.** | ||||
|   | ||||
| @@ -1,153 +0,0 @@ | ||||
| #!/system/bin/sh | ||||
| ########################################################################################## | ||||
| # | ||||
| # Magisk Uninstaller | ||||
| # by topjohnwu | ||||
| #  | ||||
| # This script can be placed in /cache/magisk_uninstaller.sh | ||||
| # The Magisk main binary will pick up the script, and uninstall itself, following a reboot | ||||
| # This script can also be used in flashable zip with the uninstaller_loader.sh | ||||
| #  | ||||
| # This script will try to do restoration with the following: | ||||
| # 1-1. Find and restore the original stock boot image dump (OTA proof) | ||||
| # 1-2. If 1-1 fails, restore ramdisk from the internal backup | ||||
| #      (ramdisk fully restored, not OTA friendly) | ||||
| # 1-3. If 1-2 fails, it will remove added files in ramdisk, however modified files | ||||
| #      are remained modified, because we have no backups. By doing so, Magisk will  | ||||
| #      not be started at boot, but this isn't actually 100% cleaned up | ||||
| # 2. Remove all Magisk related files | ||||
| #    (The list is LARGE, most likely due to bad decision in early versions | ||||
| #    the latest versions has much less bloat to cleanup) | ||||
| # | ||||
| ########################################################################################## | ||||
|  | ||||
| # Call ui_print_wrap if exists, or else simply use echo | ||||
| # Useful when wrapped in flashable zip | ||||
| ui_print_wrap() { | ||||
|   type ui_print >/dev/null 2>&1 && ui_print "$1" || echo "$1" | ||||
| } | ||||
|  | ||||
| # Call abort if exists, or else show error message and exit | ||||
| # Essential when wrapped in flashable zip | ||||
| abort_wrap() { | ||||
|   type abort >/dev/null 2>&1 | ||||
|   if [ $? -ne 0 ]; then | ||||
|     ui_print_wrap "$1" | ||||
|     exit 1 | ||||
|   else | ||||
|     abort "$1" | ||||
|   fi | ||||
| } | ||||
|  | ||||
| if [ ! -d $MAGISKBIN -o ! -f $MAGISKBIN/magiskboot -o ! -f $MAGISKBIN/util_functions.sh ]; then | ||||
|   ui_print_wrap "! Cannot find $MAGISKBIN" | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| [ -z $BOOTMODE ] && BOOTMODE=false | ||||
|  | ||||
| MAGISKBIN=/data/magisk | ||||
| CHROMEDIR=$MAGISKBIN/chromeos | ||||
|  | ||||
| # Default permissions | ||||
| umask 022 | ||||
|  | ||||
| # Load utility functions | ||||
| . $MAGISKBIN/util_functions.sh | ||||
|  | ||||
| # Find the boot image | ||||
| find_boot_image | ||||
| [ -z $BOOTIMAGE ] && abort "! Unable to detect boot image" | ||||
|  | ||||
| ui_print_wrap "- Found Boot Image: $BOOTIMAGE" | ||||
|  | ||||
| cd $MAGISKBIN | ||||
|  | ||||
| ui_print_wrap "- Unpacking boot image" | ||||
| ./magiskboot --unpack "$BOOTIMAGE" | ||||
| CHROMEOS=false | ||||
| case $? in | ||||
|   1 ) | ||||
|     abort_wrap "! Unable to unpack boot image" | ||||
|     ;; | ||||
|   2 ) | ||||
|     CHROMEOS=true | ||||
|     ;; | ||||
|   3 ) | ||||
|     ui_print_wrap "! Sony ELF32 format detected" | ||||
|     abort_wrap "! Please use BootBridge from @AdrianDC to flash Magisk" | ||||
|     ;; | ||||
|   4 ) | ||||
|     ui_print_wrap "! Sony ELF64 format detected" | ||||
|     abort_wrap "! Stock kernel cannot be patched, please use a custom kernel" | ||||
| esac | ||||
|  | ||||
| # Update our previous backup to new format if exists | ||||
| if [ -f /data/stock_boot.img ]; then | ||||
|   SHA1=`./magiskboot --sha1 /data/stock_boot.img | tail -n 1` | ||||
|   STOCKDUMP=/data/stock_boot_${SHA1}.img | ||||
|   mv /data/stock_boot.img $STOCKDUMP | ||||
|   ./magiskboot --compress $STOCKDUMP | ||||
| fi | ||||
|  | ||||
| # Detect boot image state | ||||
| ./magiskboot --cpio-test ramdisk.cpio | ||||
| case $? in | ||||
|   0 )  # Stock boot | ||||
|     ui_print_wrap "- Stock boot image detected!" | ||||
|     ui_print_wrap "! Magisk is not installed!" | ||||
|     exit | ||||
|     ;; | ||||
|   1 )  # Magisk patched | ||||
|     ui_print_wrap "- Magisk patched image detected!" | ||||
|     # Find SHA1 of stock boot image | ||||
|     if [ -z $SHA1 ]; then | ||||
|       ./magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc.old | ||||
|       SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc.old` | ||||
|       rm -f init.magisk.rc.old | ||||
|     fi | ||||
|     [ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img | ||||
|     if [ -f ${STOCKDUMP}.gz ]; then | ||||
|       ui_print_wrap "- Boot image backup found!" | ||||
|       ./magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img | ||||
|     else | ||||
|       ui_print_wrap "! Boot image backup unavailable" | ||||
|       ui_print_wrap "- Restoring ramdisk with backup" | ||||
|       ./magiskboot --cpio-restore ramdisk.cpio | ||||
|       ./magiskboot --repack $BOOTIMAGE stock_boot.img | ||||
|     fi | ||||
|     ;; | ||||
|   2 ) # Other patched | ||||
|     ui_print_wrap "! Boot image patched by other programs!" | ||||
|     abort_wrap "! Cannot uninstall with this uninstaller" | ||||
|     ;; | ||||
| esac | ||||
|  | ||||
| # Sign chromeos boot | ||||
| if $CHROMEOS; then | ||||
|   echo > empty | ||||
|  | ||||
|   ./chromeos/futility vbutil_kernel --pack stock_boot.img.signed \ | ||||
|   --keyblock ./chromeos/kernel.keyblock --signprivate ./chromeos/kernel_data_key.vbprivk \ | ||||
|   --version 1 --vmlinuz stock_boot.img --config empty --arch arm --bootloader empty --flags 0x1 | ||||
|  | ||||
|   rm -f empty stock_boot.img | ||||
|   mv stock_boot.img.signed stock_boot.img | ||||
| fi | ||||
|  | ||||
| ui_print_wrap "- Flashing stock/reverted image" | ||||
| if [ -L "$BOOTIMAGE" ]; then | ||||
|   dd if=stock_boot.img of="$BOOTIMAGE" bs=4096 | ||||
| else | ||||
|   cat stock_boot.img /dev/zero | dd of="$BOOTIMAGE" bs=4096 >/dev/null 2>&1 | ||||
| fi | ||||
| rm -f stock_boot.img | ||||
|  | ||||
| ui_print_wrap "- Removing Magisk files" | ||||
| rm -rf  /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \ | ||||
|         /cache/magisk /cache/magisk_merge /cache/magisk_mount  /cache/unblock /cache/magisk_uninstaller.sh \ | ||||
|         /data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img /data/magisk_debug.log \ | ||||
|         /data/busybox /data/magisk /data/custom_ramdisk_patch.sh /data/property/*magisk* \ | ||||
|         /data/app/com.topjohnwu.magisk* /data/user/*/com.topjohnwu.magisk 2>/dev/null | ||||
|  | ||||
| $BOOTMODE && reboot | ||||
										
											Binary file not shown.
										
									
								
							| @@ -1,27 +0,0 @@ | ||||
| -----BEGIN CERTIFICATE----- | ||||
| MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD | ||||
| VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g | ||||
| VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE | ||||
| AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe | ||||
| Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET | ||||
| MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G | ||||
| A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p | ||||
| ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI | ||||
| hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM | ||||
| qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 | ||||
| wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy | ||||
| 4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU | ||||
| RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s | ||||
| zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw | ||||
| HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ | ||||
| AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE | ||||
| CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH | ||||
| QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG | ||||
| CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud | ||||
| EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa | ||||
| J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y | ||||
| LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe | ||||
| +ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX | ||||
| 31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr | ||||
| sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0= | ||||
| -----END CERTIFICATE----- | ||||
| @@ -1,192 +0,0 @@ | ||||
| ########################################################################################## | ||||
| #  | ||||
| # Magisk General Utility Functions | ||||
| # by topjohnwu | ||||
| #  | ||||
| # Used in flash_script.sh, addon.d.sh, magisk module installers, and uninstaller | ||||
| #  | ||||
| ########################################################################################## | ||||
|  | ||||
| get_outfd() { | ||||
|   readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null | ||||
|   if [ "$?" -eq "0" ]; then | ||||
|     OUTFD=0 | ||||
|  | ||||
|     for FD in `ls /proc/$$/fd`; do | ||||
|       readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null | ||||
|       if [ "$?" -eq "0" ]; then | ||||
|         ps | grep " 3 $FD " | grep -v grep >/dev/null | ||||
|         if [ "$?" -eq "0" ]; then | ||||
|           OUTFD=$FD | ||||
|           break | ||||
|         fi | ||||
|       fi | ||||
|     done | ||||
|   fi | ||||
| } | ||||
|  | ||||
| ui_print() { | ||||
|   if $BOOTMODE; then | ||||
|     echo "$1" | ||||
|   else  | ||||
|     echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD | ||||
|     echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD | ||||
|   fi | ||||
| } | ||||
|  | ||||
| getvar() { | ||||
|   local VARNAME=$1 | ||||
|   local VALUE=$(eval echo \$"$VARNAME"); | ||||
|   for FILE in /dev/.magisk /data/.magisk /cache/.magisk /system/.magisk; do | ||||
|     if [ -z "$VALUE" ]; then | ||||
|       LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=") | ||||
|       if [ ! -z "$LINE" ]; then | ||||
|         VALUE=${LINE#*=} | ||||
|       fi | ||||
|     fi | ||||
|   done | ||||
|   eval $VARNAME=\$VALUE | ||||
| } | ||||
|  | ||||
| find_boot_image() { | ||||
|   if [ -z "$BOOTIMAGE" ]; then | ||||
|     for BLOCK in boot_a BOOT_A kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do | ||||
|       BOOTIMAGE=`ls /dev/block/by-name/$BLOCK || ls /dev/block/platform/*/by-name/$BLOCK || ls /dev/block/platform/*/*/by-name/$BLOCK` 2>/dev/null | ||||
|       [ ! -z $BOOTIMAGE ] && break | ||||
|     done | ||||
|   fi | ||||
|   # Recovery fallback | ||||
|   if [ -z "$BOOTIMAGE" ]; then | ||||
|     for FSTAB in /etc/*fstab*; do | ||||
|       BOOTIMAGE=`grep -E '\b/boot\b' $FSTAB | grep -v "#" | grep -oE '/dev/[a-zA-Z0-9_./-]*'` | ||||
|       [ ! -z $BOOTIMAGE ] && break | ||||
|     done | ||||
|   fi | ||||
|   [ -L "$BOOTIMAGE" ] && BOOTIMAGE=`readlink $BOOTIMAGE` | ||||
| } | ||||
|  | ||||
| is_mounted() { | ||||
|   if [ ! -z "$2" ]; then | ||||
|     cat /proc/mounts | grep $1 | grep $2, >/dev/null | ||||
|   else | ||||
|     cat /proc/mounts | grep $1 >/dev/null | ||||
|   fi | ||||
|   return $? | ||||
| } | ||||
|  | ||||
| grep_prop() { | ||||
|   REGEX="s/^$1=//p" | ||||
|   shift | ||||
|   FILES=$@ | ||||
|   if [ -z "$FILES" ]; then | ||||
|     FILES='/system/build.prop' | ||||
|   fi | ||||
|   cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1 | ||||
| } | ||||
|  | ||||
| remove_system_su() { | ||||
|   if [ -f /system/bin/su -o -f /system/xbin/su ] && [ ! -f /su/bin/su ]; then | ||||
|     ui_print "! System installed root detected, mount rw :(" | ||||
|     mount -o rw,remount /system | ||||
|     # SuperSU | ||||
|     if [ -e /system/bin/.ext/.su ]; then | ||||
|       mv -f /system/bin/app_process32_original /system/bin/app_process32 2>/dev/null | ||||
|       mv -f /system/bin/app_process64_original /system/bin/app_process64 2>/dev/null | ||||
|       mv -f /system/bin/install-recovery_original.sh /system/bin/install-recovery.sh 2>/dev/null | ||||
|       cd /system/bin | ||||
|       if [ -e app_process64 ]; then | ||||
|         ln -sf app_process64 app_process | ||||
|       else | ||||
|         ln -sf app_process32 app_process | ||||
|       fi | ||||
|     fi | ||||
|     rm -rf /system/.pin /system/bin/.ext /system/etc/.installed_su_daemon /system/etc/.has_su_daemon \ | ||||
|     /system/xbin/daemonsu /system/xbin/su /system/xbin/sugote /system/xbin/sugote-mksh /system/xbin/supolicy \ | ||||
|     /system/bin/app_process_init /system/bin/su /cache/su /system/lib/libsupol.so /system/lib64/libsupol.so \ | ||||
|     /system/su.d /system/etc/install-recovery.sh /system/etc/init.d/99SuperSUDaemon /cache/install-recovery.sh \ | ||||
|     /system/.supersu /cache/.supersu /data/.supersu \ | ||||
|     /system/app/Superuser.apk /system/app/SuperSU /cache/Superuser.apk  2>/dev/null | ||||
|   fi | ||||
| } | ||||
|  | ||||
| api_level_arch_detect() { | ||||
|   API=`grep_prop ro.build.version.sdk` | ||||
|   ABI=`grep_prop ro.product.cpu.abi | cut -c-3` | ||||
|   ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3` | ||||
|   ABILONG=`grep_prop ro.product.cpu.abi` | ||||
|  | ||||
|   ARCH=arm | ||||
|   IS64BIT=false | ||||
|   if [ "$ABI" = "x86" ]; then ARCH=x86; fi; | ||||
|   if [ "$ABI2" = "x86" ]; then ARCH=x86; fi; | ||||
|   if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi; | ||||
|   if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi; | ||||
| } | ||||
|  | ||||
| recovery_actions() { | ||||
|   # TWRP bug fix | ||||
|   mount -o bind /dev/urandom /dev/random | ||||
|   # Temporarily block out all custom recovery binaries/libs | ||||
|   mv /sbin /sbin_tmp | ||||
|   # Add all possible library paths | ||||
|   OLD_LD_PATH=$LD_LIBRARY_PATH | ||||
|   $IS64BIT && export LD_LIBRARY_PATH=/system/lib64:/system/vendor/lib64 || export LD_LIBRARY_PATH=/system/lib:/system/vendor/lib | ||||
| } | ||||
|  | ||||
| recovery_cleanup() { | ||||
|   mv /sbin_tmp /sbin | ||||
|   # Clear LD_LIBRARY_PATH | ||||
|   export LD_LIBRARY_PATH=$OLD_LD_PATH | ||||
|   ui_print "- Unmounting partitions" | ||||
|   umount -l /system | ||||
|   umount -l /vendor 2>/dev/null | ||||
|   umount -l /dev/random | ||||
| } | ||||
|  | ||||
| abort() { | ||||
|   ui_print "$1" | ||||
|   mv /sbin_tmp /sbin 2>/dev/null | ||||
|   exit 1 | ||||
| } | ||||
|  | ||||
| set_perm() { | ||||
|   chown $2:$3 $1 || exit 1 | ||||
|   chmod $4 $1 || exit 1 | ||||
|   if [ ! -z $5 ]; then | ||||
|     chcon $5 $1 2>/dev/null | ||||
|   else | ||||
|     chcon 'u:object_r:system_file:s0' $1 2>/dev/null | ||||
|   fi | ||||
| } | ||||
|  | ||||
| set_perm_recursive() { | ||||
|   find $1 -type d 2>/dev/null | while read dir; do | ||||
|     set_perm $dir $2 $3 $4 $6 | ||||
|   done | ||||
|   find $1 -type f 2>/dev/null | while read file; do | ||||
|     set_perm $file $2 $3 $5 $6 | ||||
|   done | ||||
| } | ||||
|  | ||||
| mktouch() { | ||||
|   mkdir -p ${1%/*} | ||||
|   if [ -z "$2" ]; then | ||||
|     touch $1 | ||||
|   else | ||||
|     echo $2 > $1 | ||||
|   fi | ||||
|   chmod 644 $1 | ||||
| } | ||||
|  | ||||
| request_size_check() { | ||||
|   reqSizeM=`du -s $1 | cut -f1` | ||||
|   reqSizeM=$((reqSizeM / 1024 + 1)) | ||||
| } | ||||
|  | ||||
| image_size_check() { | ||||
|   SIZE="`$MAGISKBIN/magisk --imgsize $IMG`" | ||||
|   curUsedM=`echo "$SIZE" | cut -d" " -f1` | ||||
|   curSizeM=`echo "$SIZE" | cut -d" " -f2` | ||||
|   curFreeM=$((curSizeM - curUsedM)) | ||||
| } | ||||
|  | ||||
| @@ -29,6 +29,8 @@ public class LogFragment extends Fragment { | ||||
|         View v = inflater.inflate(R.layout.fragment_log, container, false); | ||||
|         unbinder = ButterKnife.bind(this, v); | ||||
|  | ||||
|         ((MainActivity) getActivity()).toolbar.setElevation(0); | ||||
|  | ||||
|         TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager()); | ||||
|  | ||||
|         if (getApplication().isSuClient) { | ||||
|   | ||||
| @@ -31,8 +31,8 @@ import com.topjohnwu.magisk.components.AlertDialogBuilder; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.components.SnackbarMaker; | ||||
| import com.topjohnwu.magisk.receivers.DownloadReceiver; | ||||
| import com.topjohnwu.magisk.utils.CallbackEvent; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| import com.topjohnwu.magisk.utils.Topic; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
|  | ||||
| import java.io.File; | ||||
| @@ -49,7 +49,7 @@ import butterknife.OnClick; | ||||
| import butterknife.Unbinder; | ||||
|  | ||||
| public class MagiskFragment extends Fragment | ||||
|         implements CallbackEvent.Listener<Void>, SwipeRefreshLayout.OnRefreshListener { | ||||
|         implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener { | ||||
|  | ||||
|     public static final String SHOW_DIALOG = "dialog"; | ||||
|  | ||||
| @@ -142,7 +142,7 @@ public class MagiskFragment extends Fragment | ||||
|                                 @Override | ||||
|                                 public void onDownloadDone(Uri uri) { | ||||
|                                     if (Shell.rootAccess()) { | ||||
|                                         magiskManager.shell.su_raw( | ||||
|                                         Shell.getShell(getActivity()).su_raw( | ||||
|                                                 "rm -f /dev/.magisk", | ||||
|                                                 "echo \"BOOTIMAGE=" + boot + "\" >> /dev/.magisk", | ||||
|                                                 "echo \"KEEPFORCEENCRYPT=" + String.valueOf(enc) + "\" >> /dev/.magisk", | ||||
| @@ -206,7 +206,7 @@ public class MagiskFragment extends Fragment | ||||
|                             @Override | ||||
|                             public void onFinish() { | ||||
|                                 progress.setMessage(getString(R.string.reboot_countdown, 0)); | ||||
|                                 magiskManager.shell.su_raw( | ||||
|                                 Shell.getShell(getActivity()).su_raw( | ||||
|                                         "mv -f " + uninstaller + " /cache/" + MagiskManager.UNINSTALLER, | ||||
|                                         "mv -f " + utils + " /data/magisk/" + MagiskManager.UTIL_FUNCTIONS, | ||||
|                                         "reboot" | ||||
| @@ -253,11 +253,14 @@ public class MagiskFragment extends Fragment | ||||
|         if (getArguments() != null && getArguments().getBoolean(SHOW_DIALOG)) | ||||
|             install(); | ||||
|  | ||||
|         getActivity().setTitle(R.string.magisk); | ||||
|  | ||||
|         return v; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onRefresh() { | ||||
|         magiskManager.getMagiskInfo(); | ||||
|         updateUI(); | ||||
|  | ||||
|         magiskUpdateText.setText(R.string.checking_for_updates); | ||||
| @@ -266,8 +269,8 @@ public class MagiskFragment extends Fragment | ||||
|  | ||||
|         safetyNetStatusText.setText(R.string.safetyNet_check_text); | ||||
|  | ||||
|         magiskManager.safetyNetDone.isTriggered = false; | ||||
|         magiskManager.updateCheckDone.isTriggered = false; | ||||
|         magiskManager.safetyNetDone.hasPublished = false; | ||||
|         magiskManager.updateCheckDone.hasPublished = false; | ||||
|         magiskManager.remoteMagiskVersionString = null; | ||||
|         magiskManager.remoteMagiskVersionCode = -1; | ||||
|         collapse(); | ||||
| @@ -281,32 +284,17 @@ public class MagiskFragment extends Fragment | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTrigger(CallbackEvent<Void> event) { | ||||
|         if (event == magiskManager.updateCheckDone) { | ||||
|     public void onTopicPublished(Topic topic) { | ||||
|         if (topic == magiskManager.updateCheckDone) { | ||||
|             updateCheckUI(); | ||||
|         } else if (event == magiskManager.safetyNetDone) { | ||||
|         } else if (topic == magiskManager.safetyNetDone) { | ||||
|             updateSafetyNetUI(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|         // Manual trigger if already done | ||||
|         if (magiskManager.updateCheckDone.isTriggered) | ||||
|             updateCheckUI(); | ||||
|         if (magiskManager.safetyNetDone.isTriggered) | ||||
|             updateSafetyNetUI(); | ||||
|         magiskManager.updateCheckDone.register(this); | ||||
|         magiskManager.safetyNetDone.register(this); | ||||
|         getActivity().setTitle(R.string.magisk); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStop() { | ||||
|         magiskManager.updateCheckDone.unRegister(this); | ||||
|         magiskManager.safetyNetDone.unRegister(this); | ||||
|         super.onStop(); | ||||
|     public Topic[] getSubscription() { | ||||
|         return new Topic[] { magiskManager.updateCheckDone, magiskManager.safetyNetDone }; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -317,7 +305,6 @@ public class MagiskFragment extends Fragment | ||||
|  | ||||
|     private void updateUI() { | ||||
|         ((MainActivity) getActivity()).checkHideSection(); | ||||
|         magiskManager.updateMagiskInfo(); | ||||
|  | ||||
|         final int ROOT = 0x1, NETWORK = 0x2, UPTODATE = 0x4; | ||||
|         int status = 0; | ||||
|   | ||||
| @@ -1,12 +1,9 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.content.pm.PackageManager; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v4.view.MenuItemCompat; | ||||
| import android.support.v4.widget.SwipeRefreshLayout; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.text.TextUtils; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuInflater; | ||||
| @@ -15,16 +12,14 @@ import android.view.ViewGroup; | ||||
| import android.widget.SearchView; | ||||
|  | ||||
| import com.topjohnwu.magisk.adapters.ApplicationAdapter; | ||||
| import com.topjohnwu.magisk.asyncs.MagiskHide; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.utils.CallbackEvent; | ||||
| import com.topjohnwu.magisk.utils.Logger; | ||||
| import com.topjohnwu.magisk.utils.Topic; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| import butterknife.Unbinder; | ||||
|  | ||||
| public class MagiskHideFragment extends Fragment implements CallbackEvent.Listener<Void> { | ||||
| public class MagiskHideFragment extends Fragment implements Topic.Subscriber { | ||||
|  | ||||
|     private Unbinder unbinder; | ||||
|     @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; | ||||
| @@ -46,13 +41,12 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen | ||||
|     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { | ||||
|         View view = inflater.inflate(R.layout.fragment_magisk_hide, container, false); | ||||
|         unbinder = ButterKnife.bind(this, view); | ||||
|  | ||||
|         PackageManager packageManager = getActivity().getPackageManager(); | ||||
|         lastFilter = ""; | ||||
|  | ||||
|         mSwipeRefreshLayout.setRefreshing(true); | ||||
|         mSwipeRefreshLayout.setOnRefreshListener(() -> new MagiskHide(getActivity()).list()); | ||||
|         mSwipeRefreshLayout.setOnRefreshListener(() -> appAdapter.refresh()); | ||||
|  | ||||
|         appAdapter = new ApplicationAdapter(packageManager); | ||||
|         appAdapter = new ApplicationAdapter(getActivity()); | ||||
|         recyclerView.setAdapter(appAdapter); | ||||
|  | ||||
|         searchListener = new SearchView.OnQueryTextListener() { | ||||
| @@ -71,9 +65,7 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         if (getApplication().magiskHideDone.isTriggered) { | ||||
|             onTrigger(getApplication().magiskHideDone); | ||||
|         } | ||||
|         getActivity().setTitle(R.string.magiskhide); | ||||
|  | ||||
|         return view; | ||||
|     } | ||||
| @@ -81,23 +73,10 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen | ||||
|     @Override | ||||
|     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { | ||||
|         inflater.inflate(R.menu.menu_magiskhide, menu); | ||||
|         SearchView search = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.app_search)); | ||||
|         SearchView search = (SearchView) menu.findItem(R.id.app_search).getActionView(); | ||||
|         search.setOnQueryTextListener(searchListener); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|         getActivity().setTitle(R.string.magiskhide); | ||||
|         getApplication().magiskHideDone.register(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStop() { | ||||
|         getApplication().magiskHideDone.unRegister(this); | ||||
|         super.onStop(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroyView() { | ||||
|         super.onDestroyView(); | ||||
| @@ -105,12 +84,13 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTrigger(CallbackEvent<Void> event) { | ||||
|         Logger.dev("MagiskHideFragment: UI refresh"); | ||||
|         appAdapter.setLists(getApplication().appList, getApplication().magiskHideList); | ||||
|     public void onTopicPublished(Topic topic) { | ||||
|         mSwipeRefreshLayout.setRefreshing(false); | ||||
|         if (!TextUtils.isEmpty(lastFilter)) { | ||||
|             appAdapter.filter(lastFilter); | ||||
|         } | ||||
|         appAdapter.filter(lastFilter); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Topic[] getSubscription() { | ||||
|         return new Topic[] { getApplication().magiskHideDone }; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -135,11 +135,11 @@ public class MagiskLogFragment extends Fragment { | ||||
|             switch (mode) { | ||||
|                 case 0: | ||||
|                     StringBuildingList logList = new StringBuildingList(); | ||||
|                     magiskManager.shell.su(logList, "cat " + MAGISK_LOG); | ||||
|                     Shell.getShell(magiskManager).su(logList, "cat " + MAGISK_LOG); | ||||
|                     return logList.toString(); | ||||
|  | ||||
|                 case 1: | ||||
|                     magiskManager.shell.su_raw("echo > " + MAGISK_LOG); | ||||
|                     Shell.getShell(magiskManager).su_raw("echo > " + MAGISK_LOG); | ||||
|                     SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show(); | ||||
|                     return ""; | ||||
|  | ||||
| @@ -160,7 +160,7 @@ public class MagiskLogFragment extends Fragment { | ||||
|  | ||||
|                     try (FileWriter out = new FileWriter(targetFile)) { | ||||
|                         FileWritingList fileWritingList = new FileWritingList(out); | ||||
|                         magiskManager.shell.su(fileWritingList, "cat " + MAGISK_LOG); | ||||
|                         Shell.getShell(magiskManager).su(fileWritingList, "cat " + MAGISK_LOG); | ||||
|                     } catch (IOException e) { | ||||
|                         e.printStackTrace(); | ||||
|                         return false; | ||||
|   | ||||
| @@ -5,24 +5,27 @@ import android.app.NotificationChannel; | ||||
| import android.app.NotificationManager; | ||||
| import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.res.Configuration; | ||||
| import android.content.res.Resources; | ||||
| import android.os.Build; | ||||
| import android.os.Handler; | ||||
| import android.preference.PreferenceManager; | ||||
| import android.text.TextUtils; | ||||
| import android.widget.Toast; | ||||
|  | ||||
| import com.topjohnwu.magisk.asyncs.DownloadBusybox; | ||||
| import com.topjohnwu.magisk.asyncs.ParallelTask; | ||||
| import com.topjohnwu.magisk.database.RepoDatabaseHelper; | ||||
| import com.topjohnwu.magisk.database.SuDatabaseHelper; | ||||
| import com.topjohnwu.magisk.module.Module; | ||||
| import com.topjohnwu.magisk.module.Repo; | ||||
| import com.topjohnwu.magisk.utils.CallbackEvent; | ||||
| import com.topjohnwu.magisk.utils.SafetyNetHelper; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| import com.topjohnwu.magisk.utils.Topic; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
| import com.topjohnwu.magisk.utils.ValueSortedMap; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class MagiskManager extends Application { | ||||
|  | ||||
| @@ -34,18 +37,19 @@ public class MagiskManager extends Application { | ||||
|     public static final String INTENT_SECTION = "section"; | ||||
|     public static final String INTENT_VERSION = "version"; | ||||
|     public static final String INTENT_LINK = "link"; | ||||
|     public static final String BUSYBOX_VERSION = "1.26.2"; | ||||
|     public static final String MAGISKHIDE_PROP = "persist.magisk.hide"; | ||||
|     public static final String DISABLE_INDICATION_PROP = "ro.magisk.disable"; | ||||
|     public static final String NOTIFICATION_CHANNEL = "magisk_update_notice"; | ||||
|     public static final String BUSYBOX_VERSION = "1.27.1"; | ||||
|  | ||||
|     // Events | ||||
|     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<>(); | ||||
|     // Topics | ||||
|     public final Topic magiskHideDone = new Topic(); | ||||
|     public final Topic reloadActivity = new Topic(); | ||||
|     public final Topic moduleLoadDone = new Topic(); | ||||
|     public final Topic repoLoadDone = new Topic(); | ||||
|     public final Topic updateCheckDone = new Topic(); | ||||
|     public final Topic safetyNetDone = new Topic(); | ||||
|     public final Topic localeDone = new Topic(); | ||||
|  | ||||
|     // Info | ||||
|     public String magiskVersionString; | ||||
| @@ -64,15 +68,15 @@ public class MagiskManager extends Application { | ||||
|     public boolean disabled; | ||||
|  | ||||
|     // Data | ||||
|     public ValueSortedMap<String, Repo> repoMap; | ||||
|     public ValueSortedMap<String, Module> moduleMap; | ||||
|     public Map<String, Module> moduleMap; | ||||
|     public List<String> blockList; | ||||
|     public List<ApplicationInfo> appList; | ||||
|     public List<String> magiskHideList; | ||||
|     public List<Locale> locales; | ||||
|  | ||||
|     // Configurations | ||||
|     public static boolean shellLogging; | ||||
|     public static boolean devLogging; | ||||
|     public static Locale locale; | ||||
|     public static Locale defaultLocale; | ||||
|  | ||||
|     public boolean magiskHide; | ||||
|     public boolean isDarkTheme; | ||||
| @@ -89,16 +93,76 @@ public class MagiskManager extends Application { | ||||
|     // Global resources | ||||
|     public SharedPreferences prefs; | ||||
|     public SuDatabaseHelper suDB; | ||||
|     public RepoDatabaseHelper repoDB; | ||||
|     public Shell shell; | ||||
|  | ||||
|     private static Handler mHandler = new Handler(); | ||||
|  | ||||
|     private static class LoadLocale extends ParallelTask<Void, Void, Void> { | ||||
|  | ||||
|         LoadLocale(Context context) { | ||||
|             super(context); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected Void doInBackground(Void... voids) { | ||||
|             getMagiskManager().locales = Utils.getAvailableLocale(getMagiskManager()); | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected void onPostExecute(Void aVoid) { | ||||
|             getMagiskManager().localeDone.publish(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         new File(getApplicationInfo().dataDir).mkdirs();  /* Create the app data directory */ | ||||
|         prefs = PreferenceManager.getDefaultSharedPreferences(this); | ||||
|         shell = Shell.getShell(); | ||||
|         suDB = new SuDatabaseHelper(this); | ||||
|         repoDB = new RepoDatabaseHelper(this); | ||||
|         loadConfig(); | ||||
|     } | ||||
|  | ||||
|     public void setLocale() { | ||||
|         String localeTag = prefs.getString("locale", ""); | ||||
|         if (localeTag.isEmpty()) { | ||||
|             locale = defaultLocale; | ||||
|         } else { | ||||
|             locale = Locale.forLanguageTag(localeTag); | ||||
|         } | ||||
|         Resources res = getBaseContext().getResources(); | ||||
|         Configuration config = new Configuration(res.getConfiguration()); | ||||
|         config.setLocale(locale); | ||||
|         res.updateConfiguration(config, res.getDisplayMetrics()); | ||||
|     } | ||||
|  | ||||
|     private void loadConfig() { | ||||
|         // Locale | ||||
|         defaultLocale = Locale.getDefault(); | ||||
|         setLocale(); | ||||
|  | ||||
|         isDarkTheme = prefs.getBoolean("dark_theme", false); | ||||
|         if (BuildConfig.DEBUG) { | ||||
|             devLogging = prefs.getBoolean("developer_logging", false); | ||||
|             shellLogging = prefs.getBoolean("shell_logging", false); | ||||
|         } else { | ||||
|             devLogging = false; | ||||
|             shellLogging = false; | ||||
|         } | ||||
|  | ||||
|         // su | ||||
|         suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10); | ||||
|         suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0); | ||||
|         suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1); | ||||
|         suReauth = prefs.getBoolean("su_reauth", false); | ||||
|         suAccessState = suDB.getSettings(SuDatabaseHelper.ROOT_ACCESS, 3); | ||||
|         multiuserMode = suDB.getSettings(SuDatabaseHelper.MULTIUSER_MODE, 0); | ||||
|         suNamespaceMode = suDB.getSettings(SuDatabaseHelper.MNT_NS, 1); | ||||
|  | ||||
|         updateNotification = prefs.getBoolean("notification", true); | ||||
|     } | ||||
|  | ||||
|     public void toast(String msg, int duration) { | ||||
| @@ -110,29 +174,12 @@ public class MagiskManager extends Application { | ||||
|     } | ||||
|  | ||||
|     public void init() { | ||||
|         isDarkTheme = prefs.getBoolean("dark_theme", false); | ||||
|         if (BuildConfig.DEBUG) { | ||||
|             devLogging = prefs.getBoolean("developer_logging", false); | ||||
|             shellLogging = prefs.getBoolean("shell_logging", false); | ||||
|         } else { | ||||
|             devLogging = false; | ||||
|             shellLogging = false; | ||||
|         } | ||||
|         magiskHide = prefs.getBoolean("magiskhide", true); | ||||
|         initSU(); | ||||
|         updateMagiskInfo(); | ||||
|         new LoadLocale(this).exec(); | ||||
|         new DownloadBusybox(this).exec(); | ||||
|         getMagiskInfo(); | ||||
|         updateBlockInfo(); | ||||
|         // Initialize busybox | ||||
|         File busybox = new File(getApplicationInfo().dataDir + "/busybox/busybox"); | ||||
|         if (!busybox.exists() || !TextUtils.equals(prefs.getString("busybox_version", ""), BUSYBOX_VERSION)) { | ||||
|             busybox.getParentFile().mkdirs(); | ||||
|             shell.su_raw( | ||||
|                     "cp -f " + new File(getApplicationInfo().nativeLibraryDir, "libbusybox.so") + " " + busybox, | ||||
|                     "chmod -R 755 " + busybox.getParent(), | ||||
|                     busybox + " --install -s " + busybox.getParent() | ||||
|             ); | ||||
|         } | ||||
|         // Initialize prefs | ||||
|  | ||||
|         // Write back default values | ||||
|         prefs.edit() | ||||
|                 .putBoolean("dark_theme", isDarkTheme) | ||||
|                 .putBoolean("magiskhide", magiskHide) | ||||
| @@ -148,8 +195,9 @@ public class MagiskManager extends Application { | ||||
|                 .putString("mnt_ns", String.valueOf(suNamespaceMode)) | ||||
|                 .putString("busybox_version", BUSYBOX_VERSION) | ||||
|                 .apply(); | ||||
|  | ||||
|         // Add busybox to PATH | ||||
|         shell.su_raw("PATH=$PATH:" + busybox.getParent()); | ||||
|         shell.su_raw("PATH=" + getApplicationInfo().dataDir + "/busybox:$PATH"); | ||||
|  | ||||
|         // Create notification channel on Android O | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
| @@ -160,32 +208,14 @@ public class MagiskManager extends Application { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void initSUConfig() { | ||||
|         suDB = new SuDatabaseHelper(this); | ||||
|         suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10); | ||||
|         suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0); | ||||
|         suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1); | ||||
|         suReauth = prefs.getBoolean("su_reauth", false); | ||||
|     } | ||||
|  | ||||
|     public void initSU() { | ||||
|         initSUConfig(); | ||||
|  | ||||
|         List<String> ret = shell.sh("su -v"); | ||||
|     public void getMagiskInfo() { | ||||
|         Shell.getShell(this); | ||||
|         List<String> ret; | ||||
|         ret = shell.sh("su -v"); | ||||
|         if (Utils.isValidShellResponse(ret)) { | ||||
|             suVersion = ret.get(0); | ||||
|             isSuClient = suVersion.toUpperCase().contains("MAGISK"); | ||||
|         } | ||||
|         if (isSuClient) { | ||||
|             suAccessState = suDB.getSettings(SuDatabaseHelper.ROOT_ACCESS, 3); | ||||
|             multiuserMode = suDB.getSettings(SuDatabaseHelper.MULTIUSER_MODE, 0); | ||||
|             suNamespaceMode = suDB.getSettings(SuDatabaseHelper.MNT_NS, 1); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void updateMagiskInfo() { | ||||
|         updateNotification = prefs.getBoolean("notification", true); | ||||
|         List<String> ret; | ||||
|         ret = shell.sh("magisk -v"); | ||||
|         if (!Utils.isValidShellResponse(ret)) { | ||||
|             ret = shell.sh("getprop magisk.version"); | ||||
| @@ -216,11 +246,11 @@ public class MagiskManager extends Application { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void updateBlockInfo() { | ||||
|     private void updateBlockInfo() { | ||||
|         List<String> res = shell.su( | ||||
|                 "for BLOCK in boot_a BOOT_A kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do", | ||||
|                 "BOOTIMAGE=`ls /dev/block/by-name/$BLOCK || ls /dev/block/platform/*/by-name/$BLOCK || ls /dev/block/platform/*/*/by-name/$BLOCK` 2>/dev/null", | ||||
|                 "[ ! -z \"$BOOTIMAGE\" ] && break", | ||||
|                 "for BLOCK in boot_a kern-a android_boot kernel boot lnx; do", | ||||
|                 "  BOOTIMAGE=`find /dev/block -iname $BLOCK | head -n 1` 2>/dev/null", | ||||
|                 "  [ ! -z $BOOTIMAGE ] && break", | ||||
|                 "done", | ||||
|                 "[ ! -z \"$BOOTIMAGE\" -a -L \"$BOOTIMAGE\" ] && BOOTIMAGE=`readlink $BOOTIMAGE`", | ||||
|                 "echo \"$BOOTIMAGE\"" | ||||
|   | ||||
| @@ -20,15 +20,15 @@ import android.view.MenuItem; | ||||
| import android.view.View; | ||||
|  | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
| import com.topjohnwu.magisk.utils.CallbackEvent; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| import com.topjohnwu.magisk.utils.Topic; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
|  | ||||
| public class MainActivity extends Activity | ||||
|         implements NavigationView.OnNavigationItemSelectedListener, CallbackEvent.Listener<Void> { | ||||
|         implements NavigationView.OnNavigationItemSelectedListener, Topic.Subscriber { | ||||
|  | ||||
|     private final Handler mDrawerHandler = new Handler(); | ||||
|     private SharedPreferences prefs; | ||||
| @@ -81,7 +81,6 @@ public class MainActivity extends Activity | ||||
|             navigate(getIntent().getStringExtra(MagiskManager.INTENT_SECTION)); | ||||
|  | ||||
|         navigationView.setNavigationItemSelectedListener(this); | ||||
|         getApplicationContext().reloadMainActivity.register(this); | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -91,12 +90,6 @@ public class MainActivity extends Activity | ||||
|         checkHideSection(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         getApplicationContext().reloadMainActivity.unRegister(this); | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBackPressed() { | ||||
|         if (drawer.isDrawerOpen(navigationView)) { | ||||
| @@ -117,10 +110,15 @@ public class MainActivity extends Activity | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTrigger(CallbackEvent<Void> event) { | ||||
|     public void onTopicPublished(Topic topic) { | ||||
|         recreate(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Topic[] getSubscription() { | ||||
|         return new Topic[] { getApplicationContext().reloadActivity }; | ||||
|     } | ||||
|  | ||||
|     public void checkHideSection() { | ||||
|         Menu menu = navigationView.getMenu(); | ||||
|         menu.findItem(R.id.magiskhide).setVisible( | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import android.app.Activity; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.design.widget.FloatingActionButton; | ||||
| import android.support.v4.widget.SwipeRefreshLayout; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.view.LayoutInflater; | ||||
| @@ -16,17 +15,18 @@ import com.topjohnwu.magisk.adapters.ModulesAdapter; | ||||
| import com.topjohnwu.magisk.asyncs.LoadModules; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.module.Module; | ||||
| import com.topjohnwu.magisk.utils.CallbackEvent; | ||||
| import com.topjohnwu.magisk.utils.Logger; | ||||
| import com.topjohnwu.magisk.utils.Topic; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| import butterknife.OnClick; | ||||
| import butterknife.Unbinder; | ||||
|  | ||||
| public class ModulesFragment extends Fragment implements CallbackEvent.Listener<Void> { | ||||
| public class ModulesFragment extends Fragment implements Topic.Subscriber { | ||||
|  | ||||
|     private static final int FETCH_ZIP_CODE = 2; | ||||
|  | ||||
| @@ -34,7 +34,12 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener< | ||||
|     @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; | ||||
|     @BindView(R.id.recyclerView) RecyclerView recyclerView; | ||||
|     @BindView(R.id.empty_rv) TextView emptyRv; | ||||
|     @BindView(R.id.fab) FloatingActionButton fabio; | ||||
|     @OnClick(R.id.fab) | ||||
|     public void selectFile() { | ||||
|         Intent intent = new Intent(Intent.ACTION_GET_CONTENT); | ||||
|         intent.setType("application/zip"); | ||||
|         startActivityForResult(intent, FETCH_ZIP_CODE); | ||||
|     } | ||||
|  | ||||
|     private List<Module> listModules = new ArrayList<>(); | ||||
|  | ||||
| @@ -44,12 +49,6 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener< | ||||
|         View view = inflater.inflate(R.layout.fragment_modules, container, false); | ||||
|         unbinder = ButterKnife.bind(this, view); | ||||
|  | ||||
|         fabio.setOnClickListener(v -> { | ||||
|             Intent intent = new Intent(Intent.ACTION_GET_CONTENT); | ||||
|             intent.setType("application/zip"); | ||||
|             startActivityForResult(intent, FETCH_ZIP_CODE); | ||||
|         }); | ||||
|  | ||||
|         mSwipeRefreshLayout.setOnRefreshListener(() -> { | ||||
|             recyclerView.setVisibility(View.GONE); | ||||
|             new LoadModules(getActivity()).exec(); | ||||
| @@ -67,19 +66,22 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener< | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         if (getApplication().moduleLoadDone.isTriggered) { | ||||
|             updateUI(); | ||||
|         } | ||||
|         getActivity().setTitle(R.string.modules); | ||||
|  | ||||
|         return view; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTrigger(CallbackEvent<Void> event) { | ||||
|     public void onTopicPublished(Topic topic) { | ||||
|         Logger.dev("ModulesFragment: UI refresh triggered"); | ||||
|         updateUI(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Topic[] getSubscription() { | ||||
|         return new Topic[] { getApplication().moduleLoadDone }; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onActivityResult(int requestCode, int resultCode, Intent data) { | ||||
|         if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) { | ||||
| @@ -88,20 +90,6 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener< | ||||
|             intent.setData(data.getData()).putExtra("ACTION", "flash"); | ||||
|             startActivity(intent); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|         getApplication().moduleLoadDone.register(this); | ||||
|         getActivity().setTitle(R.string.modules); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStop() { | ||||
|         getApplication().moduleLoadDone.unRegister(this); | ||||
|         super.onStop(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -13,16 +13,16 @@ import android.widget.SearchView; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.adapters.ReposAdapter; | ||||
| import com.topjohnwu.magisk.asyncs.LoadRepos; | ||||
| import com.topjohnwu.magisk.asyncs.UpdateRepos; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.utils.CallbackEvent; | ||||
| import com.topjohnwu.magisk.utils.Logger; | ||||
| import com.topjohnwu.magisk.utils.Topic; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| import butterknife.Unbinder; | ||||
|  | ||||
| public class ReposFragment extends Fragment implements CallbackEvent.Listener<Void> { | ||||
| public class ReposFragment extends Fragment implements Topic.Subscriber { | ||||
|  | ||||
|     private Unbinder unbinder; | ||||
|     @BindView(R.id.recyclerView) RecyclerView recyclerView; | ||||
| @@ -43,36 +43,33 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo | ||||
|         View view = inflater.inflate(R.layout.fragment_repos, container, false); | ||||
|         unbinder = ButterKnife.bind(this, view); | ||||
|  | ||||
|         adapter = new ReposAdapter(getApplication().repoMap); | ||||
|  | ||||
|         adapter = new ReposAdapter(getApplication().repoDB, getApplication().moduleMap); | ||||
|         recyclerView.setAdapter(adapter); | ||||
|  | ||||
|         mSwipeRefreshLayout.setRefreshing(true); | ||||
|  | ||||
|         mSwipeRefreshLayout.setOnRefreshListener(() -> { | ||||
|             recyclerView.setVisibility(View.GONE); | ||||
|             new LoadRepos(getActivity()).exec(); | ||||
|             new UpdateRepos(getActivity()).exec(); | ||||
|         }); | ||||
|  | ||||
|         if (getApplication().repoLoadDone.isTriggered) { | ||||
|             onTrigger(null); | ||||
|         } | ||||
|         getActivity().setTitle(R.string.downloads); | ||||
|  | ||||
|         return view; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTrigger(CallbackEvent<Void> event) { | ||||
|     public void onTopicPublished(Topic topic) { | ||||
|         Logger.dev("ReposFragment: UI refresh triggered"); | ||||
|         if (getApplication().repoMap.isEmpty()) { | ||||
|             recyclerView.setVisibility(View.GONE); | ||||
|             emptyRv.setVisibility(View.VISIBLE); | ||||
|         } else { | ||||
|             adapter.filter(getApplication().moduleMap, ""); | ||||
|             recyclerView.setVisibility(View.VISIBLE); | ||||
|             emptyRv.setVisibility(View.GONE); | ||||
|             mSwipeRefreshLayout.setRefreshing(false); | ||||
|         } | ||||
|         mSwipeRefreshLayout.setRefreshing(false); | ||||
|         adapter.notifyDBChanged(); | ||||
|         recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE); | ||||
|         emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Topic[] getSubscription() { | ||||
|         return new Topic[] { getApplication().repoLoadDone }; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -87,25 +84,12 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo | ||||
|  | ||||
|             @Override | ||||
|             public boolean onQueryTextChange(String newText) { | ||||
|                 adapter.filter(getApplication().moduleMap, newText); | ||||
|                 adapter.filter(newText); | ||||
|                 return false; | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|         getApplication().repoLoadDone.register(this); | ||||
|         getActivity().setTitle(R.string.downloads); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStop() { | ||||
|         getApplication().repoLoadDone.unRegister(this); | ||||
|         super.onStop(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroyView() { | ||||
|         super.onDestroyView(); | ||||
|   | ||||
| @@ -13,18 +13,19 @@ import android.support.v7.app.ActionBar; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.widget.Toast; | ||||
|  | ||||
| import com.topjohnwu.magisk.asyncs.MagiskHide; | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
| import com.topjohnwu.magisk.components.AlertDialogBuilder; | ||||
| import com.topjohnwu.magisk.database.SuDatabaseHelper; | ||||
| import com.topjohnwu.magisk.utils.Logger; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| import com.topjohnwu.magisk.utils.Topic; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
|  | ||||
| import java.util.Locale; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
|  | ||||
| public class SettingsActivity extends Activity { | ||||
| public class SettingsActivity extends Activity implements Topic.Subscriber { | ||||
|  | ||||
|     @BindView(R.id.toolbar) Toolbar toolbar; | ||||
|  | ||||
| @@ -56,14 +57,26 @@ public class SettingsActivity extends Activity { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTopicPublished(Topic topic) { | ||||
|         recreate(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Topic[] getSubscription() { | ||||
|         return new Topic[] { getApplicationContext().reloadActivity }; | ||||
|     } | ||||
|  | ||||
|     public static class SettingsFragment extends PreferenceFragment | ||||
|             implements SharedPreferences.OnSharedPreferenceChangeListener { | ||||
|             implements SharedPreferences.OnSharedPreferenceChangeListener, | ||||
|             Topic.Subscriber { | ||||
|  | ||||
|         private SharedPreferences prefs; | ||||
|         private PreferenceScreen prefScreen; | ||||
|  | ||||
|         private ListPreference suAccess, autoRes, suNotification, requestTimeout, multiuserMode, namespaceMode; | ||||
|         private MagiskManager magiskManager; | ||||
|         private PreferenceCategory generalCatagory; | ||||
|  | ||||
|         @Override | ||||
|         public void onCreate(Bundle savedInstanceState) { | ||||
| @@ -73,6 +86,7 @@ public class SettingsActivity extends Activity { | ||||
|             prefScreen = getPreferenceScreen(); | ||||
|             magiskManager = Utils.getMagiskManager(getActivity()); | ||||
|  | ||||
|             generalCatagory = (PreferenceCategory) findPreference("general"); | ||||
|             PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk"); | ||||
|             PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser"); | ||||
|             PreferenceCategory developer = (PreferenceCategory) findPreference("developer"); | ||||
| @@ -120,16 +134,42 @@ public class SettingsActivity extends Activity { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private void setLocalePreference(ListPreference lp) { | ||||
|             boolean isNew = lp == null; | ||||
|             if (isNew) { | ||||
|                 lp = new ListPreference(getActivity()); | ||||
|             } | ||||
|             CharSequence[] entries = new CharSequence[magiskManager.locales.size() + 1]; | ||||
|             CharSequence[] entryValues = new CharSequence[magiskManager.locales.size() + 1]; | ||||
|             entries[0] = getString(R.string.system_default); | ||||
|             entryValues[0] = ""; | ||||
|             int i = 1; | ||||
|             for (Locale locale : magiskManager.locales) { | ||||
|                 entries[i] = locale.getDisplayName(locale); | ||||
|                 entryValues[i++] = locale.toLanguageTag(); | ||||
|             } | ||||
|             lp.setEntries(entries); | ||||
|             lp.setEntryValues(entryValues); | ||||
|             lp.setTitle(R.string.language); | ||||
|             lp.setKey("locale"); | ||||
|             lp.setSummary(MagiskManager.locale.getDisplayName(MagiskManager.locale)); | ||||
|             if (isNew) { | ||||
|                 generalCatagory.addPreference(lp); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onResume() { | ||||
|             super.onResume(); | ||||
|             prefs.registerOnSharedPreferenceChangeListener(this); | ||||
|             subscribeTopics(); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onPause() { | ||||
|             super.onPause(); | ||||
|             prefs.unregisterOnSharedPreferenceChangeListener(this); | ||||
|             unsubscribeTopics(); | ||||
|             super.onPause(); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
| @@ -142,44 +182,34 @@ public class SettingsActivity extends Activity { | ||||
|                     enabled = prefs.getBoolean("dark_theme", false); | ||||
|                     if (magiskManager.isDarkTheme != enabled) { | ||||
|                         magiskManager.isDarkTheme = enabled; | ||||
|                         magiskManager.reloadMainActivity.trigger(); | ||||
|                         getActivity().recreate(); | ||||
|                         magiskManager.reloadActivity.publish(false); | ||||
|                     } | ||||
|                     break; | ||||
|                 case "disable": | ||||
|                     enabled = prefs.getBoolean("disable", false); | ||||
|                     if (enabled) { | ||||
|                         Utils.createFile(magiskManager.shell, MagiskManager.MAGISK_DISABLE_FILE); | ||||
|                         Utils.createFile(Shell.getShell(magiskManager), MagiskManager.MAGISK_DISABLE_FILE); | ||||
|                     } else { | ||||
|                         Utils.removeItem(magiskManager.shell, MagiskManager.MAGISK_DISABLE_FILE); | ||||
|                         Utils.removeItem(Shell.getShell(magiskManager), MagiskManager.MAGISK_DISABLE_FILE); | ||||
|                     } | ||||
|                     Toast.makeText(getActivity(), R.string.settings_reboot_toast, Toast.LENGTH_LONG).show(); | ||||
|                     break; | ||||
|                 case "magiskhide": | ||||
|                     enabled = prefs.getBoolean("magiskhide", false); | ||||
|                     if (enabled) { | ||||
|                         if (!magiskManager.isSuClient) { | ||||
|                             new AlertDialogBuilder(getActivity()) | ||||
|                                     .setTitle(R.string.no_magisksu_title) | ||||
|                                     .setMessage(R.string.no_magisksu_msg) | ||||
|                                     .setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide(getActivity()).enable()) | ||||
|                                     .setCancelable(false) | ||||
|                                     .show(); | ||||
|                         } else { | ||||
|                             new MagiskHide(getActivity()).enable(); | ||||
|                         } | ||||
|                         Utils.enableMagiskHide(Shell.getShell(magiskManager)); | ||||
|                     } else { | ||||
|                         new MagiskHide(getActivity()).disable(); | ||||
|                         Utils.disableMagiskHide(Shell.getShell(magiskManager)); | ||||
|                     } | ||||
|                     break; | ||||
|                 case "hosts": | ||||
|                     enabled = prefs.getBoolean("hosts", false); | ||||
|                     if (enabled) { | ||||
|                         magiskManager.shell.su_raw( | ||||
|                         Shell.getShell(magiskManager).su_raw( | ||||
|                                 "cp -af /system/etc/hosts /magisk/.core/hosts", | ||||
|                                 "mount -o bind /magisk/.core/hosts /system/etc/hosts"); | ||||
|                     } else { | ||||
|                         magiskManager.shell.su_raw( | ||||
|                         Shell.getShell(magiskManager).su_raw( | ||||
|                                 "umount -l /system/etc/hosts", | ||||
|                                 "rm -f /magisk/.core/hosts"); | ||||
|                     } | ||||
| @@ -211,6 +241,10 @@ public class SettingsActivity extends Activity { | ||||
|                 case "shell_logging": | ||||
|                     MagiskManager.shellLogging = prefs.getBoolean("shell_logging", false); | ||||
|                     break; | ||||
|                 case "locale": | ||||
|                     magiskManager.setLocale(); | ||||
|                     magiskManager.reloadActivity.publish(false); | ||||
|                     break; | ||||
|             } | ||||
|             setSummary(); | ||||
|         } | ||||
| @@ -229,6 +263,16 @@ public class SettingsActivity extends Activity { | ||||
|             namespaceMode.setSummary(getResources() | ||||
|                     .getStringArray(R.array.namespace_summary)[magiskManager.suNamespaceMode]); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onTopicPublished(Topic topic) { | ||||
|             setLocalePreference((ListPreference) findPreference("locale")); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public Topic[] getSubscription() { | ||||
|             return new Topic[] { magiskManager.localeDone }; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -8,9 +8,8 @@ import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.text.TextUtils; | ||||
|  | ||||
| import com.topjohnwu.magisk.asyncs.LoadApps; | ||||
| import com.topjohnwu.magisk.asyncs.LoadModules; | ||||
| import com.topjohnwu.magisk.asyncs.LoadRepos; | ||||
| import com.topjohnwu.magisk.asyncs.UpdateRepos; | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
| import com.topjohnwu.magisk.services.UpdateCheckService; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
| @@ -33,7 +32,6 @@ public class SplashActivity extends Activity{ | ||||
|         magiskManager.remoteMagiskVersionString = getIntent().getStringExtra(MagiskManager.INTENT_VERSION); | ||||
|         magiskManager.magiskLink = getIntent().getStringExtra(MagiskManager.INTENT_LINK); | ||||
|  | ||||
|  | ||||
|         LoadModules loadModuleTask = new LoadModules(this); | ||||
|  | ||||
|         if (Utils.checkNetworkStatus(this)) { | ||||
| @@ -45,15 +43,12 @@ public class SplashActivity extends Activity{ | ||||
|                         .setPersisted(true) | ||||
|                         .setPeriodic(8 * 60 * 60 * 1000) | ||||
|                         .build(); | ||||
|                 JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); | ||||
|                 scheduler.schedule(jobInfo); | ||||
|                 ((JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(jobInfo); | ||||
|             } | ||||
|             loadModuleTask.setCallBack(() -> new LoadRepos(this).exec()); | ||||
|             loadModuleTask.setCallBack(() -> new UpdateRepos(getApplication()).exec()); | ||||
|         } | ||||
|  | ||||
|         // Now fire all async tasks | ||||
|         loadModuleTask.exec(); | ||||
|         new LoadApps(this).exec(); | ||||
|  | ||||
|         Intent intent = new Intent(this, MainActivity.class); | ||||
|         String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION); | ||||
|   | ||||
| @@ -13,9 +13,6 @@ import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.adapters.SuLogAdapter; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.superuser.SuLogEntry; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| @@ -28,6 +25,7 @@ public class SuLogFragment extends Fragment { | ||||
|  | ||||
|     private Unbinder unbinder; | ||||
|     private MagiskManager magiskManager; | ||||
|     private SuLogAdapter adapter; | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate(@Nullable Bundle savedInstanceState) { | ||||
| @@ -48,6 +46,8 @@ public class SuLogFragment extends Fragment { | ||||
|         View v = inflater.inflate(R.layout.fragment_su_log, container, false); | ||||
|         unbinder = ButterKnife.bind(this, v); | ||||
|         magiskManager = getApplication(); | ||||
|         adapter = new SuLogAdapter(magiskManager.suDB); | ||||
|         recyclerView.setAdapter(adapter); | ||||
|  | ||||
|         updateList(); | ||||
|  | ||||
| @@ -55,13 +55,12 @@ public class SuLogFragment extends Fragment { | ||||
|     } | ||||
|  | ||||
|     private void updateList() { | ||||
|         List<SuLogEntry> logs = magiskManager.suDB.getLogList(); | ||||
|         adapter.notifyDBChanged(); | ||||
|  | ||||
|         if (logs.size() == 0) { | ||||
|         if (adapter.getSectionCount() == 0) { | ||||
|             emptyRv.setVisibility(View.VISIBLE); | ||||
|             recyclerView.setVisibility(View.GONE); | ||||
|         } else { | ||||
|             recyclerView.setAdapter(new SuLogAdapter(logs).getAdapter()); | ||||
|             emptyRv.setVisibility(View.GONE); | ||||
|             recyclerView.setVisibility(View.VISIBLE); | ||||
|         } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| package com.topjohnwu.magisk.adapters; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.Context; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.support.design.widget.Snackbar; | ||||
| @@ -14,13 +14,16 @@ import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.R; | ||||
| import com.topjohnwu.magisk.asyncs.MagiskHide; | ||||
| import com.topjohnwu.magisk.asyncs.ParallelTask; | ||||
| import com.topjohnwu.magisk.components.SnackbarMaker; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| import com.topjohnwu.magisk.utils.Topic; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
| import java.util.Collections; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| @@ -41,20 +44,19 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter. | ||||
|  | ||||
|     private List<ApplicationInfo> mOriginalList, mList; | ||||
|     private List<String> mHideList; | ||||
|     private PackageManager packageManager; | ||||
|     private PackageManager pm; | ||||
|     private ApplicationFilter filter; | ||||
|     private Topic magiskHideDone; | ||||
|     private Shell shell; | ||||
|  | ||||
|     public ApplicationAdapter(PackageManager packageManager) { | ||||
|     public ApplicationAdapter(Context context) { | ||||
|         mOriginalList = mList = Collections.emptyList(); | ||||
|         mHideList = Collections.emptyList(); | ||||
|         this.packageManager = packageManager; | ||||
|         filter = new ApplicationFilter(); | ||||
|     } | ||||
|  | ||||
|     public void setLists(List<ApplicationInfo> listApps, List<String> hideList) { | ||||
|         mOriginalList = mList = listApps; | ||||
|         mHideList = hideList; | ||||
|         notifyDataSetChanged(); | ||||
|         pm = context.getPackageManager(); | ||||
|         magiskHideDone = Utils.getMagiskManager(context).magiskHideDone; | ||||
|         shell = Shell.getShell(context); | ||||
|         new LoadApps().exec(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -67,8 +69,8 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter. | ||||
|     public void onBindViewHolder(final ViewHolder holder, int position) { | ||||
|         ApplicationInfo info = mList.get(position); | ||||
|  | ||||
|         holder.appIcon.setImageDrawable(info.loadIcon(packageManager)); | ||||
|         holder.appName.setText(info.loadLabel(packageManager)); | ||||
|         holder.appIcon.setImageDrawable(info.loadIcon(pm)); | ||||
|         holder.appName.setText(info.loadLabel(pm)); | ||||
|         holder.appPackage.setText(info.packageName); | ||||
|  | ||||
|         // Remove all listeners | ||||
| @@ -87,10 +89,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter. | ||||
|             holder.checkBox.setChecked(mHideList.contains(info.packageName)); | ||||
|             holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> { | ||||
|                 if (isChecked) { | ||||
|                     new MagiskHide((Activity) holder.itemView.getContext()).add(info.packageName); | ||||
|                     Utils.addMagiskHide(shell, info.packageName); | ||||
|                     mHideList.add(info.packageName); | ||||
|                 } else { | ||||
|                     new MagiskHide((Activity) holder.itemView.getContext()).rm(info.packageName); | ||||
|                     Utils.rmMagiskHide(shell, info.packageName); | ||||
|                     mHideList.remove(info.packageName); | ||||
|                 } | ||||
|             }); | ||||
| @@ -106,6 +108,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter. | ||||
|         filter.filter(constraint); | ||||
|     } | ||||
|  | ||||
|     public void refresh() { | ||||
|         new LoadApps().exec(); | ||||
|     } | ||||
|  | ||||
|     static class ViewHolder extends RecyclerView.ViewHolder { | ||||
|  | ||||
|         @BindView(R.id.app_icon) ImageView appIcon; | ||||
| @@ -123,31 +129,47 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter. | ||||
|  | ||||
|         @Override | ||||
|         protected FilterResults performFiltering(CharSequence constraint) { | ||||
|             List<ApplicationInfo> filteredApps; | ||||
|             if (constraint == null || constraint.length() == 0) { | ||||
|                 filteredApps = mOriginalList; | ||||
|                 mList = mOriginalList; | ||||
|             } else { | ||||
|                 filteredApps = new ArrayList<>(); | ||||
|                 mList = new ArrayList<>(); | ||||
|                 String filter = constraint.toString().toLowerCase(); | ||||
|                 for (ApplicationInfo info : mOriginalList) { | ||||
|                     if (Utils.lowercaseContains(info.loadLabel(packageManager), filter) | ||||
|                     if (Utils.lowercaseContains(info.loadLabel(pm), filter) | ||||
|                             || Utils.lowercaseContains(info.packageName, filter)) { | ||||
|                         filteredApps.add(info); | ||||
|                         mList.add(info); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             FilterResults results = new FilterResults(); | ||||
|             results.values = filteredApps; | ||||
|             results.count = filteredApps.size(); | ||||
|             return results; | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         @SuppressWarnings("unchecked") | ||||
|         @Override | ||||
|         protected void publishResults(CharSequence constraint, FilterResults results) { | ||||
|             mList = (List<ApplicationInfo>) results.values; | ||||
|             notifyDataSetChanged(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private class LoadApps extends ParallelTask<Void, Void, Void> { | ||||
|  | ||||
|         @Override | ||||
|         protected Void doInBackground(Void... voids) { | ||||
|             mOriginalList = pm.getInstalledApplications(0); | ||||
|             for (Iterator<ApplicationInfo> i = mOriginalList.iterator(); i.hasNext(); ) { | ||||
|                 ApplicationInfo info = i.next(); | ||||
|                 if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) { | ||||
|                     i.remove(); | ||||
|                 } | ||||
|             } | ||||
|             Collections.sort(mOriginalList, (a, b) -> a.loadLabel(pm).toString().toLowerCase() | ||||
|                     .compareTo(b.loadLabel(pm).toString().toLowerCase())); | ||||
|             mHideList = Utils.listMagiskHide(shell); | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected void onPostExecute(Void v) { | ||||
|             magiskHideDone.publish(false); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,93 @@ | ||||
| package com.topjohnwu.magisk.adapters; | ||||
|  | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| public abstract class SectionedAdapter<S extends RecyclerView.ViewHolder, C extends RecyclerView.ViewHolder> | ||||
|         extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|  | ||||
|     private static final int SECTION_TYPE = Integer.MIN_VALUE; | ||||
|  | ||||
|     @Override | ||||
|     final public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|         if (viewType == SECTION_TYPE) | ||||
|             return onCreateSectionViewHolder(parent); | ||||
|         return onCreateItemViewHolder(parent, viewType); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     @SuppressWarnings("unchecked") | ||||
|     final public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { | ||||
|         PositionInfo info = getPositionInfo(position); | ||||
|         if (info.position == -1) | ||||
|             onBindSectionViewHolder((S) holder, info.section); | ||||
|         else | ||||
|             onBindItemViewHolder((C) holder, info.section, info.position); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     final public int getItemCount() { | ||||
|         int size, sec; | ||||
|         size = sec = getSectionCount(); | ||||
|         for (int i = 0; i < sec; ++i){ | ||||
|             size += getItemCount(i); | ||||
|         } | ||||
|         return size; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     final public int getItemViewType(int position) { | ||||
|         PositionInfo info = getPositionInfo(position); | ||||
|         if (info.position == -1) | ||||
|             return SECTION_TYPE; | ||||
|         else | ||||
|             return  getItemViewType(info.section, info.position); | ||||
|     } | ||||
|  | ||||
|     public int getItemViewType(int section, int position) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     protected int getSectionPosition(int section) { | ||||
|         return getItemPosition(section, -1); | ||||
|     } | ||||
|  | ||||
|     protected int getItemPosition(int section, int position) { | ||||
|         int realPosition = 0; | ||||
|         // Previous sections | ||||
|         for (int i = 0; i < section; ++i) { | ||||
|             realPosition += getItemCount(i) + 1; | ||||
|         } | ||||
|         // Current section | ||||
|         realPosition += position + 1; | ||||
|         return realPosition; | ||||
|     } | ||||
|  | ||||
|     private PositionInfo getPositionInfo(int position) { | ||||
|         int section = 0; | ||||
|         while (true) { | ||||
|             if (position == 0) | ||||
|                 return new PositionInfo(section, -1); | ||||
|             position -= 1; | ||||
|             if (position < getItemCount(section)) | ||||
|                 return new PositionInfo(section, position); | ||||
|             position -= getItemCount(section++); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class PositionInfo { | ||||
|         int section; | ||||
|         int position; | ||||
|         PositionInfo(int section, int position) { | ||||
|             this.section = section; | ||||
|             this.position = position; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public abstract int getSectionCount(); | ||||
|     public abstract int getItemCount(int section); | ||||
|     public abstract S onCreateSectionViewHolder(ViewGroup parent); | ||||
|     public abstract C onCreateItemViewHolder(ViewGroup parent, int viewType); | ||||
|     public abstract void onBindSectionViewHolder(S holder, int section); | ||||
|     public abstract void onBindItemViewHolder(C holder, int section, int position); | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -29,7 +29,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> { | ||||
|     protected Void doInBackground(Void... voids) { | ||||
|         MagiskManager magiskManager = getMagiskManager(); | ||||
|         if (magiskManager == null) return null; | ||||
|         String jsonStr = WebService.request(UPDATE_JSON, WebService.GET); | ||||
|         String jsonStr = WebService.getString(UPDATE_JSON); | ||||
|         try { | ||||
|             JSONObject json = new JSONObject(jsonStr); | ||||
|             JSONObject magisk = json.getJSONObject("magisk"); | ||||
| @@ -56,7 +56,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> { | ||||
|                 Utils.showMagiskUpdate(magiskManager); | ||||
|             } | ||||
|         } | ||||
|         magiskManager.updateCheckDone.trigger(); | ||||
|         magiskManager.updateCheckDone.publish(); | ||||
|         super.onPostExecute(v); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,71 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.os.Build; | ||||
|  | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
| import com.topjohnwu.magisk.utils.WebService; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
|  | ||||
| public class DownloadBusybox extends ParallelTask<Void, Void, Void> { | ||||
|  | ||||
|     private static final String BUSYBOX_ARM = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.1/busybox-arm"; | ||||
|     private static final String BUSYBOX_X86 = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.1/busybox-x86"; | ||||
|     private static final String BUSYBOXPATH = "/dev/magisk/bin"; | ||||
|  | ||||
|     private File busybox; | ||||
|  | ||||
|     public DownloadBusybox(Context context) { | ||||
|         super(context); | ||||
|         busybox = new File(context.getCacheDir(), "busybox"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPreExecute() { | ||||
|         getShell().su_raw("export PATH=" + BUSYBOXPATH + ":$PATH"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Void doInBackground(Void... voids) { | ||||
|         Context context = getMagiskManager(); | ||||
|         if (!Utils.itemExist(getShell(), BUSYBOXPATH + "/busybox")) { | ||||
|             if (!busybox.exists() && Utils.checkNetworkStatus(context)) { | ||||
|                 Utils.removeItem(getShell(), context.getApplicationInfo().dataDir + "/busybox"); | ||||
|                 try { | ||||
|                     FileOutputStream out  = new FileOutputStream(busybox); | ||||
|                     InputStream in = WebService.request(WebService.GET, | ||||
|                             Build.SUPPORTED_32_BIT_ABIS[0].contains("x86") ? | ||||
|                                     BUSYBOX_X86 : | ||||
|                                     BUSYBOX_ARM, | ||||
|                             null | ||||
|                     ); | ||||
|                     if (in == null) throw new IOException(); | ||||
|                     byte[] buffer = new byte[4096]; | ||||
|                     int read; | ||||
|                     while ((read = in.read(buffer)) != -1) { | ||||
|                         out.write(buffer, 0, read); | ||||
|                     } | ||||
|                     out.close(); | ||||
|                     in.close(); | ||||
|  | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|             if (busybox.exists()) { | ||||
|                 getShell().su_raw( | ||||
|                         "rm -rf " + BUSYBOXPATH, | ||||
|                         "mkdir -p " + BUSYBOXPATH, | ||||
|                         "cp " + busybox + " " + BUSYBOXPATH, | ||||
|                         "chmod -R 755 " + BUSYBOXPATH, | ||||
|                         BUSYBOXPATH + "/busybox --install -s " + BUSYBOXPATH | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.app.Activity; | ||||
| import android.net.Uri; | ||||
| import android.text.TextUtils; | ||||
|  | ||||
| @@ -26,7 +26,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> { | ||||
|     private String mFilename; | ||||
|     private AdaptiveList<String> mList; | ||||
|  | ||||
|     public FlashZip(Context context, Uri uri, AdaptiveList<String> list) { | ||||
|     public FlashZip(Activity context, Uri uri, AdaptiveList<String> list) { | ||||
|         super(context); | ||||
|         mUri = uri; | ||||
|         mList = list; | ||||
| @@ -82,7 +82,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> { | ||||
|             } | ||||
|             if (!unzipAndCheck()) return 0; | ||||
|             mList.add(magiskManager.getString(R.string.zip_install_progress_msg, mFilename)); | ||||
|             magiskManager.shell.su(mList, | ||||
|             getShell().su(mList, | ||||
|                     "BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile + | ||||
|                             " && echo 'Success!' || echo 'Failed!'" | ||||
|             ); | ||||
| @@ -99,23 +99,23 @@ public class FlashZip extends ParallelTask<Void, String, Integer> { | ||||
|     protected void onPostExecute(Integer result) { | ||||
|         MagiskManager magiskManager = getMagiskManager(); | ||||
|         if (magiskManager == null) return; | ||||
|         magiskManager.shell.su_raw( | ||||
|                 "rm -rf " + mCachedFile.getParent() + "/*", | ||||
|         getShell().su_raw( | ||||
|                 "rm -rf " + mCachedFile.getParent(), | ||||
|                 "rm -rf " + MagiskManager.TMP_FOLDER_PATH | ||||
|         ); | ||||
|         switch (result) { | ||||
|             case -1: | ||||
|                 mList.add(magiskManager.getString(R.string.install_error)); | ||||
|                 Utils.showUriSnack(getActivity(), mUri); | ||||
|                 return; | ||||
|                 break; | ||||
|             case 0: | ||||
|                 mList.add(magiskManager.getString(R.string.invalid_zip)); | ||||
|                 return; | ||||
|                 break; | ||||
|             case 1: | ||||
|                 // Success | ||||
|                 new LoadModules(magiskManager).exec(); | ||||
|                 break; | ||||
|         } | ||||
|         new LoadModules(magiskManager).exec(); | ||||
|         super.onPostExecute(result); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,44 +0,0 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageManager; | ||||
|  | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
| 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(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Void doInBackground(Void... voids) { | ||||
|         MagiskManager magiskManager = getMagiskManager(); | ||||
|         if (magiskManager == null) return null; | ||||
|         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) { | ||||
|         MagiskManager magiskManager = getMagiskManager(); | ||||
|         if (magiskManager == null) return; | ||||
|         new MagiskHide(magiskManager).list(); | ||||
|     } | ||||
| } | ||||
| @@ -23,10 +23,10 @@ public class LoadModules extends ParallelTask<Void, Void, Void> { | ||||
|  | ||||
|         magiskManager.moduleMap = new ValueSortedMap<>(); | ||||
|  | ||||
|         for (String path : Utils.getModList(magiskManager.shell, MagiskManager.MAGISK_PATH)) { | ||||
|         for (String path : Utils.getModList(getShell(), MagiskManager.MAGISK_PATH)) { | ||||
|             Logger.dev("LoadModules: Adding modules from " + path); | ||||
|             try { | ||||
|                 Module module = new Module(magiskManager.shell, path); | ||||
|                 Module module = new Module(getShell(), path); | ||||
|                 magiskManager.moduleMap.put(module.getId(), module); | ||||
|             } catch (BaseModule.CacheModException ignored) {} | ||||
|         } | ||||
| @@ -39,7 +39,7 @@ public class LoadModules extends ParallelTask<Void, Void, Void> { | ||||
|     protected void onPostExecute(Void v) { | ||||
|         MagiskManager magiskManager = getMagiskManager(); | ||||
|         if (magiskManager == null) return; | ||||
|         magiskManager.moduleLoadDone.trigger(); | ||||
|         magiskManager.moduleLoadDone.publish(); | ||||
|         super.onPostExecute(v); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,61 +0,0 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.content.Context; | ||||
|  | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| public class MagiskHide extends ParallelTask<Object, Void, Void> { | ||||
|  | ||||
|     private boolean isList = false; | ||||
|  | ||||
|     public MagiskHide(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Void doInBackground(Object... params) { | ||||
|         MagiskManager magiskManager = getMagiskManager(); | ||||
|         if (magiskManager == null) return null; | ||||
|         String command = (String) params[0]; | ||||
|         List<String> ret = magiskManager.shell.su("magiskhide --" + command); | ||||
|         if (isList) { | ||||
|             magiskManager.magiskHideList = ret; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostExecute(Void v) { | ||||
|         MagiskManager magiskManager = getMagiskManager(); | ||||
|         if (magiskManager == null) return; | ||||
|         if (isList) { | ||||
|             magiskManager.magiskHideDone.trigger(); | ||||
|         } | ||||
|         super.onPostExecute(v); | ||||
|     } | ||||
|  | ||||
|     public void add(CharSequence packageName) { | ||||
|         exec("add " + packageName); | ||||
|     } | ||||
|  | ||||
|     public void rm(CharSequence packageName) { | ||||
|         exec("rm " + packageName); | ||||
|     } | ||||
|  | ||||
|     public void enable() { | ||||
|         exec("enable"); | ||||
|     } | ||||
|  | ||||
|     public void disable() { | ||||
|         exec("disable"); | ||||
|     } | ||||
|  | ||||
|     public void list() { | ||||
|         isList = true; | ||||
|         if (getMagiskManager() == null) return; | ||||
|         exec("ls"); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,50 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.support.v7.app.AlertDialog; | ||||
| import android.webkit.WebView; | ||||
|  | ||||
| import com.topjohnwu.magisk.R; | ||||
| import com.topjohnwu.magisk.utils.WebService; | ||||
|  | ||||
| import org.commonmark.node.Node; | ||||
| import org.commonmark.parser.Parser; | ||||
| import org.commonmark.renderer.html.HtmlRenderer; | ||||
|  | ||||
| public class MarkDownWindow extends ParallelTask<Void, Void, String> { | ||||
|  | ||||
|     private String mTitle, mUrl; | ||||
|  | ||||
|     public MarkDownWindow(Activity context, String title, String url) { | ||||
|         super(context); | ||||
|         mTitle = title; | ||||
|         mUrl = url; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected String doInBackground(Void... voids) { | ||||
|         String md = WebService.getString(mUrl); | ||||
|         Parser parser = Parser.builder().build(); | ||||
|         HtmlRenderer renderer = HtmlRenderer.builder().build(); | ||||
|         Node doc = parser.parse(md); | ||||
|         return renderer.render(doc); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostExecute(String html) { | ||||
|         AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); | ||||
|         alert.setTitle(mTitle); | ||||
|  | ||||
|         WebView wv = new WebView(getActivity()); | ||||
|  | ||||
|         html = String.format( | ||||
|                 "<link rel='stylesheet' type='text/css' href='file:///android_asset/%s.css'/> %s", | ||||
|                 getMagiskManager().isDarkTheme ? "dark" : "light", html); | ||||
|  | ||||
|         wv.loadDataWithBaseURL("fake://", html, "text/html", "UTF-8", null); | ||||
|  | ||||
|         alert.setView(wv); | ||||
|         alert.setNegativeButton(R.string.close, (dialog, id) -> dialog.dismiss()); | ||||
|         alert.show(); | ||||
|     } | ||||
| } | ||||
| @@ -38,7 +38,7 @@ public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<P | ||||
|  | ||||
|     protected Shell getShell() { | ||||
|         MagiskManager magiskManager = getMagiskManager(); | ||||
|         return magiskManager == null ? null : getMagiskManager().shell; | ||||
|         return magiskManager == null ? null : Shell.getShell(magiskManager); | ||||
|     } | ||||
|  | ||||
|     @SuppressWarnings("unchecked") | ||||
|   | ||||
| @@ -65,13 +65,14 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> { | ||||
|             ZipUtils.signZip(activity, temp1, temp2, true); | ||||
|  | ||||
|             // Write it back to the downloaded zip, temp2 -> Uri | ||||
|             FileInputStream in = new FileInputStream(temp2); | ||||
|             try (OutputStream target = activity.getContentResolver().openOutputStream(mUri)) { | ||||
|             try (OutputStream out = activity.getContentResolver().openOutputStream(mUri); | ||||
|                  FileInputStream in = new FileInputStream(temp2) | ||||
|             ) { | ||||
|                 byte[] buffer = new byte[4096]; | ||||
|                 int length; | ||||
|                 if (target == null) throw new FileNotFoundException(); | ||||
|                 if (out == null) throw new FileNotFoundException(); | ||||
|                 while ((length = in.read(buffer)) > 0) | ||||
|                     target.write(buffer, 0, length); | ||||
|                     out.write(buffer, 0, length); | ||||
|             } | ||||
|  | ||||
|             // Delete the temp file | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user