mirror of
				https://github.com/topjohnwu/Magisk
				synced 2025-11-03 15:52:30 +01:00 
			
		
		
		
	Compare commits
	
		
			241 Commits
		
	
	
		
			manager-v4
			...
			manager-v5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					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 54
 | 
			
		||||
        versionName "5.3.0"
 | 
			
		||||
        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.0.2'
 | 
			
		||||
    implementation 'com.android.support:cardview-v7:26.0.2'
 | 
			
		||||
    implementation 'com.android.support:design:26.0.2'
 | 
			
		||||
    implementation 'com.android.support:support-v4:26.0.2'
 | 
			
		||||
    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"
 | 
			
		||||
@@ -21,8 +21,7 @@
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".MainActivity"
 | 
			
		||||
            android:configChanges="orientation|screenSize"
 | 
			
		||||
            android:exported="true"/>
 | 
			
		||||
 | 
			
		||||
            android:exported="true" />
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".SplashActivity"
 | 
			
		||||
            android:configChanges="orientation|screenSize"
 | 
			
		||||
@@ -30,16 +29,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 +57,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 +95,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;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										338
									
								
								app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										338
									
								
								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