mirror of
				https://github.com/topjohnwu/Magisk
				synced 2025-10-30 09:00:52 +01:00 
			
		
		
		
	Compare commits
	
		
			268 Commits
		
	
	
		
			manager-v4
			...
			manager-v5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 773c24b7fc | ||
|   | 8f926c7ca9 | ||
|   | c562cbc2bb | ||
|   | 3fbbb0865a | ||
|   | 7d5f612a48 | ||
|   | 4a5a36440b | ||
|   | 43dd5cfea1 | ||
|   | 7b5fec1842 | ||
|   | 5762ded601 | ||
|   | a3abb86daa | ||
|   | 4f5c656b05 | ||
|   | a31cddbe7b | ||
|   | b4ecd93f1c | ||
|   | 0acc23e058 | ||
|   | cdd5f9b628 | ||
|   | 4c9f5f4655 | ||
|   | b80ba13cb4 | ||
|   | 8260bdc09c | ||
|   | 24f856e02b | ||
|   | 3aa619b928 | ||
|   | 4cb5e98d94 | ||
|   | 272910575e | ||
|   | a15a62f4bc | ||
|   | 53cf11db8c | ||
|   | 01052fbe47 | ||
|   | a5e1e075c7 | ||
|   | 6be32ac688 | ||
|   | b362c0ef38 | ||
|   | bba9969e31 | ||
|   | 007ba24809 | ||
|   | df21539311 | ||
|   | 2592cb6019 | ||
|   | f7df17a7ed | ||
|   | 62f42b72f8 | ||
|   | a1ba4fda6f | ||
|   | 1c06b04c45 | ||
|   | 2ee22fd374 | ||
|   | 4c230d9e61 | ||
|   | 727294fbbe | ||
|   | 478c43969b | ||
|   | 79b5303350 | ||
|   | ce4b742b25 | ||
|   | a9dc15bda5 | ||
|   | ba6387ff5c | ||
|   | 8fa98508b7 | ||
|   | decdbaecf9 | ||
|   | 6d87cf9be0 | ||
|   | 94f434c4a6 | ||
|   | 7ba867c30b | ||
|   | 3424395e10 | ||
|   | 926c7359a2 | ||
|   | ec0af99a2e | ||
|   | b4d948886c | ||
|   | 4d8d79372a | ||
|   | 04a589722c | ||
|   | d4a10e2873 | ||
|   | 4998ad6c7e | ||
|   | a07ca5ff50 | ||
|   | f07e7571ab | ||
|   | 834c16485c | ||
|   | 04a4265ef3 | ||
|   | 0ec473195d | ||
|   | 0bf09256b0 | ||
|   | db8fd2c913 | ||
|   | dbe6e5b3d7 | ||
|   | cc81cd446b | ||
|   | 439c7118f1 | ||
|   | d8154a5815 | ||
|   | 4e3787bc0d | ||
|   | 02e0955924 | ||
|   | a78950e822 | ||
|   | 1ce1a94a35 | ||
|   | 977b6d9f67 | ||
|   | b5e6dbd797 | ||
|   | 833e6688f1 | ||
|   | bc22c9f84f | ||
|   | 2149a7d116 | ||
|   | 29175d2c17 | ||
|   | 803454d5c8 | ||
|   | 36cf32dc42 | ||
|   | 657f4ab303 | ||
|   | ea6552615d | ||
|   | 4bf3287fce | ||
|   | 832c2034c2 | ||
|   | b0aa26e1f1 | ||
|   | e52baeb967 | ||
|   | 8268eb9a83 | ||
|   | 3cc458abd9 | ||
|   | 337b4c4268 | ||
|   | 001f8657f6 | ||
|   | ea884e7fa1 | ||
|   | 1b1394cf5d | ||
|   | 1eef930dbb | ||
|   | 1e175e74ed | ||
|   | 75a46c365e | ||
|   | 8e7b8825f5 | ||
|   | 2ecbca303b | ||
|   | 8195a4d616 | ||
|   | 7ba40f925f | ||
|   | 345cd1795f | ||
|   | 959aaee045 | ||
|   | 53477f0f59 | ||
|   | 5716218f41 | ||
|   | 9df6b9d5c0 | ||
|   | ec46031d36 | ||
|   | 55b84d166a | ||
|   | 34ae8bacec | ||
|   | cb4e5ca0f7 | ||
|   | 0ba45468c4 | ||
|   | 710502784e | ||
|   | 0275a8558d | ||
|   | 58acc75cf6 | ||
|   | 874ababb9f | ||
|   | 3771e6b0cd | ||
|   | 33eaefa966 | ||
|   | cd7e236d57 | ||
|   | 54c0b7c7d5 | ||
|   | a2177daec2 | ||
|   | 628386b453 | ||
|   | b222bfb3e0 | ||
|   | ab199d883d | ||
|   | 356065d1ee | ||
|   | 76e7c5623d | ||
|   | 085fba050a | ||
|   | 295334d3ac | ||
|   | 36124ddca4 | ||
|   | bd6585765e | ||
|   | c325deb4ed | ||
|   | 73bb0b10ee | ||
|   | 72820b162c | ||
|   | 89e5b8d057 | ||
|   | da4f53ebbb | ||
|   | 8458553b74 | ||
|   | 55ecc41d06 | ||
|   | 28fcdf2cbb | ||
|   | 24087679a8 | ||
|   | 5ac6a8cb4a | ||
|   | 668d85d14e | ||
|   | c11a3dc95c | ||
|   | 56f57c20a2 | ||
|   | 240d14779a | ||
|   | 3550d1e61c | ||
|   | 6513ad249c | ||
|   | 50297b1880 | ||
|   | f189b78b9e | ||
|   | 5c0250f495 | ||
|   | 2093f726e9 | ||
|   | 10efe3859d | ||
|   | 6933bcf7bb | ||
|   | 2ea046cd80 | ||
|   | f4097a372b | ||
|   | 87ea2a2bef | ||
|   | cc14a1c361 | ||
|   | bcdface60d | ||
|   | 4dc9419d2e | ||
|   | d2bcac813e | ||
|   | 080c37a7f6 | ||
|   | f9a3838db6 | ||
|   | 1e61db104b | ||
|   | 30a9c7718d | ||
|   | 34b052b5d3 | ||
|   | aaa12853ad | ||
|   | b0ab55b0bf | ||
|   | d2f8496f4e | ||
|   | 1a69b16d36 | ||
|   | b5e8673e62 | ||
|   | 264c6a50b6 | ||
|   | 493642eb38 | ||
|   | 28d42b9164 | ||
|   | 42f29062ca | ||
|   | c4377ed6c2 | ||
|   | 7d283ed65f | ||
|   | bf1f941e50 | ||
|   | 789fef34ba | ||
|   | 1daf5a611c | ||
|   | 6aed1db67e | ||
|   | cf68854770 | ||
|   | 711392c73b | ||
|   | 9573c32481 | ||
|   | a15f80f79d | ||
|   | 23e7475f06 | ||
|   | 1eb571b787 | ||
|   | dd3b716d85 | ||
|   | 28649c07e3 | ||
|   | 961e02be0d | ||
|   | a161491bfd | ||
|   | e0b4d1c1e4 | ||
|   | fd4aaab137 | ||
|   | 42d14d5ca2 | ||
|   | d3ff482c9b | ||
|   | f682368eeb | ||
|   | 4a5d033efb | ||
|   | 343161b195 | ||
|   | bc576a9659 | ||
|   | 19e407fcc4 | ||
|   | bc7327d004 | ||
|   | 666fa1c797 | ||
|   | 0eda4a7821 | ||
|   | 862058fd2b | ||
|   | 69e5bcd57d | ||
|   | efeddda328 | ||
|   | ff6938280e | ||
|   | 1e4425b30f | ||
|   | b5d1d8cdad | ||
|   | 029be5ccca | ||
|   | 29c2d785b5 | ||
|   | abda8cfa32 | ||
|   | 44e7d79d4c | ||
|   | 9a1dc8ee0e | ||
|   | 27879c3f01 | ||
|   | 29096eb5d7 | ||
|   | a573baea03 | ||
|   | 5af07c4531 | ||
|   | 44e36feb09 | ||
|   | 2a7d996881 | ||
|   | 738f943a68 | ||
|   | 47e62a5681 | ||
|   | 1ecbfd7590 | ||
|   | 67c139a04b | ||
|   | 31cc008249 | ||
|   | 9cb026439d | ||
|   | e6f10176c6 | ||
|   | 0917c79470 | ||
|   | 597baa986d | ||
|   | 75cc4b4843 | ||
|   | aac088d496 | ||
|   | a822e5bbc5 | ||
|   | c527249c21 | ||
|   | 9ef798f534 | ||
|   | e69b99f089 | ||
|   | 55b8079e86 | ||
|   | e272dbe9af | ||
|   | 962f8354ac | ||
|   | 20e4a960f7 | ||
|   | 82249cb50a | ||
|   | fad417e553 | ||
|   | 5ba692f50c | ||
|   | 907e01e524 | ||
|   | b8ed23efa7 | ||
|   | 2b3bbf7e67 | ||
|   | 464fe627a3 | ||
|   | 6a9e39c470 | ||
|   | 7fec9a3cc6 | ||
|   | 008f6ef462 | ||
|   | 2440c108ca | ||
|   | 430baad8a4 | ||
|   | 51132e74b4 | ||
|   | a4f33e106a | ||
|   | baba3190e0 | ||
|   | 47b13aa5ea | ||
|   | ae88d3054d | ||
|   | 411b600e14 | ||
|   | 0a0ad9a184 | ||
|   | 234bead59e | ||
|   | 76de310986 | ||
|   | 817f050bcd | ||
|   | 60ae685d1e | ||
|   | 4c7bdbb284 | ||
|   | 435251ca41 | ||
|   | 324a0dd38f | ||
|   | cc77d93918 | ||
|   | 0ea7d8bd8c | ||
|   | 849b217143 | ||
|   | 9af6efba59 | ||
|   | 079d6f06ef | ||
|   | 9cf0757689 | ||
|   | b54c438948 | ||
|   | c3ff4bfdad | 
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,6 +3,10 @@ | ||||
| /local.properties | ||||
| .idea/ | ||||
| /build | ||||
| app/app-release.apk | ||||
| app/release | ||||
| *.hprof | ||||
| app/.externalNativeBuild/ | ||||
| *.sh | ||||
| public.certificate.x509.pem | ||||
| private.key.pk8 | ||||
| *.apk | ||||
|   | ||||
| @@ -1,4 +1,7 @@ | ||||
| # Magisk Manager | ||||
| The project should be built with Android Studio version 2.2.0+   | ||||
| I use Java 8 features, which requires Jack compiler and it's only available in 2.2.0+   | ||||
| Also, you need to install CMake and NDK to build the zipadjust library for zip preprocessing | ||||
| 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) | ||||
|  | ||||
| ## Building Notes | ||||
| You need to install CMake and NDK to build the zipadjust library. | ||||
| There are several files required to let Magisk Manager work properly, and they can be copied by using the build script in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk). These files are: `magisk_uninstaller.sh`, `util_functions.sh`, `public.certificate.x509.pem`, and `private.key.pk8` under the `app/src/main/assets` folder. | ||||
|   | ||||
| @@ -1,28 +1,30 @@ | ||||
| apply plugin: 'com.android.application' | ||||
|  | ||||
| android { | ||||
|     compileSdkVersion 25 | ||||
|     buildToolsVersion "25.0.2" | ||||
|     compileSdkVersion 26 | ||||
|     buildToolsVersion "26.0.1" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "com.topjohnwu.magisk" | ||||
|         minSdkVersion 21 | ||||
|         targetSdkVersion 25 | ||||
|         versionCode 25 | ||||
|         versionName "4.2.6" | ||||
|         jackOptions { | ||||
|             enabled true | ||||
|             jackInProcess true | ||||
|         } | ||||
|         targetSdkVersion 26 | ||||
|         versionCode 55 | ||||
|         versionName "5.3.5" | ||||
|         ndk { | ||||
|             moduleName 'zipadjust' | ||||
|             abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' | ||||
|         } | ||||
|         javaCompileOptions { | ||||
|             annotationProcessorOptions { | ||||
|                 argument('butterknife.debuggable', 'false') | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled true | ||||
|             shrinkResources true | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
| @@ -31,34 +33,36 @@ android { | ||||
|         targetCompatibility JavaVersion.VERSION_1_8 | ||||
|     } | ||||
|     dexOptions { | ||||
|         preDexLibraries = true | ||||
|         preDexLibraries true | ||||
|         javaMaxHeapSize "2g" | ||||
|     } | ||||
|     externalNativeBuild { | ||||
|         cmake { | ||||
|             path 'src/main/jni/CMakeLists.txt' | ||||
|         } | ||||
|     } | ||||
|     lintOptions { | ||||
|         disable 'MissingTranslation' | ||||
|     } | ||||
| } | ||||
| repositories { | ||||
|     jcenter() | ||||
|     maven { url "https://jitpack.io" } | ||||
|     maven { url "https://maven.google.com" } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     compile fileTree(include: ['*.jar'], dir: 'libs') | ||||
|  | ||||
|     compile 'com.android.support:recyclerview-v7:25.2.0' | ||||
|     compile 'com.android.support:cardview-v7:25.2.0' | ||||
|     compile 'com.android.support:design:25.2.0' | ||||
|     compile 'com.android.support:support-v4:25.2.0' | ||||
|     compile 'com.jakewharton:butterknife:8.5.1' | ||||
|     compile 'com.github.clans:fab:1.6.4' | ||||
|     compile 'com.thoughtbot:expandablerecyclerview:1.4' | ||||
|     compile 'us.feras.mdv:markdownview:1.1.0' | ||||
|     compile 'com.madgag.spongycastle:core:1.54.0.0' | ||||
|     compile 'com.madgag.spongycastle:prov:1.54.0.0' | ||||
|     compile 'com.madgag.spongycastle:pkix:1.54.0.0' | ||||
|     compile 'com.madgag.spongycastle:pg:1.54.0.0' | ||||
|     compile 'com.google.android.gms:play-services-safetynet:9.0.1' | ||||
|     annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' | ||||
|     implementation fileTree(include: ['*.jar'], dir: 'libs') | ||||
|     implementation project(':resource') | ||||
|     implementation 'com.android.support:recyclerview-v7:26.1.0' | ||||
|     implementation 'com.android.support:cardview-v7:26.1.0' | ||||
|     implementation 'com.android.support:design:26.1.0' | ||||
|     implementation 'com.android.support:support-v4:26.1.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 'org.kamranzafar:jtar:2.3' | ||||
|     implementation 'com.google.android.gms:play-services-safetynet:9.0.1' | ||||
|     annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' | ||||
| } | ||||
|   | ||||
							
								
								
									
										12
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							| @@ -16,10 +16,10 @@ | ||||
| #   public *; | ||||
| #} | ||||
|  | ||||
| -keep class android.support.v7.internal.** { *; } | ||||
| -keep interface android.support.v7.internal.** { *; } | ||||
| -keep class android.support.v7.** { *; } | ||||
| -keep interface android.support.v7.** { *; } | ||||
| # BouncyCastle | ||||
| -keep class org.bouncycastle.** { *; } | ||||
| -dontwarn javax.naming.** | ||||
|  | ||||
| -dontwarn android.content.** | ||||
| -dontwarn android.animation.** | ||||
|  | ||||
| # SpongyCastle | ||||
| -keep class org.spongycastle.** {*;} | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest package="com.topjohnwu.magisk" | ||||
|           xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|  | ||||
|           xmlns:tools="http://schemas.android.com/tools"> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     package="com.topjohnwu.magisk"> | ||||
|  | ||||
|     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | ||||
|     <uses-permission android:name="android.permission.INTERNET" /> | ||||
|     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||||
|     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> | ||||
|     <uses-permission android:name="android.permission.VIBRATE" /> | ||||
|     <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> | ||||
|  | ||||
|     <application | ||||
|         android:name=".MagiskManager" | ||||
| @@ -17,12 +17,12 @@ | ||||
|         android:label="@string/app_name" | ||||
|         android:supportsRtl="true" | ||||
|         android:theme="@style/AppTheme" | ||||
|         tools:ignore="AllowBackup,GoogleAppIndexingWarning"> | ||||
|         android:directBootAware="true" | ||||
|         tools:ignore="UnusedAttribute"> | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
|             android:configChanges="orientation|screenSize" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|             android:exported="true" /> | ||||
|         <activity | ||||
|             android:name=".SplashActivity" | ||||
|             android:configChanges="orientation|screenSize" | ||||
| @@ -30,16 +30,22 @@ | ||||
|             android:theme="@style/SplashTheme"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.MAIN" /> | ||||
|  | ||||
|                 <category android:name="android.intent.category.LAUNCHER" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".AboutActivity" | ||||
|             android:theme="@style/AppTheme.Transparent"/> | ||||
|             android:theme="@style/AppTheme.Transparent" /> | ||||
|         <activity | ||||
|             android:name=".SettingsActivity" | ||||
|             android:theme="@style/AppTheme.Transparent" /> | ||||
|         <activity | ||||
|             android:name=".FlashActivity" | ||||
|             android:screenOrientation="nosensor" | ||||
|             android:configChanges="keyboardHidden|orientation|screenSize" | ||||
|             android:theme="@style/AppTheme.Transparent" /> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".superuser.RequestActivity" | ||||
|             android:excludeFromRecents="true" | ||||
| @@ -52,21 +58,27 @@ | ||||
|             android:taskAffinity="internal.superuser" | ||||
|             android:theme="@style/SuRequest" /> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".superuser.SuReceiver" /> | ||||
|  | ||||
|         <receiver android:name=".superuser.SuReceiver" /> | ||||
|         <receiver android:name=".receivers.BootReceiver"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.BOOT_COMPLETED" /> | ||||
|             </intent-filter> | ||||
|         </receiver> | ||||
|         <receiver android:name=".receivers.PackageReceiver"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.PACKAGE_REPLACED" /> | ||||
|                 <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" /> | ||||
|  | ||||
|         <service android:name=".services.BootupIntentService" /> | ||||
|                 <data android:scheme="package" /> | ||||
|             </intent-filter> | ||||
|         </receiver> | ||||
|         <receiver android:name=".receivers.ManagerUpdate" /> | ||||
|  | ||||
|         <service android:name=".services.OnBootIntentService" /> | ||||
|         <service | ||||
|             android:name=".services.UpdateCheckService" | ||||
|             android:permission="android.permission.BIND_JOB_SERVICE" | ||||
|             android:exported="true" /> | ||||
|             android:exported="true" | ||||
|             android:permission="android.permission.BIND_JOB_SERVICE" /> | ||||
|  | ||||
|         <provider | ||||
|             android:name="android.support.v4.content.FileProvider" | ||||
| @@ -84,4 +96,4 @@ | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| </manifest> | ||||
| @@ -1,150 +0,0 @@ | ||||
| #!/system/bin/sh | ||||
|  | ||||
| [ -z $BOOTMODE ] && BOOTMODE=false | ||||
| TMPDIR=/tmp | ||||
| ($BOOTMODE) && TMPDIR=/dev/tmp | ||||
|  | ||||
| BINDIR=/data/magisk | ||||
| CHROMEDIR=$BINDIR/chromeos | ||||
|  | ||||
| NEWBOOT=$TMPDIR/boottmp/new-boot.img | ||||
| UNPACKDIR=$TMPDIR/boottmp/bootunpack | ||||
| RAMDISK=$TMPDIR/boottmp/ramdisk | ||||
|  | ||||
| SYSTEMLIB=/system/lib | ||||
| [ -d /system/lib64 ] && SYSTEMLIB=/system/lib64 | ||||
|  | ||||
| ui_print() { | ||||
|   echo "$1" | ||||
| } | ||||
|  | ||||
| grep_prop() { | ||||
|   REGEX="s/^$1=//p" | ||||
|   shift | ||||
|   FILES=$@ | ||||
|   if [ -z "$FILES" ]; then | ||||
|     FILES='/system/build.prop' | ||||
|   fi | ||||
|   cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1 | ||||
| } | ||||
|  | ||||
| find_boot_image() { | ||||
|   if [ -z "$BOOTIMAGE" ]; then | ||||
|     for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do | ||||
|       BOOTIMAGE=`readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION` | ||||
|       if [ ! -z "$BOOTIMAGE" ]; then break; fi | ||||
|     done | ||||
|   fi | ||||
|   if [ -z "$BOOTIMAGE" ]; then | ||||
|     FSTAB="/etc/recovery.fstab" | ||||
|     [ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak" | ||||
|     [ -f "$FSTAB" ] && BOOTIMAGE=`grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*'` | ||||
|   fi | ||||
| } | ||||
|  | ||||
| unpack_boot() { | ||||
|   rm -rf $UNPACKDIR $RAMDISK 2>/dev/null | ||||
|   mkdir -p $UNPACKDIR | ||||
|   mkdir -p $RAMDISK | ||||
|   cd $UNPACKDIR | ||||
|   LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/bootimgtools --extract $1 | ||||
|  | ||||
|   cd $RAMDISK | ||||
|   $BINDIR/busybox gunzip -c < $UNPACKDIR/ramdisk.gz | cpio -i | ||||
| } | ||||
|  | ||||
| repack_boot() { | ||||
|   cd $RAMDISK | ||||
|   find . | cpio -o -H newc 2>/dev/null | gzip -9 > $UNPACKDIR/ramdisk.gz | ||||
|   cd $UNPACKDIR | ||||
|   LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/bootimgtools --repack $BOOTIMAGE | ||||
|   if [ -f chromeos ]; then | ||||
|     echo " " > config | ||||
|     echo " " > bootloader | ||||
|     LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz new-boot.img --config config --arch arm --bootloader bootloader --flags 0x1 | ||||
|     rm -f new-boot.img | ||||
|     mv new-boot.img.signed new-boot.img | ||||
|   fi | ||||
|   if ($SAMSUNG); then | ||||
|     SAMSUNG_CHECK=$(cat new-boot.img | grep SEANDROIDENFORCE) | ||||
|     if [ $? -ne 0 ]; then | ||||
|       echo -n "SEANDROIDENFORCE" >> new-boot.img | ||||
|     fi | ||||
|   fi | ||||
|   if ($LGE_G); then | ||||
|     # Prevent secure boot error on LG G2/G3. | ||||
|     # Just for know, It's a pattern which bootloader verifies at boot. Thanks to LG hackers. | ||||
|     echo -n -e "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79" >> new-boot.img | ||||
|   fi | ||||
|   mv new-boot.img $NEWBOOT | ||||
| } | ||||
|  | ||||
| # Set permissions | ||||
| chmod -R 755 $CHROMEDIR/futility $BINDIR | ||||
|  | ||||
| # Find the boot image | ||||
| find_boot_image | ||||
| if [ -z "$BOOTIMAGE" ]; then | ||||
|   ui_print "! Unable to detect boot image" | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| ui_print "- Found Boot Image: $BOOTIMAGE" | ||||
|  | ||||
| # Detect special vendors  | ||||
| SAMSUNG=false | ||||
| SAMSUNG_CHECK=$(cat /system/build.prop | grep "ro.build.fingerprint=" | grep -i "samsung") | ||||
| if [ $? -eq 0 ]; then | ||||
|   SAMSUNG=true | ||||
| fi | ||||
| LGE_G=false | ||||
| RBRAND=$(grep_prop ro.product.brand) | ||||
| RMODEL=$(grep_prop ro.product.device) | ||||
| if [ "$RBRAND" = "lge" ] || [ "$RBRAND" = "LGE" ];  then  | ||||
|   if [ "$RMODEL" = "*D80*" ] ||  | ||||
|      [ "$RMODEL" = "*S98*" ] ||  | ||||
|      [ "$RMODEL" = "*D85*" ] || | ||||
|      [ "$RMODEL" = "*F40*" ]; then | ||||
|     LGE_G=true | ||||
|     ui_print "! Bump device detected" | ||||
|   fi | ||||
| fi | ||||
|  | ||||
| # First unpack the boot image | ||||
| unpack_boot $BOOTIMAGE | ||||
|  | ||||
| SUPERSU=false | ||||
| [ -f sbin/launch_daemonsu.sh ] && SUPERSU=true | ||||
|  | ||||
| if ($SUPERSU); then | ||||
|   ui_print "- SuperSU patched image detected" | ||||
|   rm -f magisk sbin/init.magisk.rc sbin/magic_mask.sh | ||||
|   repack_boot | ||||
| else | ||||
|   if [ -f /data/stock_boot.img ]; then | ||||
|     ui_print "- Boot image backup found!" | ||||
|     NEWBOOT=/data/stock_boot.img | ||||
|   else | ||||
|     ui_print "! Boot image backup unavailable" | ||||
|     if [ -d ".backup" ]; then | ||||
|       ui_print "- Restoring ramdisk with backup" | ||||
|       cp -af .backup/. . | ||||
|     fi | ||||
|     rm -f magisk sbin/init.magisk.rc sbin/magic_mask.sh | ||||
|     repack_boot | ||||
|   fi | ||||
| fi | ||||
|  | ||||
| chmod 644 $NEWBOOT | ||||
|  | ||||
| ui_print "- Flashing stock/reverted image" | ||||
| [ ! -L "$BOOTIMAGE" ] && dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null | ||||
| dd if=$NEWBOOT of=$BOOTIMAGE bs=4096 | ||||
|  | ||||
| ui_print "- Removing Magisk files" | ||||
| rm -rf  /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \ | ||||
|         /cache/magisk /cache/magisk_merge /cache/magisk_mount  /cache/unblock /cache/magisk_uninstaller.sh \ | ||||
|         /data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img \ | ||||
|         /data/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null | ||||
|  | ||||
| ($BOOTMODE) && reboot | ||||
										
											Binary file not shown.
										
									
								
							| @@ -1,27 +0,0 @@ | ||||
| -----BEGIN CERTIFICATE----- | ||||
| MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD | ||||
| VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g | ||||
| VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE | ||||
| AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe | ||||
| Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET | ||||
| MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G | ||||
| A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p | ||||
| ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI | ||||
| hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM | ||||
| qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 | ||||
| wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy | ||||
| 4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU | ||||
| RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s | ||||
| zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw | ||||
| HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ | ||||
| AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE | ||||
| CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH | ||||
| QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG | ||||
| CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud | ||||
| EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa | ||||
| J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y | ||||
| LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe | ||||
| +ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX | ||||
| 31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr | ||||
| sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0= | ||||
| -----END CERTIFICATE----- | ||||
| @@ -3,7 +3,6 @@ package com.topjohnwu.magisk; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.preference.PreferenceManager; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v7.app.ActionBar; | ||||
| import android.support.v7.app.AlertDialog; | ||||
| @@ -13,13 +12,11 @@ import android.text.Spanned; | ||||
| import android.text.TextUtils; | ||||
| import android.text.method.LinkMovementMethod; | ||||
| import android.view.View; | ||||
| import android.view.WindowManager; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.components.AboutCardRow; | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
| import com.topjohnwu.magisk.components.AlertDialogBuilder; | ||||
| import com.topjohnwu.magisk.utils.Logger; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| @@ -29,7 +26,7 @@ import butterknife.ButterKnife; | ||||
|  | ||||
| public class AboutActivity extends Activity { | ||||
|  | ||||
|     private static final String DONATION_URL = "http://topjohnwu.github.io/donate"; | ||||
|     private static final String DONATION_URL = "https://www.paypal.me/topjohnwu"; | ||||
|     private static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382"; | ||||
|     private static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/MagiskManager"; | ||||
|  | ||||
| @@ -45,10 +42,8 @@ public class AboutActivity extends Activity { | ||||
|     @Override | ||||
|     protected void onCreate(@Nullable Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         String theme = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("theme", ""); | ||||
|         Logger.dev("AboutActivity: Theme is " + theme); | ||||
|         if (getApplicationContext().isDarkTheme) { | ||||
|             setTheme(R.style.AppTheme_Dark); | ||||
|         if (getMagiskManager().isDarkTheme) { | ||||
|             setTheme(R.style.AppTheme_Transparent_Dark); | ||||
|         } | ||||
|         setContentView(R.layout.activity_about); | ||||
|         ButterKnife.bind(this); | ||||
| @@ -135,18 +130,4 @@ public class AboutActivity extends Activity { | ||||
|         setFloating(); | ||||
|     } | ||||
|  | ||||
|     public void setFloating() { | ||||
|         boolean isTablet = getResources().getBoolean(R.bool.isTablet); | ||||
|         if (isTablet) { | ||||
|             WindowManager.LayoutParams params = getWindow().getAttributes(); | ||||
|             params.height = getResources().getDimensionPixelSize(R.dimen.floating_height); | ||||
|             params.width = getResources().getDimensionPixelSize(R.dimen.floating_width); | ||||
|             params.alpha = 1.0f; | ||||
|             params.dimAmount = 0.6f; | ||||
|             params.flags |= 2; | ||||
|             getWindow().setAttributes(params); | ||||
|             setFinishOnTouchOutside(true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
							
								
								
									
										151
									
								
								app/src/main/java/com/topjohnwu/magisk/FlashActivity.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								app/src/main/java/com/topjohnwu/magisk/FlashActivity.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.support.v7.app.ActionBar; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.Button; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.asyncs.FlashZip; | ||||
| import com.topjohnwu.magisk.asyncs.InstallMagisk; | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
| import com.topjohnwu.magisk.utils.AdaptiveList; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| import butterknife.OnClick; | ||||
|  | ||||
| public class FlashActivity extends Activity { | ||||
|  | ||||
|     public static final String SET_ACTION = "action"; | ||||
|     public static final String SET_BOOT = "boot"; | ||||
|     public static final String SET_ENC = "enc"; | ||||
|     public static final String SET_VERITY = "verity"; | ||||
|  | ||||
|     public static final String FLASH_ZIP = "flash"; | ||||
|     public static final String PATCH_BOOT = "patch"; | ||||
|     public static final String FLASH_MAGISK = "magisk"; | ||||
|  | ||||
|     @BindView(R.id.toolbar) Toolbar toolbar; | ||||
|     @BindView(R.id.flash_logs) RecyclerView flashLogs; | ||||
|     @BindView(R.id.button_panel) LinearLayout buttonPanel; | ||||
|     @BindView(R.id.reboot) Button reboot; | ||||
|  | ||||
|     @OnClick(R.id.no_thanks) | ||||
|     public void dismiss() { | ||||
|         finish(); | ||||
|     } | ||||
|  | ||||
|     @OnClick(R.id.reboot) | ||||
|     public void reboot() { | ||||
|         getShell().su_raw("reboot"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_flash); | ||||
|         ButterKnife.bind(this); | ||||
|         AdaptiveList<String> rootShellOutput = new AdaptiveList<>(flashLogs); | ||||
|         setSupportActionBar(toolbar); | ||||
|         ActionBar ab = getSupportActionBar(); | ||||
|         if (ab != null) { | ||||
|             ab.setTitle(R.string.flashing); | ||||
|         } | ||||
|         setFloating(); | ||||
|         if (!Shell.rootAccess()) | ||||
|             reboot.setVisibility(View.GONE); | ||||
|  | ||||
|         flashLogs.setAdapter(new FlashLogAdapter(rootShellOutput)); | ||||
|  | ||||
|         // We must receive a Uri of the target zip | ||||
|         Intent intent = getIntent(); | ||||
|         Uri uri = intent.getData(); | ||||
|  | ||||
|         boolean keepEnc = intent.getBooleanExtra(SET_ENC, false); | ||||
|         boolean keepVerity = intent.getBooleanExtra(SET_VERITY, false); | ||||
|  | ||||
|         switch (getIntent().getStringExtra(SET_ACTION)) { | ||||
|             case FLASH_ZIP: | ||||
|                 new FlashZip(this, uri, rootShellOutput) | ||||
|                         .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) | ||||
|                         .exec(); | ||||
|                 break; | ||||
|             case PATCH_BOOT: | ||||
|                 new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(SET_BOOT)) | ||||
|                         .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) | ||||
|                         .exec(); | ||||
|                 break; | ||||
|             case FLASH_MAGISK: | ||||
|                 String boot = intent.getStringExtra(SET_BOOT); | ||||
|                 if (getMagiskManager().remoteMagiskVersionCode < 1370) { | ||||
|                     // Use legacy installation method | ||||
|                     getShell().su_raw( | ||||
|                             "echo \"BOOTIMAGE=" + boot + "\" > /dev/.magisk", | ||||
|                             "echo \"KEEPFORCEENCRYPT=" + keepEnc + "\" >> /dev/.magisk", | ||||
|                             "echo \"KEEPVERITY=" + keepVerity + "\" >> /dev/.magisk" | ||||
|                     ); | ||||
|                     new FlashZip(this, uri, rootShellOutput) | ||||
|                             .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) | ||||
|                             .exec(); | ||||
|                 } else { | ||||
|                     // Use new installation method | ||||
|                     new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, boot) | ||||
|                             .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) | ||||
|                             .exec(); | ||||
|                 } | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBackPressed() { | ||||
|         // Prevent user accidentally press back button | ||||
|     } | ||||
|  | ||||
|     private static class FlashLogAdapter extends RecyclerView.Adapter<ViewHolder> { | ||||
|  | ||||
|         private List<String> mList; | ||||
|  | ||||
|         FlashLogAdapter(List<String> list) { | ||||
|             mList = list; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|             View view = LayoutInflater.from(parent.getContext()) | ||||
|                     .inflate(R.layout.list_item_flashlog, parent, false); | ||||
|             return new ViewHolder(view); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onBindViewHolder(ViewHolder holder, int position) { | ||||
|             holder.text.setText(mList.get(position)); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int getItemCount() { | ||||
|             return mList.size(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static class ViewHolder extends RecyclerView.ViewHolder { | ||||
|  | ||||
|         @BindView(R.id.textView) TextView text; | ||||
|  | ||||
|         public ViewHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             ButterKnife.bind(this, itemView); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,224 +0,0 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.app.ProgressDialog; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.os.CountDownTimer; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.design.widget.Snackbar; | ||||
| import android.support.v7.widget.CardView; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.ArrayAdapter; | ||||
| import android.widget.Button; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.Spinner; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.asyncs.ProcessMagiskZip; | ||||
| import com.topjohnwu.magisk.components.AlertDialogBuilder; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.components.SnackbarMaker; | ||||
| import com.topjohnwu.magisk.receivers.DownloadReceiver; | ||||
| import com.topjohnwu.magisk.utils.CallbackEvent; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| import butterknife.OnClick; | ||||
| import butterknife.Unbinder; | ||||
|  | ||||
| public class InstallFragment extends Fragment implements CallbackEvent.Listener<Void> { | ||||
|  | ||||
|  | ||||
|     private static final String UNINSTALLER = "magisk_uninstaller.sh"; | ||||
|  | ||||
|     @BindView(R.id.current_version_title) TextView currentVersionTitle; | ||||
|     @BindView(R.id.install_title) TextView installTitle; | ||||
|     @BindView(R.id.block_spinner) Spinner spinner; | ||||
|     @BindView(R.id.detect_bootimage) Button detectButton; | ||||
|     @BindView(R.id.install_button) CardView installButton; | ||||
|     @BindView(R.id.install_text) TextView installText; | ||||
|     @BindView(R.id.uninstall_button) CardView uninstallButton; | ||||
|     @BindView(R.id.keep_force_enc) CheckBox keepEncChkbox; | ||||
|     @BindView(R.id.keep_verity) CheckBox keepVerityChkbox; | ||||
|  | ||||
|     @OnClick(R.id.detect_bootimage) | ||||
|     public void toAutoDetect() { | ||||
|         if (magiskManager.bootBlock != null) { | ||||
|             spinner.setSelection(0); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @OnClick(R.id.install_button) | ||||
|     public void install() { | ||||
|         String bootImage = null; | ||||
|         if (magiskManager.blockList != null) { | ||||
|             int idx = spinner.getSelectedItemPosition(); | ||||
|             if (magiskManager.bootBlock != null) { | ||||
|                 if (idx > 0) { | ||||
|                     bootImage = magiskManager.blockList.get(idx - 1); | ||||
|                 } | ||||
|             } else { | ||||
|                 if (idx > 0)  { | ||||
|                     bootImage = magiskManager.blockList.get(idx - 1); | ||||
|                 } else { | ||||
|                     SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         final String finalBootImage = bootImage; | ||||
|         String filename = "Magisk-v" + magiskManager.remoteMagiskVersion + ".zip"; | ||||
|         new AlertDialogBuilder(getActivity()) | ||||
|                 .setTitle(getString(R.string.repo_install_title, getString(R.string.magisk))) | ||||
|                 .setMessage(getString(R.string.repo_install_msg, filename)) | ||||
|                 .setCancelable(true) | ||||
|                 .setPositiveButton(Shell.rootAccess() ? R.string.install : R.string.download, | ||||
|                     (dialogInterface, i) -> Utils.dlAndReceive( | ||||
|                         getActivity(), | ||||
|                         new DownloadReceiver() { | ||||
|                             private String boot = finalBootImage; | ||||
|                             private boolean enc = keepEncChkbox.isChecked(); | ||||
|                             private boolean verity = keepVerityChkbox.isChecked(); | ||||
|  | ||||
|                             @Override | ||||
|                             public void onDownloadDone(Uri uri) { | ||||
|                                 new ProcessMagiskZip(getActivity(), uri, boot, enc, verity).exec(); | ||||
|                             } | ||||
|                         }, | ||||
|                         magiskManager.magiskLink, | ||||
|                         Utils.getLegalFilename(filename))) | ||||
|                 .setNeutralButton(R.string.release_notes, (dialog, which) -> { | ||||
|                     magiskManager.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink))); | ||||
|                 }) | ||||
|                 .setNegativeButton(R.string.no_thanks, null) | ||||
|                 .show(); | ||||
|     } | ||||
|  | ||||
|     @OnClick(R.id.uninstall_button) | ||||
|     public void uninstall() { | ||||
|         new AlertDialogBuilder(getActivity()) | ||||
|                 .setTitle(R.string.uninstall_magisk_title) | ||||
|                 .setMessage(R.string.uninstall_magisk_msg) | ||||
|                 .setPositiveButton(R.string.yes, (dialogInterface, i) -> { | ||||
|                     try { | ||||
|                         InputStream in = magiskManager.getAssets().open(UNINSTALLER); | ||||
|                         File uninstaller = new File(magiskManager.getCacheDir(), UNINSTALLER); | ||||
|                         FileOutputStream out = new FileOutputStream(uninstaller); | ||||
|                         byte[] bytes = new byte[1024]; | ||||
|                         int read; | ||||
|                         while ((read = in.read(bytes)) != -1) { | ||||
|                             out.write(bytes, 0, read); | ||||
|                         } | ||||
|                         in.close(); | ||||
|                         out.close(); | ||||
|                         ProgressDialog progress = new ProgressDialog(getActivity()); | ||||
|                         progress.setTitle(R.string.reboot); | ||||
|                         progress.show(); | ||||
|                         new CountDownTimer(5000, 1000) { | ||||
|                             @Override | ||||
|                             public void onTick(long millisUntilFinished) { | ||||
|                                 progress.setMessage(getString(R.string.reboot_countdown, millisUntilFinished / 1000)); | ||||
|                             } | ||||
|  | ||||
|                             @Override | ||||
|                             public void onFinish() { | ||||
|                                 progress.setMessage(getString(R.string.reboot_countdown, 0)); | ||||
|                                 Shell.su(true, "mv -f " + uninstaller + " /cache/" + UNINSTALLER, | ||||
|                                         "reboot"); | ||||
|                             } | ||||
|                         }.start(); | ||||
|                     } catch (IOException e) { | ||||
|                         e.printStackTrace(); | ||||
|                     } | ||||
|                 }) | ||||
|                 .setNegativeButton(R.string.no_thanks, null) | ||||
|                 .show(); | ||||
|     } | ||||
|  | ||||
|     private Unbinder unbinder; | ||||
|     private MagiskManager magiskManager; | ||||
|  | ||||
|     @Nullable | ||||
|     @Override | ||||
|     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | ||||
|         View v = inflater.inflate(R.layout.fragment_install, container, false); | ||||
|         unbinder = ButterKnife.bind(this, v); | ||||
|         magiskManager = getApplication(); | ||||
|         if (magiskManager.magiskVersion < 0) { | ||||
|             currentVersionTitle.setText(getString(R.string.current_magisk_title, getString(R.string.version_none))); | ||||
|         } else { | ||||
|             currentVersionTitle.setText(getString(R.string.current_magisk_title, "v" + magiskManager.magiskVersionString)); | ||||
|         } | ||||
|         installTitle.setText(getString(R.string.install_magisk_title, "v" + String.format(Locale.US, "%.1f", magiskManager.remoteMagiskVersion))); | ||||
|  | ||||
|         updateUI(); | ||||
|         return v; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTrigger(CallbackEvent<Void> event) { | ||||
|         updateUI(); | ||||
|     } | ||||
|  | ||||
|     private void updateUI() { | ||||
|         if (magiskManager.blockList == null || !Shell.rootAccess()) { | ||||
|             uninstallButton.setVisibility(View.GONE); | ||||
|             installText.setText(R.string.download); | ||||
|             detectButton.setEnabled(false); | ||||
|             keepEncChkbox.setEnabled(false); | ||||
|             keepVerityChkbox.setEnabled(false); | ||||
|             spinner.setEnabled(false); | ||||
|         } else { | ||||
|             uninstallButton.setVisibility(magiskManager.magiskVersion > 10.3 ? View.VISIBLE : View.GONE); | ||||
|             installText.setText(R.string.download_install); | ||||
|             detectButton.setEnabled(true); | ||||
|             keepEncChkbox.setEnabled(true); | ||||
|             keepVerityChkbox.setEnabled(true); | ||||
|             spinner.setEnabled(true); | ||||
|  | ||||
|             List<String> items = new ArrayList<>(); | ||||
|             if (magiskManager.bootBlock != null) { | ||||
|                 items.add(getString(R.string.auto_detect, magiskManager.bootBlock)); | ||||
|             } else { | ||||
|                 items.add(getString(R.string.cannot_auto_detect)); | ||||
|             } | ||||
|             items.addAll(magiskManager.blockList); | ||||
|             ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(), | ||||
|                     android.R.layout.simple_spinner_item, items); | ||||
|             adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); | ||||
|             spinner.setAdapter(adapter); | ||||
|             toAutoDetect(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|         getActivity().setTitle(R.string.install); | ||||
|         magiskManager.blockDetectionDone.register(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStop() { | ||||
|         magiskManager.blockDetectionDone.unRegister(this); | ||||
|         super.onStop(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroyView() { | ||||
|         super.onDestroyView(); | ||||
|         unbinder.unbind(); | ||||
|     } | ||||
| } | ||||
| @@ -29,9 +29,9 @@ public class LogFragment extends Fragment { | ||||
|         View v = inflater.inflate(R.layout.fragment_log, container, false); | ||||
|         unbinder = ButterKnife.bind(this, v); | ||||
|  | ||||
|         TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager()); | ||||
|         ((MainActivity) getActivity()).toolbar.setElevation(0); | ||||
|  | ||||
|         adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk)); | ||||
|         TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager()); | ||||
|  | ||||
|         if (getApplication().isSuClient) { | ||||
|             adapter.addTab(new SuLogFragment(), getString(R.string.superuser)); | ||||
| @@ -39,6 +39,8 @@ public class LogFragment extends Fragment { | ||||
|             tab.setVisibility(View.VISIBLE); | ||||
|         } | ||||
|  | ||||
|         adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk)); | ||||
|  | ||||
|         viewPager.setAdapter(adapter); | ||||
|  | ||||
|         return v; | ||||
|   | ||||
							
								
								
									
										339
									
								
								app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,12 +1,9 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| 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 }; | ||||
|     } | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,15 +1,11 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.Manifest; | ||||
| import android.content.Intent; | ||||
| import android.content.SharedPreferences; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.design.widget.NavigationView; | ||||
| import android.support.v4.app.ActivityCompat; | ||||
| import android.support.v4.app.Fragment; | ||||
| import android.support.v4.app.FragmentTransaction; | ||||
| import android.support.v4.widget.DrawerLayout; | ||||
| @@ -20,14 +16,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; | ||||
| @@ -41,24 +38,20 @@ public class MainActivity extends Activity | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(final Bundle savedInstanceState) { | ||||
|         getMagiskManager().startup(); | ||||
|  | ||||
|         prefs = getApplicationContext().prefs; | ||||
|         prefs = getMagiskManager().prefs; | ||||
|  | ||||
|         if (getApplicationContext().isDarkTheme) { | ||||
|         if (getMagiskManager().isDarkTheme) { | ||||
|             setTheme(R.style.AppTheme_Dark); | ||||
|         } | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_main); | ||||
|         ButterKnife.bind(this); | ||||
|  | ||||
|         if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED | ||||
|                 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||||
|             requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); | ||||
|         } | ||||
|  | ||||
|         setSupportActionBar(toolbar); | ||||
|  | ||||
|         ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) { | ||||
|         ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.magisk, R.string.magisk) { | ||||
|             @Override | ||||
|             public void onDrawerOpened(View drawerView) { | ||||
|                 super.onDrawerOpened(drawerView); | ||||
| @@ -80,7 +73,6 @@ public class MainActivity extends Activity | ||||
|             navigate(getIntent().getStringExtra(MagiskManager.INTENT_SECTION)); | ||||
|  | ||||
|         navigationView.setNavigationItemSelectedListener(this); | ||||
|         getApplicationContext().reloadMainActivity.register(this); | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -90,30 +82,15 @@ public class MainActivity extends Activity | ||||
|         checkHideSection(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onRestoreInstanceState(Bundle savedInstanceState) { | ||||
|         super.onRestoreInstanceState(savedInstanceState); | ||||
|         navigate(savedInstanceState.getInt(MagiskManager.INTENT_SECTION, R.id.status)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onSaveInstanceState(Bundle outState) { | ||||
|         super.onSaveInstanceState(outState); | ||||
|         outState.putInt(MagiskManager.INTENT_SECTION, mDrawerItem); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         getApplicationContext().reloadMainActivity.unRegister(this); | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBackPressed() { | ||||
|         if (drawer.isDrawerOpen(navigationView)) | ||||
|         if (drawer.isDrawerOpen(navigationView)) { | ||||
|             drawer.closeDrawer(navigationView); | ||||
|         else | ||||
|         } else if (mDrawerItem != R.id.magisk) { | ||||
|             navigate(R.id.magisk); | ||||
|         } else { | ||||
|             finish(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -125,34 +102,35 @@ public class MainActivity extends Activity | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTrigger(CallbackEvent<Void> event) { | ||||
|     public void onTopicPublished(Topic topic) { | ||||
|         recreate(); | ||||
|     } | ||||
|  | ||||
|     private void checkHideSection() { | ||||
|     @Override | ||||
|     public Topic[] getSubscription() { | ||||
|         return new Topic[] { getMagiskManager().reloadActivity }; | ||||
|     } | ||||
|  | ||||
|     public void checkHideSection() { | ||||
|         Menu menu = navigationView.getMenu(); | ||||
|         menu.findItem(R.id.magiskhide).setVisible( | ||||
|                 Shell.rootAccess() && getApplicationContext().magiskVersion >= 8 | ||||
|                 Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 1300 | ||||
|                         && prefs.getBoolean("magiskhide", false)); | ||||
|         menu.findItem(R.id.modules).setVisible( | ||||
|                 Shell.rootAccess() && getApplicationContext().magiskVersion >= 4); | ||||
|         menu.findItem(R.id.downloads).setVisible( | ||||
|                 Shell.rootAccess() && getApplicationContext().magiskVersion >= 4); | ||||
|                 Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 0); | ||||
|         menu.findItem(R.id.downloads).setVisible(Utils.checkNetworkStatus(this) && | ||||
|                 Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 0); | ||||
|         menu.findItem(R.id.log).setVisible(Shell.rootAccess()); | ||||
|         menu.findItem(R.id.superuser).setVisible( | ||||
|                 Shell.rootAccess() && getApplicationContext().isSuClient); | ||||
|         menu.findItem(R.id.install).setVisible(getApplicationContext().remoteMagiskVersion > 0); | ||||
|                 Shell.rootAccess() && getMagiskManager().isSuClient); | ||||
|     } | ||||
|  | ||||
|     public void navigate(String item) { | ||||
|         int itemId = R.id.status; | ||||
|         int itemId = R.id.magisk; | ||||
|         if (item != null) { | ||||
|             switch (item) { | ||||
|                 case "status": | ||||
|                     itemId = R.id.status; | ||||
|                     break; | ||||
|                 case "install": | ||||
|                     itemId = R.id.install; | ||||
|                 case "magisk": | ||||
|                     itemId = R.id.magisk; | ||||
|                     break; | ||||
|                 case "superuser": | ||||
|                     itemId = R.id.superuser; | ||||
| @@ -185,11 +163,8 @@ public class MainActivity extends Activity | ||||
|         mDrawerItem = itemId; | ||||
|         navigationView.setCheckedItem(itemId); | ||||
|         switch (itemId) { | ||||
|             case R.id.status: | ||||
|                 displayFragment(new StatusFragment(), "status", true); | ||||
|                 break; | ||||
|             case R.id.install: | ||||
|                 displayFragment(new InstallFragment(), "install", true); | ||||
|             case R.id.magisk: | ||||
|                 displayFragment(new MagiskFragment(), "magisk", true); | ||||
|                 break; | ||||
|             case R.id.superuser: | ||||
|                 displayFragment(new SuperuserFragment(), "superuser", true); | ||||
|   | ||||
| @@ -2,7 +2,6 @@ package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v4.widget.SwipeRefreshLayout; | ||||
| @@ -12,23 +11,22 @@ import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.github.clans.fab.FloatingActionButton; | ||||
| import com.topjohnwu.magisk.adapters.ModulesAdapter; | ||||
| import com.topjohnwu.magisk.asyncs.FlashZip; | ||||
| import com.topjohnwu.magisk.asyncs.LoadModules; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.module.Module; | ||||
| import com.topjohnwu.magisk.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; | ||||
|  | ||||
| @@ -36,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<>(); | ||||
|  | ||||
| @@ -46,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(); | ||||
| @@ -69,40 +66,30 @@ 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) { | ||||
|             // Get the URI of the selected file | ||||
|             final Uri uri = data.getData(); | ||||
|             new FlashZip(getActivity(), uri).exec(); | ||||
|             Intent intent = new Intent(getActivity(), FlashActivity.class); | ||||
|             intent.setData(data.getData()).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP); | ||||
|             startActivity(intent); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|         getApplication().moduleLoadDone.register(this); | ||||
|         getActivity().setTitle(R.string.modules); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStop() { | ||||
|         getApplication().moduleLoadDone.unRegister(this); | ||||
|         super.onStop(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -2,7 +2,6 @@ package com.topjohnwu.magisk; | ||||
|  | ||||
| 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.view.LayoutInflater; | ||||
| @@ -14,39 +13,23 @@ import android.widget.SearchView; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.adapters.ReposAdapter; | ||||
| import com.topjohnwu.magisk.adapters.SimpleSectionedRecyclerViewAdapter; | ||||
| import com.topjohnwu.magisk.asyncs.LoadRepos; | ||||
| import com.topjohnwu.magisk.asyncs.ParallelTask; | ||||
| import com.topjohnwu.magisk.asyncs.UpdateRepos; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.module.Module; | ||||
| import com.topjohnwu.magisk.module.Repo; | ||||
| import com.topjohnwu.magisk.utils.CallbackEvent; | ||||
| import com.topjohnwu.magisk.utils.Logger; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import 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; | ||||
|     @BindView(R.id.empty_rv) TextView emptyRv; | ||||
|     @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; | ||||
|  | ||||
|     private List<Repo> mUpdateRepos = new ArrayList<>(); | ||||
|     private List<Repo> mInstalledRepos = new ArrayList<>(); | ||||
|     private List<Repo> mOthersRepos = new ArrayList<>(); | ||||
|     private List<Repo> fUpdateRepos = new ArrayList<>(); | ||||
|     private List<Repo> fInstalledRepos = new ArrayList<>(); | ||||
|     private List<Repo> fOthersRepos = new ArrayList<>(); | ||||
|  | ||||
|     private SimpleSectionedRecyclerViewAdapter mSectionedAdapter; | ||||
|  | ||||
|     private SearchView.OnQueryTextListener searchListener; | ||||
|     private ReposAdapter adapter; | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate(@Nullable Bundle savedInstanceState) { | ||||
| @@ -60,24 +43,40 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo | ||||
|         View view = inflater.inflate(R.layout.fragment_repos, container, false); | ||||
|         unbinder = ButterKnife.bind(this, view); | ||||
|  | ||||
|         mSectionedAdapter = new SimpleSectionedRecyclerViewAdapter(R.layout.section, | ||||
|                 R.id.section_text, new ReposAdapter(fUpdateRepos, fInstalledRepos, fOthersRepos)); | ||||
|  | ||||
|         recyclerView.setAdapter(mSectionedAdapter); | ||||
|         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) { | ||||
|             reloadRepos(); | ||||
|             updateUI(); | ||||
|         } | ||||
|         getActivity().setTitle(R.string.downloads); | ||||
|  | ||||
|         searchListener = new SearchView.OnQueryTextListener() { | ||||
|         return view; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTopicPublished(Topic topic) { | ||||
|         Logger.dev("ReposFragment: UI refresh triggered"); | ||||
|         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 | ||||
|     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { | ||||
|         inflater.inflate(R.menu.menu_repo, menu); | ||||
|         SearchView search = (SearchView) menu.findItem(R.id.repo_search).getActionView(); | ||||
|         search.setOnQueryTextListener(new SearchView.OnQueryTextListener() { | ||||
|             @Override | ||||
|             public boolean onQueryTextSubmit(String query) { | ||||
|                 return false; | ||||
| @@ -85,39 +84,10 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo | ||||
|  | ||||
|             @Override | ||||
|             public boolean onQueryTextChange(String newText) { | ||||
|                 new FilterApps().exec(newText); | ||||
|                 adapter.filter(newText); | ||||
|                 return false; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         return view; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onTrigger(CallbackEvent<Void> event) { | ||||
|         Logger.dev("ReposFragment: UI refresh triggered"); | ||||
|         reloadRepos(); | ||||
|         updateUI(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { | ||||
|         inflater.inflate(R.menu.menu_repo, menu); | ||||
|         SearchView search = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.repo_search)); | ||||
|         search.setOnQueryTextListener(searchListener); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|         getApplication().repoLoadDone.register(this); | ||||
|         getActivity().setTitle(R.string.downloads); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStop() { | ||||
|         getApplication().repoLoadDone.unRegister(this); | ||||
|         super.onStop(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -125,92 +95,4 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo | ||||
|         super.onDestroyView(); | ||||
|         unbinder.unbind(); | ||||
|     } | ||||
|  | ||||
|     private void reloadRepos() { | ||||
|         mUpdateRepos.clear(); | ||||
|         mInstalledRepos.clear(); | ||||
|         mOthersRepos.clear(); | ||||
|         for (Repo repo : getApplication().repoMap.values()) { | ||||
|             Module module = getApplication().moduleMap.get(repo.getId()); | ||||
|             if (module != null) { | ||||
|                 if (repo.getVersionCode() > module.getVersionCode()) { | ||||
|                     mUpdateRepos.add(repo); | ||||
|                 } else { | ||||
|                     mInstalledRepos.add(repo); | ||||
|                 } | ||||
|             } else { | ||||
|                 mOthersRepos.add(repo); | ||||
|             } | ||||
|         } | ||||
|         fUpdateRepos.clear(); | ||||
|         fInstalledRepos.clear(); | ||||
|         fOthersRepos.clear(); | ||||
|         fUpdateRepos.addAll(mUpdateRepos); | ||||
|         fInstalledRepos.addAll(mInstalledRepos); | ||||
|         fOthersRepos.addAll(mOthersRepos); | ||||
|     } | ||||
|  | ||||
|     private void updateUI() { | ||||
|         if (fUpdateRepos.size() + fInstalledRepos.size() + fOthersRepos.size() == 0) { | ||||
|             emptyRv.setVisibility(View.VISIBLE); | ||||
|             recyclerView.setVisibility(View.GONE); | ||||
|         } else { | ||||
|             List<SimpleSectionedRecyclerViewAdapter.Section> sections = new ArrayList<>(); | ||||
|             if (!fUpdateRepos.isEmpty()) { | ||||
|                 sections.add(new SimpleSectionedRecyclerViewAdapter.Section(0, getString(R.string.update_available))); | ||||
|             } | ||||
|             if (!fInstalledRepos.isEmpty()) { | ||||
|                 sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size(), getString(R.string.installed))); | ||||
|             } | ||||
|             if (!fOthersRepos.isEmpty()) { | ||||
|                 sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size() + fInstalledRepos.size(), getString(R.string.not_installed))); | ||||
|             } | ||||
|             SimpleSectionedRecyclerViewAdapter.Section[] array = sections.toArray(new SimpleSectionedRecyclerViewAdapter.Section[sections.size()]); | ||||
|             mSectionedAdapter.setSections(array); | ||||
|             emptyRv.setVisibility(View.GONE); | ||||
|             recyclerView.setVisibility(View.VISIBLE); | ||||
|         } | ||||
|         mSwipeRefreshLayout.setRefreshing(false); | ||||
|     } | ||||
|  | ||||
|     private class FilterApps extends ParallelTask<String, Void, Void> { | ||||
|         @Override | ||||
|         protected Void doInBackground(String... strings) { | ||||
|             String newText = strings[0]; | ||||
|             fUpdateRepos.clear(); | ||||
|             fInstalledRepos.clear(); | ||||
|             fOthersRepos.clear(); | ||||
|             for (Repo repo: mUpdateRepos) { | ||||
|                 if (repo.getName().toLowerCase().contains(newText.toLowerCase()) | ||||
|                         || repo.getAuthor().toLowerCase().contains(newText.toLowerCase()) | ||||
|                         || repo.getDescription().toLowerCase().contains(newText.toLowerCase()) | ||||
|                         ) { | ||||
|                     fUpdateRepos.add(repo); | ||||
|                 } | ||||
|             } | ||||
|             for (Repo repo: mInstalledRepos) { | ||||
|                 if (repo.getName().toLowerCase().contains(newText.toLowerCase()) | ||||
|                         || repo.getAuthor().toLowerCase().contains(newText.toLowerCase()) | ||||
|                         || repo.getDescription().toLowerCase().contains(newText.toLowerCase()) | ||||
|                         ) { | ||||
|                     fInstalledRepos.add(repo); | ||||
|                 } | ||||
|             } | ||||
|             for (Repo repo: mOthersRepos) { | ||||
|                 if (repo.getName().toLowerCase().contains(newText.toLowerCase()) | ||||
|                         || repo.getAuthor().toLowerCase().contains(newText.toLowerCase()) | ||||
|                         || repo.getDescription().toLowerCase().contains(newText.toLowerCase()) | ||||
|                         ) { | ||||
|                     fOthersRepos.add(repo); | ||||
|                 } | ||||
|             } | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected void onPostExecute(Void v) { | ||||
|             updateUI(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,73 +1,24 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.app.job.JobInfo; | ||||
| import android.app.job.JobScheduler; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
|  | ||||
| import com.topjohnwu.magisk.asyncs.CheckUpdates; | ||||
| import com.topjohnwu.magisk.asyncs.GetBootBlocks; | ||||
| import com.topjohnwu.magisk.asyncs.LoadApps; | ||||
| import com.topjohnwu.magisk.asyncs.LoadModules; | ||||
| import com.topjohnwu.magisk.asyncs.LoadRepos; | ||||
| import com.topjohnwu.magisk.asyncs.MagiskHide; | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
| import com.topjohnwu.magisk.services.UpdateCheckService; | ||||
|  | ||||
| public class SplashActivity extends Activity{ | ||||
|  | ||||
|     private static final int UPDATE_SERVICE_ID = 1; | ||||
| public class SplashActivity extends Activity { | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|  | ||||
|         super.onCreate(savedInstanceState); | ||||
|  | ||||
|         MagiskManager magiskManager = getApplicationContext(); | ||||
|         getMagiskManager().startup(); | ||||
|  | ||||
|         // Init the info and configs and root shell | ||||
|         magiskManager.init(); | ||||
|  | ||||
|         // Initialize the update check service, notify every 3 hours | ||||
|         if (!"install".equals(getIntent().getStringExtra(MagiskManager.INTENT_SECTION))) { | ||||
|             ComponentName service = new ComponentName(magiskManager, UpdateCheckService.class); | ||||
|             JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service) | ||||
|                     .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) | ||||
|                     .setPersisted(true) | ||||
|                     .setPeriodic(3 * 60 * 60 * 1000) | ||||
|                     .build(); | ||||
|             JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); | ||||
|             scheduler.schedule(jobInfo); | ||||
|         Intent intent = new Intent(this, MainActivity.class); | ||||
|         String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION); | ||||
|         if (section != null) { | ||||
|             intent.putExtra(MagiskManager.INTENT_SECTION, section); | ||||
|         } | ||||
|  | ||||
|         // Now fire all async tasks | ||||
|         new GetBootBlocks(this).exec(); | ||||
|         if (magiskManager.magiskHide && !magiskManager.disabled && | ||||
|                 magiskManager.magiskVersion > 11 && !magiskManager.magiskHideStarted) { | ||||
|             new MagiskHide().enable(); | ||||
|         } | ||||
|         new LoadModules(this) { | ||||
|             @Override | ||||
|             protected void onPostExecute(Void v) { | ||||
|                 super.onPostExecute(v); | ||||
|                 new LoadRepos(activity).exec(); | ||||
|             } | ||||
|         }.exec(); | ||||
|         new LoadApps(this).exec(); | ||||
|         new CheckUpdates(this, false){ | ||||
|             @Override | ||||
|             protected void onPostExecute(Void v) { | ||||
|                 super.onPostExecute(v); | ||||
|                 String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION); | ||||
|                 Intent intent = new Intent(magiskManager, MainActivity.class); | ||||
|                 if (section != null) { | ||||
|                     intent.putExtra(MagiskManager.INTENT_SECTION, section); | ||||
|                 } | ||||
|                 startActivity(intent); | ||||
|                 finish(); | ||||
|             } | ||||
|         }.exec(); | ||||
|         startActivity(intent); | ||||
|         finish(); | ||||
|     } | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -13,10 +13,6 @@ import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.adapters.SuLogAdapter; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.database.SuLogDatabaseHelper; | ||||
| import com.topjohnwu.magisk.superuser.SuLogEntry; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| @@ -28,7 +24,8 @@ public class SuLogFragment extends Fragment { | ||||
|     @BindView(R.id.recyclerView) RecyclerView recyclerView; | ||||
|  | ||||
|     private Unbinder unbinder; | ||||
|     private SuLogDatabaseHelper dbHelper; | ||||
|     private MagiskManager mm; | ||||
|     private SuLogAdapter adapter; | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate(@Nullable Bundle savedInstanceState) { | ||||
| @@ -48,8 +45,9 @@ public class SuLogFragment extends Fragment { | ||||
|         // Inflate the layout for this fragment | ||||
|         View v = inflater.inflate(R.layout.fragment_su_log, container, false); | ||||
|         unbinder = ButterKnife.bind(this, v); | ||||
|  | ||||
|         dbHelper = new SuLogDatabaseHelper(getActivity()); | ||||
|         mm = getApplication(); | ||||
|         adapter = new SuLogAdapter(mm.suDB); | ||||
|         recyclerView.setAdapter(adapter); | ||||
|  | ||||
|         updateList(); | ||||
|  | ||||
| @@ -57,13 +55,12 @@ public class SuLogFragment extends Fragment { | ||||
|     } | ||||
|  | ||||
|     private void updateList() { | ||||
|         List<SuLogEntry> logs = dbHelper.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); | ||||
|         } | ||||
| @@ -76,7 +73,7 @@ public class SuLogFragment extends Fragment { | ||||
|                 updateList(); | ||||
|                 return true; | ||||
|             case R.id.menu_clear: | ||||
|                 dbHelper.clearLogs(); | ||||
|                 mm.suDB.clearLogs(); | ||||
|                 updateList(); | ||||
|                 return true; | ||||
|             default: | ||||
|   | ||||
| @@ -11,7 +11,6 @@ import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.adapters.PolicyAdapter; | ||||
| import com.topjohnwu.magisk.components.Fragment; | ||||
| import com.topjohnwu.magisk.database.SuDatabaseHelper; | ||||
| import com.topjohnwu.magisk.superuser.Policy; | ||||
|  | ||||
| import java.util.List; | ||||
| @@ -33,15 +32,15 @@ public class SuperuserFragment extends Fragment { | ||||
|         unbinder = ButterKnife.bind(this, view); | ||||
|  | ||||
|         PackageManager pm = getActivity().getPackageManager(); | ||||
|         MagiskManager mm = getApplication(); | ||||
|  | ||||
|         SuDatabaseHelper dbHelper = new SuDatabaseHelper(getActivity()); | ||||
|         List<Policy> policyList = dbHelper.getPolicyList(pm); | ||||
|         List<Policy> policyList = mm.suDB.getPolicyList(pm); | ||||
|  | ||||
|         if (policyList.size() == 0) { | ||||
|             emptyRv.setVisibility(View.VISIBLE); | ||||
|             recyclerView.setVisibility(View.GONE); | ||||
|         } else { | ||||
|             recyclerView.setAdapter(new PolicyAdapter(policyList, dbHelper, pm)); | ||||
|             recyclerView.setAdapter(new PolicyAdapter(policyList, mm.suDB, pm)); | ||||
|             emptyRv.setVisibility(View.GONE); | ||||
|             recyclerView.setVisibility(View.VISIBLE); | ||||
|         } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package com.topjohnwu.magisk.adapters; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.support.design.widget.Snackbar; | ||||
| @@ -13,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; | ||||
| @@ -40,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 | ||||
| @@ -66,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 | ||||
| @@ -86,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().add(info.packageName); | ||||
|                     Utils.addMagiskHide(shell, info.packageName); | ||||
|                     mHideList.add(info.packageName); | ||||
|                 } else { | ||||
|                     new MagiskHide().rm(info.packageName); | ||||
|                     Utils.rmMagiskHide(shell, info.packageName); | ||||
|                     mHideList.remove(info.packageName); | ||||
|                 } | ||||
|             }); | ||||
| @@ -105,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; | ||||
| @@ -122,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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -12,7 +12,6 @@ import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.R; | ||||
| import com.topjohnwu.magisk.asyncs.SerialTask; | ||||
| import com.topjohnwu.magisk.components.SnackbarMaker; | ||||
| import com.topjohnwu.magisk.module.Module; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| @@ -39,6 +38,7 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold | ||||
|     @Override | ||||
|     public void onBindViewHolder(final ViewHolder holder, int position) { | ||||
|         Context context = holder.itemView.getContext(); | ||||
|         Shell rootShell = Shell.getShell(context); | ||||
|         final Module module = mList.get(position); | ||||
|  | ||||
|         String version = module.getVersion(); | ||||
| @@ -53,44 +53,31 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold | ||||
|  | ||||
|         holder.checkBox.setOnCheckedChangeListener(null); | ||||
|         holder.checkBox.setChecked(module.isEnabled()); | ||||
|         holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> new SerialTask<Void, Void, Void>() { | ||||
|             @Override | ||||
|             protected Void doInBackground(Void... voids) { | ||||
|                 if (isChecked) { | ||||
|                     module.removeDisableFile(); | ||||
|                 } else { | ||||
|                     module.createDisableFile(); | ||||
|                 } | ||||
|                 return null; | ||||
|         holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> { | ||||
|             int snack; | ||||
|             if (isChecked) { | ||||
|                 module.removeDisableFile(rootShell); | ||||
|                 snack = R.string.disable_file_removed; | ||||
|             } else { | ||||
|                 module.createDisableFile(rootShell); | ||||
|                 snack = R.string.disable_file_created; | ||||
|             } | ||||
|             SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show(); | ||||
|         }); | ||||
|  | ||||
|             @Override | ||||
|             protected void onPostExecute(Void v) { | ||||
|                 int snack = isChecked ? R.string.disable_file_removed : R.string.disable_file_created; | ||||
|                 SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show(); | ||||
|         holder.delete.setOnClickListener(v -> { | ||||
|             boolean removed = module.willBeRemoved(); | ||||
|             int snack; | ||||
|             if (removed) { | ||||
|                 module.deleteRemoveFile(rootShell); | ||||
|                 snack = R.string.remove_file_deleted; | ||||
|             } else { | ||||
|                 module.createRemoveFile(rootShell); | ||||
|                 snack = R.string.remove_file_created; | ||||
|             } | ||||
|         }.exec()); | ||||
|  | ||||
|         holder.delete.setOnClickListener(v -> new SerialTask<Void, Void, Void>() { | ||||
|             private final boolean removed = module.willBeRemoved(); | ||||
|  | ||||
|             @Override | ||||
|             protected Void doInBackground(Void... voids) { | ||||
|                 if (removed) { | ||||
|                     module.deleteRemoveFile(); | ||||
|                 } else { | ||||
|                     module.createRemoveFile(); | ||||
|                 } | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             protected void onPostExecute(Void v) { | ||||
|                 int snack = removed ? R.string.remove_file_deleted : R.string.remove_file_created; | ||||
|                 SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show(); | ||||
|                 updateDeleteButton(holder, module); | ||||
|             } | ||||
|         }.exec()); | ||||
|             SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show(); | ||||
|             updateDeleteButton(holder, module); | ||||
|         }); | ||||
|  | ||||
|         if (module.isUpdated()) { | ||||
|             holder.notice.setVisibility(View.VISIBLE); | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,9 +1,11 @@ | ||||
| package com.topjohnwu.magisk.adapters; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.Context; | ||||
| import android.net.Uri; | ||||
| import android.database.Cursor; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.text.TextUtils; | ||||
| import android.util.Pair; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| @@ -12,99 +14,164 @@ import android.widget.LinearLayout; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.R; | ||||
| import com.topjohnwu.magisk.asyncs.MarkDownWindow; | ||||
| import com.topjohnwu.magisk.asyncs.ProcessRepoZip; | ||||
| import com.topjohnwu.magisk.components.AlertDialogBuilder; | ||||
| import com.topjohnwu.magisk.components.MarkDownWindow; | ||||
| import com.topjohnwu.magisk.database.RepoDatabaseHelper; | ||||
| import com.topjohnwu.magisk.module.Module; | ||||
| import com.topjohnwu.magisk.module.Repo; | ||||
| import com.topjohnwu.magisk.receivers.DownloadReceiver; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
|  | ||||
| public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> { | ||||
| public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, ReposAdapter.RepoHolder> { | ||||
|  | ||||
|     private List<Repo> mUpdateRepos, mInstalledRepos, mOthersRepos; | ||||
|     private Context mContext; | ||||
|     private static final int UPDATES = 0; | ||||
|     private static final int INSTALLED = 1; | ||||
|     private static final int OTHERS = 2; | ||||
|  | ||||
|     public ReposAdapter(List<Repo> update, List<Repo> installed, List<Repo> others) { | ||||
|         mUpdateRepos = update; | ||||
|         mInstalledRepos = installed; | ||||
|         mOthersRepos = others; | ||||
|     private Cursor repoCursor = null; | ||||
|     private Map<String, Module> moduleMap; | ||||
|     private RepoDatabaseHelper repoDB; | ||||
|     private List<Pair<Integer, List<Repo>>> repoPairs; | ||||
|  | ||||
|     public ReposAdapter(RepoDatabaseHelper db, Map<String, Module> map) { | ||||
|         repoDB = db; | ||||
|         moduleMap = map; | ||||
|         repoPairs = new ArrayList<>(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public int getSectionCount() { | ||||
|         return repoPairs.size(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|         mContext = parent.getContext(); | ||||
|         View v = LayoutInflater.from(mContext).inflate(R.layout.list_item_repo, parent, false); | ||||
|         return new ViewHolder(v); | ||||
|     public int getItemCount(int section) { | ||||
|         return repoPairs.get(section).second.size(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBindViewHolder(final ViewHolder holder, int position) { | ||||
|         Repo repo = getItem(position); | ||||
|     public SectionHolder onCreateSectionViewHolder(ViewGroup parent) { | ||||
|         View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.section, parent, false); | ||||
|         return new SectionHolder(v); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public RepoHolder onCreateItemViewHolder(ViewGroup parent, int viewType) { | ||||
|         View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false); | ||||
|         return new RepoHolder(v); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBindSectionViewHolder(SectionHolder holder, int section) { | ||||
|         switch (repoPairs.get(section).first) { | ||||
|             case UPDATES: | ||||
|                 holder.sectionText.setText(R.string.update_available); | ||||
|                 break; | ||||
|             case INSTALLED: | ||||
|                 holder.sectionText.setText(R.string.installed); | ||||
|                 break; | ||||
|             case OTHERS: | ||||
|                 holder.sectionText.setText(R.string.not_installed); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBindItemViewHolder(RepoHolder holder, int section, int position) { | ||||
|         Repo repo = repoPairs.get(section).second.get(position); | ||||
|         Context context = holder.itemView.getContext(); | ||||
|  | ||||
|         holder.title.setText(repo.getName()); | ||||
|         holder.versionName.setText(repo.getVersion()); | ||||
|         String author = repo.getAuthor(); | ||||
|         holder.author.setText(TextUtils.isEmpty(author) ? null : mContext.getString(R.string.author, author)); | ||||
|         holder.author.setText(TextUtils.isEmpty(author) ? null : context.getString(R.string.author, author)); | ||||
|         holder.description.setText(repo.getDescription()); | ||||
|  | ||||
|         holder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), mContext)); | ||||
|         holder.infoLayout.setOnClickListener(v -> | ||||
|                 new MarkDownWindow((Activity) context, null, repo.getDetailUrl()).exec()); | ||||
|  | ||||
|         holder.downloadImage.setOnClickListener(v -> { | ||||
|             String filename = repo.getName() + "-" + repo.getVersion() + ".zip"; | ||||
|             new AlertDialogBuilder(mContext) | ||||
|                     .setTitle(mContext.getString(R.string.repo_install_title, repo.getName())) | ||||
|                     .setMessage(mContext.getString(R.string.repo_install_msg, filename)) | ||||
|             new AlertDialogBuilder((Activity) context) | ||||
|                     .setTitle(context.getString(R.string.repo_install_title, repo.getName())) | ||||
|                     .setMessage(context.getString(R.string.repo_install_msg, filename)) | ||||
|                     .setCancelable(true) | ||||
|                     .setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive( | ||||
|                             mContext, | ||||
|                             new DownloadReceiver() { | ||||
|                                 @Override | ||||
|                                 public void onDownloadDone(Uri uri) { | ||||
|                                     new ProcessRepoZip(activity, uri, true).exec(); | ||||
|                                 } | ||||
|                             }, | ||||
|                             repo.getZipUrl(), | ||||
|                             Utils.getLegalFilename(filename))) | ||||
|                     .setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive( | ||||
|                             mContext, | ||||
|                             new DownloadReceiver() { | ||||
|                                 @Override | ||||
|                                 public void onDownloadDone(Uri uri) { | ||||
|                                     new ProcessRepoZip(activity, uri, false).exec(); | ||||
|                                 } | ||||
|                             }, | ||||
|                             repo.getZipUrl(), | ||||
|                             Utils.getLegalFilename(filename))) | ||||
|                     .setPositiveButton(R.string.install, (d, i) -> | ||||
|                         new ProcessRepoZip((Activity) context, repo.getZipUrl(), | ||||
|                                 Utils.getLegalFilename(filename), true).exec() | ||||
|                     ) | ||||
|                     .setNeutralButton(R.string.download, (d, i) -> | ||||
|                         new ProcessRepoZip((Activity) context, repo.getZipUrl(), | ||||
|                                 Utils.getLegalFilename(filename), false).exec()) | ||||
|                     .setNegativeButton(R.string.no_thanks, null) | ||||
|                     .show(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return mUpdateRepos.size() + mInstalledRepos.size() + mOthersRepos.size(); | ||||
|     public void notifyDBChanged() { | ||||
|         if (repoCursor != null) | ||||
|             repoCursor.close(); | ||||
|         repoCursor = repoDB.getRepoCursor(); | ||||
|         filter(""); | ||||
|     } | ||||
|  | ||||
|     private Repo getItem(int position) { | ||||
|         if (position >= mUpdateRepos.size()) { | ||||
|             position -= mUpdateRepos.size(); | ||||
|             if (position >= mInstalledRepos.size()) { | ||||
|                 position -= mInstalledRepos.size(); | ||||
|                 return mOthersRepos.get(position); | ||||
|             } else { | ||||
|                 return mInstalledRepos.get(position); | ||||
|     public void filter(String s) { | ||||
|         List<Repo> updates = new ArrayList<>(); | ||||
|         List<Repo> installed = new ArrayList<>(); | ||||
|         List<Repo> others = new ArrayList<>(); | ||||
|  | ||||
|         repoPairs.clear(); | ||||
|         while (repoCursor.moveToNext()) { | ||||
|             Repo repo = new Repo(repoCursor); | ||||
|             if (repo.getName().toLowerCase().contains(s.toLowerCase()) | ||||
|                     || repo.getAuthor().toLowerCase().contains(s.toLowerCase()) | ||||
|                     || repo.getDescription().toLowerCase().contains(s.toLowerCase()) | ||||
|                     ) { | ||||
|                 // Passed the repoFilter | ||||
|                 Module module = moduleMap.get(repo.getId()); | ||||
|                 if (module != null) { | ||||
|                     if (repo.getVersionCode() > module.getVersionCode()) { | ||||
|                         // Updates | ||||
|                         updates.add(repo); | ||||
|                     } else { | ||||
|                         installed.add(repo); | ||||
|                     } | ||||
|                 } else { | ||||
|                     others.add(repo); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             return mUpdateRepos.get(position); | ||||
|         } | ||||
|         repoCursor.moveToFirst(); | ||||
|  | ||||
|         if (!updates.isEmpty()) | ||||
|             repoPairs.add(new Pair<>(UPDATES, updates)); | ||||
|         if (!installed.isEmpty()) | ||||
|             repoPairs.add(new Pair<>(INSTALLED, installed)); | ||||
|         if (!others.isEmpty()) | ||||
|             repoPairs.add(new Pair<>(OTHERS, others)); | ||||
|  | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
|  | ||||
|     static class SectionHolder extends RecyclerView.ViewHolder { | ||||
|  | ||||
|         @BindView(R.id.section_text) TextView sectionText; | ||||
|  | ||||
|         SectionHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             ButterKnife.bind(this, itemView); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     static class ViewHolder extends RecyclerView.ViewHolder { | ||||
|     static class RepoHolder extends RecyclerView.ViewHolder { | ||||
|  | ||||
|         @BindView(R.id.title) TextView title; | ||||
|         @BindView(R.id.version_name) TextView versionName; | ||||
| @@ -113,7 +180,7 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> | ||||
|         @BindView(R.id.info_layout) LinearLayout infoLayout; | ||||
|         @BindView(R.id.download) ImageView downloadImage; | ||||
|  | ||||
|         ViewHolder(View itemView) { | ||||
|         RepoHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             ButterKnife.bind(this, itemView); | ||||
|         } | ||||
|   | ||||
| @@ -0,0 +1,93 @@ | ||||
| package com.topjohnwu.magisk.adapters; | ||||
|  | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| public abstract class SectionedAdapter<S extends RecyclerView.ViewHolder, C extends RecyclerView.ViewHolder> | ||||
|         extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|  | ||||
|     private static final int SECTION_TYPE = Integer.MIN_VALUE; | ||||
|  | ||||
|     @Override | ||||
|     final public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|         if (viewType == SECTION_TYPE) | ||||
|             return onCreateSectionViewHolder(parent); | ||||
|         return onCreateItemViewHolder(parent, viewType); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     @SuppressWarnings("unchecked") | ||||
|     final public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { | ||||
|         PositionInfo info = getPositionInfo(position); | ||||
|         if (info.position == -1) | ||||
|             onBindSectionViewHolder((S) holder, info.section); | ||||
|         else | ||||
|             onBindItemViewHolder((C) holder, info.section, info.position); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     final public int getItemCount() { | ||||
|         int size, sec; | ||||
|         size = sec = getSectionCount(); | ||||
|         for (int i = 0; i < sec; ++i){ | ||||
|             size += getItemCount(i); | ||||
|         } | ||||
|         return size; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     final public int getItemViewType(int position) { | ||||
|         PositionInfo info = getPositionInfo(position); | ||||
|         if (info.position == -1) | ||||
|             return SECTION_TYPE; | ||||
|         else | ||||
|             return  getItemViewType(info.section, info.position); | ||||
|     } | ||||
|  | ||||
|     public int getItemViewType(int section, int position) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     protected int getSectionPosition(int section) { | ||||
|         return getItemPosition(section, -1); | ||||
|     } | ||||
|  | ||||
|     protected int getItemPosition(int section, int position) { | ||||
|         int realPosition = 0; | ||||
|         // Previous sections | ||||
|         for (int i = 0; i < section; ++i) { | ||||
|             realPosition += getItemCount(i) + 1; | ||||
|         } | ||||
|         // Current section | ||||
|         realPosition += position + 1; | ||||
|         return realPosition; | ||||
|     } | ||||
|  | ||||
|     private PositionInfo getPositionInfo(int position) { | ||||
|         int section = 0; | ||||
|         while (true) { | ||||
|             if (position == 0) | ||||
|                 return new PositionInfo(section, -1); | ||||
|             position -= 1; | ||||
|             if (position < getItemCount(section)) | ||||
|                 return new PositionInfo(section, position); | ||||
|             position -= getItemCount(section++); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class PositionInfo { | ||||
|         int section; | ||||
|         int position; | ||||
|         PositionInfo(int section, int position) { | ||||
|             this.section = section; | ||||
|             this.position = position; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public abstract int getSectionCount(); | ||||
|     public abstract int getItemCount(int section); | ||||
|     public abstract S onCreateSectionViewHolder(ViewGroup parent); | ||||
|     public abstract C onCreateItemViewHolder(ViewGroup parent, int viewType); | ||||
|     public abstract void onBindSectionViewHolder(S holder, int section); | ||||
|     public abstract void onBindItemViewHolder(C holder, int section, int position); | ||||
| } | ||||
| @@ -1,178 +0,0 @@ | ||||
| package com.topjohnwu.magisk.adapters; | ||||
|  | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.util.SparseArray; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.Comparator; | ||||
|  | ||||
| public class SimpleSectionedRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|  | ||||
|     private static final int SECTION_TYPE = 0; | ||||
|  | ||||
|     private boolean mValid = true; | ||||
|     private int mSectionResourceId; | ||||
|     private int mTextResourceId; | ||||
|     private RecyclerView.Adapter mBaseAdapter; | ||||
|     private SparseArray<Section> mSections = new SparseArray<Section>(); | ||||
|  | ||||
|  | ||||
|     public SimpleSectionedRecyclerViewAdapter(int sectionResourceId, int textResourceId, | ||||
|                                               RecyclerView.Adapter baseAdapter) { | ||||
|  | ||||
|         mSectionResourceId = sectionResourceId; | ||||
|         mTextResourceId = textResourceId; | ||||
|         mBaseAdapter = baseAdapter; | ||||
|  | ||||
|         mBaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { | ||||
|             @Override | ||||
|             public void onChanged() { | ||||
|                 mValid = mBaseAdapter.getItemCount()>0; | ||||
|                 notifyDataSetChanged(); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onItemRangeChanged(int positionStart, int itemCount) { | ||||
|                 mValid = mBaseAdapter.getItemCount()>0; | ||||
|                 notifyItemRangeChanged(positionStart, itemCount); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onItemRangeInserted(int positionStart, int itemCount) { | ||||
|                 mValid = mBaseAdapter.getItemCount()>0; | ||||
|                 notifyItemRangeInserted(positionStart, itemCount); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onItemRangeRemoved(int positionStart, int itemCount) { | ||||
|                 mValid = mBaseAdapter.getItemCount()>0; | ||||
|                 notifyItemRangeRemoved(positionStart, itemCount); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static class SectionViewHolder extends RecyclerView.ViewHolder { | ||||
|  | ||||
|         public TextView title; | ||||
|  | ||||
|         public SectionViewHolder(View view, int mTextResourceid) { | ||||
|             super(view); | ||||
|             title = (TextView) view.findViewById(mTextResourceid); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int typeView) { | ||||
|         if (typeView == SECTION_TYPE) { | ||||
|             View view = LayoutInflater.from(parent.getContext()).inflate(mSectionResourceId, parent, false); | ||||
|             return new SectionViewHolder(view,mTextResourceId); | ||||
|         }else{ | ||||
|             return mBaseAdapter.onCreateViewHolder(parent, typeView -1); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) { | ||||
|         if (isSectionHeaderPosition(position)) { | ||||
|             ((SectionViewHolder)sectionViewHolder).title.setText(mSections.get(position).title); | ||||
|         }else{ | ||||
|             mBaseAdapter.onBindViewHolder(sectionViewHolder,sectionedPositionToPosition(position)); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getItemViewType(int position) { | ||||
|         return isSectionHeaderPosition(position) | ||||
|                 ? SECTION_TYPE | ||||
|                 : mBaseAdapter.getItemViewType(sectionedPositionToPosition(position)) +1 ; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static class Section { | ||||
|         int firstPosition; | ||||
|         int sectionedPosition; | ||||
|         CharSequence title; | ||||
|  | ||||
|         public Section(int firstPosition, CharSequence title) { | ||||
|             this.firstPosition = firstPosition; | ||||
|             this.title = title; | ||||
|         } | ||||
|  | ||||
|         public CharSequence getTitle() { | ||||
|             return title; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public void setSections(Section[] sections) { | ||||
|         mSections.clear(); | ||||
|  | ||||
|         Arrays.sort(sections, new Comparator<Section>() { | ||||
|             @Override | ||||
|             public int compare(Section o, Section o1) { | ||||
|                 return (o.firstPosition == o1.firstPosition) | ||||
|                         ? 0 | ||||
|                         : ((o.firstPosition < o1.firstPosition) ? -1 : 1); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         int offset = 0; // offset positions for the headers we're adding | ||||
|         for (Section section : sections) { | ||||
|             section.sectionedPosition = section.firstPosition + offset; | ||||
|             mSections.append(section.sectionedPosition, section); | ||||
|             ++offset; | ||||
|         } | ||||
|  | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
|  | ||||
|     public int positionToSectionedPosition(int position) { | ||||
|         int offset = 0; | ||||
|         for (int i = 0; i < mSections.size(); i++) { | ||||
|             if (mSections.valueAt(i).firstPosition > position) { | ||||
|                 break; | ||||
|             } | ||||
|             ++offset; | ||||
|         } | ||||
|         return position + offset; | ||||
|     } | ||||
|  | ||||
|     public int sectionedPositionToPosition(int sectionedPosition) { | ||||
|         if (isSectionHeaderPosition(sectionedPosition)) { | ||||
|             return RecyclerView.NO_POSITION; | ||||
|         } | ||||
|  | ||||
|         int offset = 0; | ||||
|         for (int i = 0; i < mSections.size(); i++) { | ||||
|             if (mSections.valueAt(i).sectionedPosition > sectionedPosition) { | ||||
|                 break; | ||||
|             } | ||||
|             --offset; | ||||
|         } | ||||
|         return sectionedPosition + offset; | ||||
|     } | ||||
|  | ||||
|     public boolean isSectionHeaderPosition(int position) { | ||||
|         return mSections.get(position) != null; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public long getItemId(int position) { | ||||
|         return isSectionHeaderPosition(position) | ||||
|                 ? Integer.MAX_VALUE - mSections.indexOfKey(position) | ||||
|                 : mBaseAdapter.getItemId(sectionedPositionToPosition(position)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return (mValid ? mBaseAdapter.getItemCount() + mSections.size() : 0); | ||||
|     } | ||||
|  | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,15 +1,9 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.app.NotificationManager; | ||||
| import android.app.PendingIntent; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.support.v4.app.TaskStackBuilder; | ||||
| import android.support.v7.app.NotificationCompat; | ||||
|  | ||||
| import com.topjohnwu.magisk.BuildConfig; | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
| import com.topjohnwu.magisk.R; | ||||
| import com.topjohnwu.magisk.SplashActivity; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
| import com.topjohnwu.magisk.utils.WebService; | ||||
|  | ||||
| @@ -18,55 +12,65 @@ import org.json.JSONObject; | ||||
|  | ||||
| public class CheckUpdates extends ParallelTask<Void, Void, Void> { | ||||
|  | ||||
|     private static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json"; | ||||
|     private static final int NOTIFICATION_ID = 1; | ||||
|     public static final int STABLE_CHANNEL = 0; | ||||
|     public static final int BETA_CHANNEL = 1; | ||||
|  | ||||
|     private static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/stable.json"; | ||||
|     private static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/beta.json"; | ||||
|  | ||||
|     private boolean showNotification = false; | ||||
|  | ||||
|     public CheckUpdates(Context context, boolean b) { | ||||
|         this(context); | ||||
|         showNotification = b; | ||||
|     public CheckUpdates(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     public CheckUpdates(Context context) { | ||||
|         magiskManager = Utils.getMagiskManager(context); | ||||
|     public CheckUpdates(Context context, boolean b) { | ||||
|         super(context); | ||||
|         showNotification = b; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Void doInBackground(Void... voids) { | ||||
|         String jsonStr = WebService.request(UPDATE_JSON, WebService.GET); | ||||
|         MagiskManager mm = getMagiskManager(); | ||||
|         if (mm == null) return null; | ||||
|         String jsonStr; | ||||
|         switch (mm.updateChannel) { | ||||
|             case STABLE_CHANNEL: | ||||
|                 jsonStr = WebService.getString(STABLE_URL); | ||||
|                 break; | ||||
|             case BETA_CHANNEL: | ||||
|                 jsonStr = WebService.getString(BETA_URL); | ||||
|                 break; | ||||
|             default: | ||||
|                 jsonStr = null; | ||||
|         } | ||||
|         try { | ||||
|             JSONObject json = new JSONObject(jsonStr); | ||||
|             JSONObject magisk = json.getJSONObject("magisk"); | ||||
|             magiskManager.remoteMagiskVersion = magisk.getDouble("versionCode"); | ||||
|             magiskManager.magiskLink = magisk.getString("link"); | ||||
|             magiskManager.releaseNoteLink = magisk.getString("note"); | ||||
|         } catch (JSONException ignored) { | ||||
|         } | ||||
|             mm.remoteMagiskVersionString = magisk.getString("version"); | ||||
|             mm.remoteMagiskVersionCode = magisk.getInt("versionCode"); | ||||
|             mm.magiskLink = magisk.getString("link"); | ||||
|             mm.releaseNoteLink = magisk.getString("note"); | ||||
|             JSONObject manager = json.getJSONObject("app"); | ||||
|             mm.remoteManagerVersionString = manager.getString("version"); | ||||
|             mm.remoteManagerVersionCode = manager.getInt("versionCode"); | ||||
|             mm.managerLink = manager.getString("link"); | ||||
|         } catch (JSONException ignored) {} | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostExecute(Void v) { | ||||
|         if (magiskManager.magiskVersion < magiskManager.remoteMagiskVersion | ||||
|                 && showNotification && magiskManager.updateNotification) { | ||||
|             NotificationCompat.Builder builder = new NotificationCompat.Builder(magiskManager); | ||||
|             builder.setSmallIcon(R.drawable.ic_magisk) | ||||
|                     .setContentTitle(magiskManager.getString(R.string.magisk_update_title)) | ||||
|                     .setContentText(magiskManager.getString(R.string.magisk_update_available, magiskManager.remoteMagiskVersion)) | ||||
|                     .setVibrate(new long[]{0, 100, 100, 100}) | ||||
|                     .setAutoCancel(true); | ||||
|             Intent intent = new Intent(magiskManager, SplashActivity.class); | ||||
|             intent.putExtra(MagiskManager.INTENT_SECTION, "install"); | ||||
|             TaskStackBuilder stackBuilder = TaskStackBuilder.create(magiskManager); | ||||
|             stackBuilder.addParentStack(SplashActivity.class); | ||||
|             stackBuilder.addNextIntent(intent); | ||||
|             PendingIntent pendingIntent = stackBuilder.getPendingIntent(NOTIFICATION_ID, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
|             builder.setContentIntent(pendingIntent); | ||||
|             NotificationManager notificationManager = | ||||
|                     (NotificationManager) magiskManager.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
|             notificationManager.notify(NOTIFICATION_ID, builder.build()); | ||||
|         MagiskManager mm = getMagiskManager(); | ||||
|         if (mm == null) return; | ||||
|         if (showNotification && mm.updateNotification) { | ||||
|             if (BuildConfig.VERSION_CODE < mm.remoteManagerVersionCode) { | ||||
|                 Utils.showManagerUpdateNotification(mm); | ||||
|             } else if (mm.magiskVersionCode < mm.remoteMagiskVersionCode) { | ||||
|                 Utils.showMagiskUpdateNotification(mm); | ||||
|             } | ||||
|         } | ||||
|         magiskManager.updateCheckDone.trigger(); | ||||
|         mm.updateCheckDone.publish(); | ||||
|         super.onPostExecute(v); | ||||
|     } | ||||
| } | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user