1
mirror of https://github.com/topjohnwu/Magisk synced 2025-11-13 07:07:34 +01:00

Compare commits

...

196 Commits

Author SHA1 Message Date
Dmitry Val'd
13bf1b27b4 Update strings.xml
Added new lines from original
2017-10-15 03:15:39 +08:00
topjohnwu
f742bb1c47 Hot fix for detecting MagiskHide 2017-10-15 03:12:13 +08:00
topjohnwu
aa0b9e2db2 Bump version 2017-10-14 04:18:14 +08:00
topjohnwu
c10076f7ed Remove debug logs 2017-10-14 04:05:41 +08:00
topjohnwu
bcd92499f2 Massive improvement on Online Repo fetching 2017-10-14 04:05:41 +08:00
topjohnwu
b2bb0d4f72 Fix some external storage permission issues 2017-10-14 00:36:10 +08:00
topjohnwu
e140481f14 Wrap wrapper with buffer 2017-10-13 20:47:14 +08:00
topjohnwu
186bd11463 Reconnect until we got content length 2017-10-13 03:25:56 +08:00
topjohnwu
a0490d6687 Update Trad. Chinese translation 2017-10-13 03:10:35 +08:00
killer7mod
beef740ade update strings.xml for PT-BR 2017-10-13 02:45:02 +08:00
Frieder Bluemle
2ac7786a90 Update commonmark to 0.10.0 2017-10-13 02:44:42 +08:00
Frieder Bluemle
a3fb5e910f Update bouncycastle libs to 1.58 2017-10-13 02:44:42 +08:00
Frieder Bluemle
319afe86b5 Update Gradle wrapper to 4.2.1 2017-10-13 02:44:42 +08:00
Frieder Bluemle
762ab66b86 Fix Lint errors 2017-10-13 02:44:42 +08:00
topjohnwu
0c239a42de Allow secondary users to control Superuser settings except multiuser options 2017-10-13 02:41:43 +08:00
dark-basic #DarkBasic BasicHD
e9322fba26 Update strings.xml
New Lines Added
2017-10-07 23:44:10 +08:00
RoySchutte
39b6df27b3 Update strings.xml 2017-10-07 20:55:00 +08:00
topjohnwu
b1ee284e7f Rename resource -> common 2017-10-07 20:48:45 +08:00
topjohnwu
e986332bf2 Several small snet fixes 2017-10-07 20:47:44 +08:00
topjohnwu
48f9b27381 Seperate JarSigner and add task for host 2017-10-07 20:31:49 +08:00
topjohnwu
42a6e0dd10 Seperate Google proprietary code 2017-10-07 17:12:36 +08:00
topjohnwu
d4798b02ac Move functions 2017-10-04 22:27:14 +08:00
topjohnwu
963edfe8ab Add InputStream mode for signing zips 2017-10-04 22:09:59 +08:00
topjohnwu
53237f3ae0 Update Android Studio and Proguard configs 2017-10-04 15:23:08 +08:00
topjohnwu
64da9281a4 Show progress while downloading modules 2017-10-01 02:38:25 +08:00
topjohnwu
ab7fd9799d Remove cache module exception 2017-10-01 01:38:25 +08:00
topjohnwu
f6bcc84251 Improve repo fetching 2017-10-01 01:28:50 +08:00
topjohnwu
35dc3d9df9 Update WebService 2017-10-01 01:12:45 +08:00
topjohnwu
566714a75d Use override functions 2017-09-30 03:25:50 +08:00
topjohnwu
c92f30b122 Re-organize classes 2017-09-30 03:04:23 +08:00
topjohnwu
294ad094c4 Show repo loading progress by showing repos already loaded 2017-09-30 01:15:34 +08:00
topjohnwu
c1a0f520f9 Prevent flash screen close when tapping outside 2017-09-29 13:20:34 +08:00
topjohnwu
773c24b7fc Bump version 2017-09-28 03:55:53 +08:00
topjohnwu
8f926c7ca9 Load scripts in memory 2017-09-28 03:33:56 +08:00
topjohnwu
c562cbc2bb Update zip and magisk installation 2017-09-26 20:46:58 +08:00
topjohnwu
3fbbb0865a Update trad. Chinese 2017-09-26 02:13:39 +08:00
Naboleo
7d5f612a48 Update strings.xml 2017-09-26 03:07:55 +09:00
linar10
4a5a36440b Update strings.xml 2017-09-26 03:07:41 +09:00
Dmitry Val'd
43dd5cfea1 Update RU translation
Added new or missing lines
2017-09-26 03:07:33 +09:00
dark-basic #DarkBasic BasicHD
7b5fec1842 Update strings.xml 2017-09-26 03:07:20 +09:00
topjohnwu
5762ded601 Properly detect hosts file 2017-09-25 17:55:40 +08:00
topjohnwu
a3abb86daa Only place files in de on FDE enabled devices 2017-09-24 21:29:01 +08:00
topjohnwu
4f5c656b05 Update uninstall method 2017-09-16 03:53:13 +08:00
topjohnwu
a31cddbe7b Prevent NPE 2017-09-16 02:41:24 +08:00
topjohnwu
b4ecd93f1c Proper FBE support: place files in DE 2017-09-15 18:03:25 +08:00
topjohnwu
0acc23e058 Allow dialog to popup 2017-09-15 13:55:36 +08:00
topjohnwu
cdd5f9b628 Fix busybox installation 2017-09-15 13:34:53 +08:00
topjohnwu
4c9f5f4655 Support patching second slot 2017-09-15 13:03:10 +08:00
topjohnwu
b80ba13cb4 Fix strings 2017-09-15 03:47:18 +08:00
Santiago Pintos
8260bdc09c Update translations into spanish
Add two strings: "zip_download_title" and "zip_download_msg"
2017-09-13 10:12:13 -05:00
RoySchutte
24f856e02b Update strings.xml 2017-09-13 10:12:03 -05:00
Mevlüt TOPÇU
3aa619b928 Update
Merge please

Thank you
2017-09-13 10:11:53 -05:00
Taras Korzhak
4cb5e98d94 Update Ukrainian translation 2017-09-13 10:11:25 -05:00
Primokorn
272910575e Update FR strings.xml
Stupid typo
Unhide Magisk Manager should not be translated
2017-09-13 10:09:37 -05:00
topjohnwu
a15a62f4bc Move logic to external script file 2017-09-13 23:07:59 +08:00
topjohnwu
53cf11db8c Fix failure if MagiskManager folder doesn't exist 2017-09-13 23:07:59 +08:00
Dmitry Val'd
01052fbe47 Update strings.xml 2017-09-07 10:45:27 +08:00
dark-basic #DarkBasic BasicHD
a5e1e075c7 Update Strings (6-9-17)
Small Update
New Line Added.
2017-09-07 10:45:12 +08:00
c727
6be32ac688 update german strings
small improvements for new strings
also unified some strings

@topjohnwu:
what do you thing about calling the hidden Magsik Manager also "Magisk Manager" instead of "Unhide Magisk Manager"
The hidden status could be symbolized by an incognito style version of the app icon
advantages:
-same position in app drawer
-no need to translate it
2017-09-07 10:45:02 +08:00
topjohnwu
b362c0ef38 Bump version 2017-09-06 23:06:18 +08:00
topjohnwu
bba9969e31 Fix install button hiding 2017-09-06 23:05:51 +08:00
Primokorn
007ba24809 Update FR strings.xml 2017-09-06 22:33:04 +08:00
topjohnwu
df21539311 Some versioning fixes 2017-09-06 22:32:40 +08:00
topjohnwu
2592cb6019 Show Install button after update check done 2017-09-06 16:28:24 +08:00
topjohnwu
f7df17a7ed Small fix 2017-09-06 15:42:45 +08:00
dark-basic #DarkBasic BasicHD
62f42b72f8 Update Strings.xml (05-09-17)
New lines added.
2017-09-06 14:42:22 +08:00
topjohnwu
a1ba4fda6f Improve install Magisk 2017-09-06 14:41:59 +08:00
topjohnwu
1c06b04c45 Use GNU tar format 2017-09-06 13:39:29 +08:00
topjohnwu
2ee22fd374 Add restore stock image feature 2017-09-05 17:43:13 +08:00
topjohnwu
4c230d9e61 Root shell workaround 2017-09-05 13:46:54 +08:00
topjohnwu
727294fbbe Disable D8, dex not compatible with Android 5.0 2017-09-05 02:57:30 +08:00
Dmitry Val'd
478c43969b Update strings.xml
Added missing/new lines
2017-09-05 02:50:36 +08:00
Jens Lody
79b5303350 Update german translation 2017-09-05 02:50:20 +08:00
topjohnwu
ce4b742b25 Support .img.tar as input 2017-09-04 01:57:45 +08:00
topjohnwu
a9dc15bda5 Update TW translations 2017-09-04 01:14:38 +08:00
topjohnwu
ba6387ff5c Resource cleanup! 2017-09-04 00:58:39 +08:00
linar10
8fa98508b7 Update strings.xml 2017-09-03 23:18:12 +08:00
Dmitry Val'd
decdbaecf9 Update strings.xml
Added missing lines
2017-09-03 23:18:02 +08:00
gh2923
6d87cf9be0 Update Simplified Chinese Translation 2017-09-03 23:17:53 +08:00
Leonidas P
94f434c4a6 Translate Update Channel Strings 2017-09-03 23:17:36 +08:00
dark-basic #DarkBasic BasicHD
7ba867c30b Update Strings - (New Update 03-09-17) 2017-09-03 23:17:18 +08:00
topjohnwu
3424395e10 Calculate offset for unhide 2017-09-03 23:00:54 +08:00
topjohnwu
926c7359a2 Merge download and process repo modules 2017-09-03 22:10:54 +08:00
topjohnwu
ec0af99a2e Fix locale settings 2017-09-03 21:12:09 +08:00
topjohnwu
b4d948886c Fix unzip issues 2017-09-03 21:05:57 +08:00
topjohnwu
4d8d79372a Update strings 2017-09-03 18:28:46 +08:00
topjohnwu
04a589722c Support .img.tar format for ODIN 2017-09-03 17:46:00 +08:00
topjohnwu
d4a10e2873 Various adjustments 2017-09-03 17:46:00 +08:00
topjohnwu
4998ad6c7e Show Manager updates in dialogs 2017-09-03 14:58:21 +08:00
topjohnwu
a07ca5ff50 Slightly change busybox handling 2017-09-03 03:26:01 +08:00
topjohnwu
f07e7571ab Change block detection method 2017-09-03 02:45:43 +08:00
topjohnwu
834c16485c Reduce unnecessary code 2017-09-03 02:34:23 +08:00
topjohnwu
04a4265ef3 Show correct message 2017-09-03 00:17:42 +08:00
topjohnwu
0ec473195d Update install Magisk method 2017-09-03 00:10:14 +08:00
topjohnwu
0bf09256b0 Update Android Studio and Gradle 2017-09-02 19:12:03 +08:00
topjohnwu
db8fd2c913 Add boot image file patch 2017-08-31 03:07:33 +08:00
topjohnwu
dbe6e5b3d7 Simplify app startup 2017-08-30 02:28:24 +08:00
topjohnwu
cc81cd446b Extract ExpandableView code into interface 2017-08-29 04:10:04 +08:00
topjohnwu
439c7118f1 Proper runtime permission implementation 2017-08-29 03:08:09 +08:00
topjohnwu
d8154a5815 Update deprecate code 2017-08-29 01:56:43 +08:00
topjohnwu
4e3787bc0d Add beta update channel 2017-08-29 01:34:42 +08:00
topjohnwu
02e0955924 Fix settings crash 2017-08-29 00:37:52 +08:00
topjohnwu
a78950e822 Reduce boilerplate 2017-08-28 00:27:10 +08:00
topjohnwu
1ce1a94a35 Update translations 2017-08-27 01:38:05 +08:00
gh2923
977b6d9f67 Update Simplified Chinese Translation 2017-08-27 01:09:49 +08:00
Igor Sorocean
b5e6dbd797 update romanian translation 2017-08-27 01:09:41 +08:00
Taras
833e6688f1 Added Ukrainian translation 2017-08-27 01:09:33 +08:00
Dmitry Val'd
bc22c9f84f Update strings.xml
Added missing strings
2017-08-27 01:08:25 +08:00
Mevlüt TOPÇU
2149a7d116 Update
Merge please
2017-08-27 01:08:14 +08:00
dark-basic #DarkBasic BasicHD
29175d2c17 Update Strings.xml 2017-08-27 01:07:45 +08:00
Leonidas P
803454d5c8 Update Greek Strings 2017-08-27 01:07:26 +08:00
topjohnwu
36cf32dc42 Change unhide app temp location 2017-08-27 01:04:55 +08:00
topjohnwu
657f4ab303 Add hide Magisk Manager feature 2017-08-22 03:01:54 +08:00
topjohnwu
ea6552615d Bump version 2017-08-13 01:50:20 +08:00
Generator
4bf3287fce update pt_PT 2017-08-13 01:20:04 +08:00
Mevlüt TOPÇU
832c2034c2 Update
Hi,

Update, translations and typo fix

Merge please

Thank you
2017-08-13 01:19:48 +08:00
RJ Trujillo
b0aa26e1f1 More string updates
* A few grammatical corrections were made
* Everything looks cleaner now
2017-08-13 01:19:27 +08:00
dark-basic #DarkBasic BasicHD
e52baeb967 Update Strings.xml 2017-08-13 01:19:15 +08:00
Leonidas P
8268eb9a83 Update strings.xml 2017-08-13 01:18:55 +08:00
topjohnwu
3cc458abd9 Always use global mount namespace 2017-08-12 17:07:28 +08:00
topjohnwu
337b4c4268 Upgrade Android Studio 2017-08-12 15:54:14 +08:00
topjohnwu
001f8657f6 Use global Magisk native busybox for Magisk Manager 2017-08-12 02:25:55 +08:00
topjohnwu
ea884e7fa1 Re-organize application startup 2017-08-12 01:31:34 +08:00
topjohnwu
1b1394cf5d Improve Markdown support
Close #259
2017-08-08 16:12:49 +08:00
topjohnwu
1eef930dbb Move OnClickListener to Butterknife 2017-08-08 16:09:45 +08:00
topjohnwu
1e175e74ed Prevent crashes 2017-08-07 00:15:46 +08:00
John Wu
75a46c365e Update README.md 2017-08-04 00:23:14 +08:00
topjohnwu
8e7b8825f5 Rename callbackevents to topic/subscribers 2017-08-04 00:17:31 +08:00
topjohnwu
2ecbca303b Update Shell 2017-08-03 23:33:08 +08:00
topjohnwu
8195a4d616 Don't ignore libbusybox.so, we want it removed 2017-08-01 23:54:45 +08:00
topjohnwu
7ba40f925f Remove busybox in APK, download from internet 2017-08-01 23:52:39 +08:00
topjohnwu
345cd1795f Update WebService 2017-08-01 23:08:34 +08:00
topjohnwu
959aaee045 Fix FlashZip crash when fails 2017-07-31 01:19:43 +08:00
topjohnwu
53477f0f59 Improve locale settings 2017-07-31 00:44:38 +08:00
topjohnwu
5716218f41 Update busybox version and bug fixes 2017-07-31 00:21:18 +08:00
topjohnwu
9df6b9d5c0 Remove external files from git
These files should be copied to the correct place by Magisk's build script
2017-07-30 23:17:39 +08:00
topjohnwu
ec46031d36 Update Android Studio 2017-07-30 14:41:22 +08:00
RJ Trujillo
55b84d166a Improve dialog strings
* A space should never follow a question mark or any form of punctuation
* Multiple exclamation marks are not needed
2017-07-30 01:36:25 -05:00
Silvered99
34ae8bacec Update strings.xml 2017-07-30 01:36:16 -05:00
RoySchutte
cb4e5ca0f7 Update strings.xml 2017-07-30 01:36:07 -05:00
Leonidas P
0ba45468c4 Fix typos
these pesky little buggers, you never find them...
2017-07-30 01:35:57 -05:00
Frieder Bluemle
710502784e Update Gradle wrapper to 4.1-rc-1 2017-07-30 01:35:46 -05:00
topjohnwu
0275a8558d Fix locale settings duplicate 2017-07-24 18:37:13 +08:00
topjohnwu
58acc75cf6 Fix SuLog UI 2017-07-24 13:15:05 +08:00
topjohnwu
874ababb9f Fix strings.xml 2017-07-24 02:08:58 +08:00
gh2923
3771e6b0cd Update Simplified Chinese Translation 2017-07-24 01:38:55 +08:00
Sopor
33eaefa966 Add Swedish translation 2017-07-24 01:38:43 +08:00
RoySchutte
cd7e236d57 Update strings.xml 2017-07-24 01:38:18 +08:00
Andrei Conache
54c0b7c7d5 update italian translation 2017-07-24 01:38:02 +08:00
zertyuiop
a2177daec2 Update strings.xml 2017-07-24 01:37:42 +08:00
dark-basic #DarkBasic BasicHD
628386b453 Update Spanish strings.xml 2017-07-24 01:37:23 +08:00
Leonidas P
b222bfb3e0 Update Greek translation 2017-07-24 01:36:09 +08:00
topjohnwu
ab199d883d Change su logs time granularity 2017-07-24 01:26:56 +08:00
topjohnwu
356065d1ee Rewrite SuLogAdapter 2017-07-24 01:26:56 +08:00
topjohnwu
76e7c5623d Simplify ApplicationAdapter filter 2017-07-24 01:26:56 +08:00
topjohnwu
085fba050a Introduce self-written SectionedAdapter 2017-07-24 01:26:45 +08:00
topjohnwu
295334d3ac Preserve toolbar elevation when restart activity 2017-07-23 00:47:54 +08:00
topjohnwu
36124ddca4 Update CallbackEvents 2017-07-23 00:39:38 +08:00
topjohnwu
bd6585765e Add locale settings 2017-07-23 00:33:24 +08:00
topjohnwu
c325deb4ed Random changes 2017-07-22 17:39:34 +08:00
topjohnwu
73bb0b10ee Prevent memory leak in CallbackEvent 2017-07-21 05:18:24 +08:00
topjohnwu
72820b162c Code cleanups 2017-07-21 05:08:39 +08:00
topjohnwu
89e5b8d057 Switch to official BouncyCastle 2017-07-21 03:56:48 +08:00
topjohnwu
da4f53ebbb Don't store multiple repo copies in memory 2017-07-21 02:46:19 +08:00
topjohnwu
8458553b74 Update database helper 2017-07-21 02:10:00 +08:00
topjohnwu
55ecc41d06 Bump version 2017-07-20 03:20:17 +08:00
#DarkBasic - BasicHD
28fcdf2cbb Update strings.xml
Delele Translate "Magisk Modo Sólo Núcleo". (After several hours (Days :v ). I thought it was best left in its original form .Magisk Hide, should also be translated if it were the case, it was better to leave it that way so as not to confuse the users.)
Fix translation error
Translations Updates and added new line
2017-07-20 03:19:58 +08:00
topjohnwu
24087679a8 Update uninstaller 2017-07-20 02:56:36 +08:00
topjohnwu
5ac6a8cb4a Small minor updates 2017-07-20 02:54:34 +08:00
topjohnwu
668d85d14e Improve notification support 2017-07-20 01:44:32 +08:00
topjohnwu
c11a3dc95c Fix Magisk Manager freezing issue 2017-07-20 00:51:30 +08:00
topjohnwu
56f57c20a2 Update AsyncTasks to prevent memory leak 2017-07-19 18:01:22 +08:00
topjohnwu
240d14779a Minor cleanup in check updates 2017-07-19 16:10:17 +08:00
topjohnwu
3550d1e61c Bump version 2017-07-19 00:38:25 +08:00
topjohnwu
6513ad249c Fix string.xml 2017-07-19 00:36:54 +08:00
killer7mod
50297b1880 update strings.xml portuguese brazil 2017-07-19 00:25:36 +08:00
#DarkBasic - BasicHD
f189b78b9e #DBC01 - Translation update 2017-07-19 00:25:23 +08:00
zertyuiop
5c0250f495 Fix too long string
checking_safetyNet_status string is too long.
2017-07-19 00:24:47 +08:00
pavlaras
2093f726e9 Update strings.xml
corrected Greek translation
2017-07-19 00:24:36 +08:00
topjohnwu
10efe3859d Update repo fragment and adapter 2017-07-18 23:18:57 +08:00
topjohnwu
6933bcf7bb Merge shells 2017-07-18 17:14:42 +08:00
topjohnwu
2ea046cd80 Add flashing screen 2017-07-18 17:14:42 +08:00
topjohnwu
f4097a372b Root shell with no outputs 2017-07-18 01:06:05 +08:00
topjohnwu
87ea2a2bef Rewrite root shell 2017-07-16 03:00:01 +08:00
JpegXguy
cc14a1c361 Fix untranslated strings 2017-07-15 01:23:59 +08:00
topjohnwu
bcdface60d Fix crashing when installing modules 2017-07-15 01:22:00 +08:00
topjohnwu
4dc9419d2e Bump version 2017-07-14 02:31:29 +08:00
topjohnwu
d2bcac813e Fix update notifications on Android O 2017-07-14 02:27:02 +08:00
topjohnwu
080c37a7f6 Remove busybox from strings 2017-07-14 01:18:20 +08:00
topjohnwu
f9a3838db6 Fix strings 2017-07-13 15:37:00 +08:00
JpegXguy
1e61db104b Added Greek Language 2017-07-13 15:22:53 +08:00
Generator
30a9c7718d Added (European) Portuguese
Split Portuguese into pt_BR and pt_PT
2017-07-13 15:22:40 +08:00
Dmitry Val'd
34b052b5d3 Update strings.xml
Full and correct translation to russian language
2017-07-13 15:21:27 +08:00
topjohnwu
aaa12853ad Prevent crashing when requesting SN check while checking
Fixed #208, fixed #212
2017-07-13 15:12:43 +08:00
topjohnwu
b0ab55b0bf Only show one notification at a time 2017-07-13 14:51:12 +08:00
topjohnwu
d2f8496f4e Update dependency 2017-07-13 14:47:47 +08:00
151 changed files with 6410 additions and 4729 deletions

4
.gitignore vendored
View File

@@ -6,3 +6,7 @@
app/release
*.hprof
app/.externalNativeBuild/
*.sh
public.certificate.x509.pem
private.key.pk8
*.apk

View File

@@ -1,6 +1,7 @@
# Magisk Manager
You need to install CMake and NDK to build the zipadjust library for zip preprocessing
# Magisk Manager
This is one of the submodules used in Magisk. The project is licensed under GPL v3 (or newer).
More info are written in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk)
## Pre-built Binaries
Busybox (arm and x86) compiled by osm0sis (`libbusybox.so` under `app\src\main\jniLibs`)
Source and more info: [osm0sis' Odds and Ends](https://forum.xda-developers.com/showthread.php?t=2239421)
## Building Notes
You need to install CMake and NDK to build the zipadjust library.
There are several files required to let Magisk Manager work properly, and they can be copied by using the build script in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk). These files are: `magisk_uninstaller.sh`, `util_functions.sh`, `public.certificate.x509.pem`, and `private.key.pk8` under the `app/src/main/assets` folder.

View File

@@ -2,17 +2,22 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.0"
buildToolsVersion "26.0.2"
defaultConfig {
applicationId "com.topjohnwu.magisk"
minSdkVersion 21
targetSdkVersion 26
versionCode 44
versionName "5.0.4"
versionCode 57
versionName "5.4.0"
ndk {
moduleName 'zipadjust'
abiFilters 'x86', 'armeabi-v7a'
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
}
javaCompileOptions {
annotationProcessorOptions {
argument('butterknife.debuggable', 'false')
}
}
}
@@ -48,16 +53,14 @@ repositories {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:recyclerview-v7:26.0.0-beta2'
implementation 'com.android.support:cardview-v7:26.0.0-beta2'
implementation 'com.android.support:design:26.0.0-beta2'
implementation 'com.android.support:support-v4:26.0.0-beta2'
implementation 'com.jakewharton:butterknife:8.6.0'
implementation 'com.thoughtbot:expandablerecyclerview:1.4'
implementation 'us.feras.mdv:markdownview:1.1.0'
implementation 'com.madgag.spongycastle:core:1.54.0.0'
implementation 'com.madgag.spongycastle:prov:1.54.0.0'
implementation 'com.madgag.spongycastle:pkix:1.54.0.0'
implementation 'com.google.android.gms:play-services-safetynet:9.0.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'
implementation project(':common')
implementation project(':jarsigner')
implementation 'com.android.support:recyclerview-v7:26.1.0'
implementation 'com.android.support:cardview-v7:26.1.0'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support:support-v4:26.1.0'
implementation 'com.jakewharton:butterknife:8.8.1'
implementation 'com.atlassian.commonmark:commonmark:0.10.0'
implementation 'org.kamranzafar:jtar:2.3'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}

View File

@@ -16,10 +16,9 @@
# public *;
#}
# SpongyCastle
-keep class org.spongycastle.** { *; }
# Keep all names, we are open source anyway :)
-keepnames class ** { *; }
# BouncyCastle
-keep class org.bouncycastle.jcajce.provider.** { *; }
-dontwarn javax.naming.**
-dontwarn android.content.**
-dontwarn android.animation.**

View File

@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
package="com.topjohnwu.magisk"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.topjohnwu.magisk">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application
android:name=".MagiskManager"
@@ -17,12 +17,12 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
android:directBootAware="true"
tools:ignore="UnusedAttribute">
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:exported="true"/>
android:exported="true" />
<activity
android:name=".SplashActivity"
android:configChanges="orientation|screenSize"
@@ -30,16 +30,22 @@
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".AboutActivity"
android:theme="@style/AppTheme.Transparent"/>
android:theme="@style/AppTheme.Transparent" />
<activity
android:name=".SettingsActivity"
android:theme="@style/AppTheme.Transparent" />
<activity
android:name=".FlashActivity"
android:screenOrientation="nosensor"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/AppTheme.Transparent" />
<activity
android:name=".superuser.RequestActivity"
android:excludeFromRecents="true"
@@ -53,29 +59,26 @@
android:theme="@style/SuRequest" />
<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" />
<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"
@@ -87,10 +90,11 @@
android:resource="@xml/file_paths" />
</provider>
<!-- Hardcode GMS version -->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
android:value="11400000" />
</application>
</manifest>
</manifest>

View File

@@ -1,137 +0,0 @@
#!/system/bin/sh
##########################################################################################
#
# Magisk Uninstaller
# by topjohnwu
#
# This script can be placed in /cache/magisk_uninstaller.sh
# The Magisk main binary will pick up the script, and uninstall itself, following a reboot
# This script can also be used in flashable zip with the uninstaller_loader.sh
#
# This script will try to do restoration with the following:
# 1-1. Find and restore the original stock boot image dump (OTA proof)
# 1-2. If 1-1 fails, restore ramdisk from the internal backup
# (ramdisk fully restored, not OTA friendly)
# 1-3. If 1-2 fails, it will remove added files in ramdisk, however modified files
# are remained modified, because we have no backups. By doing so, Magisk will
# not be started at boot, but this isn't actually 100% cleaned up
# 2. Remove all Magisk related files
# (The list is LARGE, most likely due to bad decision in early versions
# the latest versions has much less bloat to cleanup)
#
##########################################################################################
# Call ui_print_wrap if exists, or else simply use echo
# Useful when wrapped in flashable zip
ui_print_wrap() {
type ui_print >/dev/null 2>&1 && ui_print "$1" || echo "$1"
}
# Call abort if exists, or else show error message and exit
# Essential when wrapped in flashable zip
abort_wrap() {
type abort >/dev/null 2>&1
if [ $? -ne 0 ]; then
ui_print_wrap "$1"
exit 1
else
abort "$1"
fi
}
if [ ! -d $MAGISKBIN -o ! -f $MAGISKBIN/magiskboot -o ! -f $MAGISKBIN/util_functions.sh ]; then
ui_print_wrap "! Cannot find $MAGISKBIN"
exit 1
fi
[ -z $BOOTMODE ] && BOOTMODE=false
MAGISKBIN=/data/magisk
CHROMEDIR=$MAGISKBIN/chromeos
# Default permissions
umask 022
# Load utility functions
. $MAGISKBIN/util_functions.sh
# Find the boot image
find_boot_image
[ -z $BOOTIMAGE ] && abort "! Unable to detect boot image"
ui_print_wrap "- Found Boot Image: $BOOTIMAGE"
cd $MAGISKBIN
ui_print_wrap "- Unpacking boot image"
./magiskboot --unpack "$BOOTIMAGE"
[ $? -ne 0 ] && abort_wrap "! Unable to unpack boot image"
# Update our previous backup to new format if exists
if [ -f /data/stock_boot.img ]; then
SHA1=`./magiskboot --sha1 /data/stock_boot.img | tail -n 1`
STOCKDUMP=/data/stock_boot_${SHA1}.img
mv /data/stock_boot.img $STOCKDUMP
./magiskboot --compress $STOCKDUMP
fi
# Detect boot image state
./magiskboot --cpio-test ramdisk.cpio
case $? in
0 ) # Stock boot
ui_print_wrap "- Stock boot image detected!"
ui_print_wrap "! Magisk is not installed!"
exit
;;
1 ) # Magisk patched
ui_print_wrap "- Magisk patched image detected!"
# Find SHA1 of stock boot image
if [ -z $SHA1 ]; then
./magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc.old
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc.old`
rm -f init.magisk.rc.old
fi
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
if [ -f ${STOCKDUMP}.gz ]; then
ui_print_wrap "- Boot image backup found!"
./magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
else
ui_print_wrap "! Boot image backup unavailable"
ui_print_wrap "- Restoring ramdisk with backup"
./magiskboot --cpio-restore ramdisk.cpio
./magiskboot --repack $BOOTIMAGE stock_boot.img
fi
;;
2 ) # Other patched
ui_print_wrap "! Boot image patched by other programs!"
abort_wrap "! Cannot uninstall with this uninstaller"
;;
esac
# Sign chromeos boot
if [ -f chromeos ]; then
echo > empty
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack stock_boot.img.signed \
--keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk \
--version 1 --vmlinuz stock_boot.img --config empty --arch arm --bootloader empty --flags 0x1
rm -f empty stock_boot.img
mv stock_boot.img.signed stock_boot.img
fi
ui_print_wrap "- Flashing stock/reverted image"
if [ -L "$BOOTIMAGE" ]; then
dd if=stock_boot.img of="$BOOTIMAGE" bs=4096
else
cat stock_boot.img /dev/zero | dd of="$BOOTIMAGE" bs=4096 >/dev/null 2>&1
fi
rm -f stock_boot.img
ui_print_wrap "- Removing Magisk files"
rm -rf /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \
/cache/magisk /cache/magisk_merge /cache/magisk_mount /cache/unblock /cache/magisk_uninstaller.sh \
/data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img /data/magisk_debug.log \
/data/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null
$BOOTMODE && reboot

Binary file not shown.

View File

@@ -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-----

View File

@@ -1,192 +0,0 @@
##########################################################################################
#
# Magisk General Utility Functions
# by topjohnwu
#
# Used in flash_script.sh, addon.d.sh, magisk module installers, and uninstaller
#
##########################################################################################
get_outfd() {
readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=0
for FD in `ls /proc/$$/fd`; do
readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
if [ "$?" -eq "0" ]; then
ps | grep " 3 $FD " | grep -v grep >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=$FD
break
fi
fi
done
fi
}
ui_print() {
if $BOOTMODE; then
echo "$1"
else
echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
fi
}
getvar() {
local VARNAME=$1
local VALUE=$(eval echo \$"$VARNAME");
for FILE in /dev/.magisk /data/.magisk /cache/.magisk /system/.magisk; do
if [ -z "$VALUE" ]; then
LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=")
if [ ! -z "$LINE" ]; then
VALUE=${LINE#*=}
fi
fi
done
eval $VARNAME=\$VALUE
}
find_boot_image() {
if [ -z "$BOOTIMAGE" ]; then
for BLOCK in boot_a BOOT_A kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
BOOTIMAGE=`ls /dev/block/by-name/$BLOCK || ls /dev/block/platform/*/by-name/$BLOCK || ls /dev/block/platform/*/*/by-name/$BLOCK` 2>/dev/null
[ ! -z $BOOTIMAGE ] && break
done
fi
# Recovery fallback
if [ -z "$BOOTIMAGE" ]; then
for FSTAB in /etc/*fstab*; do
BOOTIMAGE=`grep -E '\b/boot\b' $FSTAB | grep -v "#" | grep -oE '/dev/[a-zA-Z0-9_./-]*'`
[ ! -z $BOOTIMAGE ] && break
done
fi
[ -L "$BOOTIMAGE" ] && BOOTIMAGE=`readlink $BOOTIMAGE`
}
is_mounted() {
if [ ! -z "$2" ]; then
cat /proc/mounts | grep $1 | grep $2, >/dev/null
else
cat /proc/mounts | grep $1 >/dev/null
fi
return $?
}
grep_prop() {
REGEX="s/^$1=//p"
shift
FILES=$@
if [ -z "$FILES" ]; then
FILES='/system/build.prop'
fi
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
}
remove_system_su() {
if [ -f /system/bin/su -o -f /system/xbin/su ] && [ ! -f /su/bin/su ]; then
ui_print "! System installed root detected, mount rw :("
mount -o rw,remount /system
# SuperSU
if [ -e /system/bin/.ext/.su ]; then
mv -f /system/bin/app_process32_original /system/bin/app_process32 2>/dev/null
mv -f /system/bin/app_process64_original /system/bin/app_process64 2>/dev/null
mv -f /system/bin/install-recovery_original.sh /system/bin/install-recovery.sh 2>/dev/null
cd /system/bin
if [ -e app_process64 ]; then
ln -sf app_process64 app_process
else
ln -sf app_process32 app_process
fi
fi
rm -rf /system/.pin /system/bin/.ext /system/etc/.installed_su_daemon /system/etc/.has_su_daemon \
/system/xbin/daemonsu /system/xbin/su /system/xbin/sugote /system/xbin/sugote-mksh /system/xbin/supolicy \
/system/bin/app_process_init /system/bin/su /cache/su /system/lib/libsupol.so /system/lib64/libsupol.so \
/system/su.d /system/etc/install-recovery.sh /system/etc/init.d/99SuperSUDaemon /cache/install-recovery.sh \
/system/.supersu /cache/.supersu /data/.supersu \
/system/app/Superuser.apk /system/app/SuperSU /cache/Superuser.apk 2>/dev/null
fi
}
api_level_arch_detect() {
API=`grep_prop ro.build.version.sdk`
ABI=`grep_prop ro.product.cpu.abi | cut -c-3`
ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3`
ABILONG=`grep_prop ro.product.cpu.abi`
ARCH=arm
IS64BIT=false
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
}
recovery_actions() {
# TWRP bug fix
mount -o bind /dev/urandom /dev/random
# Temporarily block out all custom recovery binaries/libs
mv /sbin /sbin_tmp
# Add all possible library paths
OLD_LD_PATH=$LD_LIBRARY_PATH
$IS64BIT && export LD_LIBRARY_PATH=/system/lib64:/system/vendor/lib64 || export LD_LIBRARY_PATH=/system/lib:/system/vendor/lib
}
recovery_cleanup() {
mv /sbin_tmp /sbin
# Clear LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$OLD_LD_PATH
ui_print "- Unmounting partitions"
umount -l /system
umount -l /vendor 2>/dev/null
umount -l /dev/random
}
abort() {
ui_print "$1"
mv /sbin_tmp /sbin 2>/dev/null
exit 1
}
set_perm() {
chown $2:$3 $1 || exit 1
chmod $4 $1 || exit 1
if [ ! -z $5 ]; then
chcon $5 $1 2>/dev/null
else
chcon 'u:object_r:system_file:s0' $1 2>/dev/null
fi
}
set_perm_recursive() {
find $1 -type d 2>/dev/null | while read dir; do
set_perm $dir $2 $3 $4 $6
done
find $1 -type f 2>/dev/null | while read file; do
set_perm $file $2 $3 $5 $6
done
}
mktouch() {
mkdir -p ${1%/*}
if [ -z "$2" ]; then
touch $1
else
echo $2 > $1
fi
chmod 644 $1
}
request_size_check() {
reqSizeM=`du -s $1 | cut -f1`
reqSizeM=$((reqSizeM / 1024 + 1))
}
image_size_check() {
SIZE="`$MAGISKBIN/magisk --imgsize $IMG`"
curUsedM=`echo "$SIZE" | cut -d" " -f1`
curSizeM=`echo "$SIZE" | cut -d" " -f2`
curFreeM=$((curSizeM - curUsedM))
}

View File

@@ -20,6 +20,7 @@ import com.topjohnwu.magisk.components.AlertDialogBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
@@ -42,7 +43,7 @@ public class AboutActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getApplicationContext().isDarkTheme) {
if (getMagiskManager().isDarkTheme) {
setTheme(R.style.AppTheme_Transparent_Dark);
}
setContentView(R.layout.activity_about);
@@ -57,7 +58,7 @@ public class AboutActivity extends Activity {
ab.setDisplayHomeAsUpEnabled(true);
}
appVersionInfo.setSummary(BuildConfig.VERSION_NAME);
appVersionInfo.setSummary(String.format(Locale.US, "%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
String changes = null;
try (InputStream is = getAssets().open("changelog.html")) {

View File

@@ -0,0 +1,153 @@
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.container.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();
setFinishOnTouchOutside(false);
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);
}
}
}

View File

@@ -29,6 +29,8 @@ public class LogFragment extends Fragment {
View v = inflater.inflate(R.layout.fragment_log, container, false);
unbinder = ButterKnife.bind(this, v);
((MainActivity) getActivity()).toolbar.setElevation(0);
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
if (getApplication().isSuClient) {

File diff suppressed because it is too large Load Diff

View File

@@ -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, Object result) {
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

View File

@@ -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,15 +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;
@@ -42,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);
@@ -81,7 +73,6 @@ public class MainActivity extends Activity
navigate(getIntent().getStringExtra(MagiskManager.INTENT_SECTION));
navigationView.setNavigationItemSelectedListener(this);
getApplicationContext().reloadMainActivity.register(this);
}
@@ -91,12 +82,6 @@ public class MainActivity extends Activity
checkHideSection();
}
@Override
protected void onDestroy() {
getApplicationContext().reloadMainActivity.unRegister(this);
super.onDestroy();
}
@Override
public void onBackPressed() {
if (drawer.isDrawerOpen(navigationView)) {
@@ -117,22 +102,27 @@ public class MainActivity extends Activity
}
@Override
public void onTrigger(CallbackEvent<Void> event) {
public void onTopicPublished(Topic topic, Object result) {
recreate();
}
@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().magiskVersionCode >= 1300
Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 1300
&& prefs.getBoolean("magiskhide", false));
menu.findItem(R.id.modules).setVisible(
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 0);
Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 0);
menu.findItem(R.id.downloads).setVisible(Utils.checkNetworkStatus(this) &&
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 0);
Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 0);
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
menu.findItem(R.id.superuser).setVisible(
Shell.rootAccess() && getApplicationContext().isSuClient);
Shell.rootAccess() && getMagiskManager().isSuClient);
}
public void navigate(String item) {
@@ -140,7 +130,6 @@ public class MainActivity extends Activity
if (item != null) {
switch (item) {
case "magisk":
case "install":
itemId = R.id.magisk;
break;
case "superuser":

View File

@@ -1,11 +1,10 @@
package com.topjohnwu.magisk;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -14,21 +13,21 @@ import android.view.ViewGroup;
import android.widget.TextView;
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.container.Module;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
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 +35,14 @@ 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() {
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, () -> {
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 +52,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 +69,29 @@ 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) {
Logger.dev("ModulesFragment: UI refresh triggered");
public void onTopicPublished(Topic topic, Object result) {
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

View File

@@ -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,22 @@ 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;
public static ReposAdapter adapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -60,24 +42,49 @@ 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);
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.setOnRefreshListener(() -> {
recyclerView.setVisibility(View.GONE);
new LoadRepos(getActivity()).exec();
recyclerView.setVisibility(View.VISIBLE);
emptyRv.setVisibility(View.GONE);
new UpdateRepos(getActivity(), true).exec();
});
if (getApplication().repoLoadDone.isTriggered) {
reloadRepos();
updateUI();
}
getActivity().setTitle(R.string.downloads);
searchListener = new SearchView.OnQueryTextListener() {
return view;
}
@Override
public void onResume() {
adapter = new ReposAdapter(getApplication().repoDB, getApplication().moduleMap);
recyclerView.setAdapter(adapter);
super.onResume();
}
@Override
public void onPause() {
super.onPause();
adapter = null;
}
@Override
public void onTopicPublished(Topic topic, Object result) {
mSwipeRefreshLayout.setRefreshing(false);
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 +92,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 +103,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

View File

@@ -1,51 +1,17 @@
package com.topjohnwu.magisk;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import com.topjohnwu.magisk.asyncs.GetBootBlocks;
import com.topjohnwu.magisk.asyncs.LoadApps;
import com.topjohnwu.magisk.asyncs.LoadModules;
import com.topjohnwu.magisk.asyncs.LoadRepos;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.services.UpdateCheckService;
import com.topjohnwu.magisk.utils.Utils;
public class SplashActivity extends Activity{
private static final int UPDATE_SERVICE_ID = 1;
public class SplashActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Init the info and configs and root shell
getApplicationContext().init();
// Now fire all async tasks
new GetBootBlocks(this).exec();
new LoadModules(this).setCallBack(() -> new LoadRepos(this).exec()).exec();
new LoadApps(this).exec();
if (Utils.checkNetworkStatus(this)) {
// Initialize the update check service, notify every 8 hours
if (!TextUtils.equals("install", getIntent().getStringExtra(MagiskManager.INTENT_SECTION))) {
ComponentName service = new ComponentName(this, UpdateCheckService.class);
JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.setPeriodic(8 * 60 * 60 * 1000)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);
}
}
getMagiskManager().startup();
Intent intent = new Intent(this, MainActivity.class);
String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION);

View File

@@ -13,9 +13,6 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.SuLogAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.superuser.SuLogEntry;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
@@ -27,7 +24,8 @@ public class SuLogFragment extends Fragment {
@BindView(R.id.recyclerView) RecyclerView recyclerView;
private Unbinder unbinder;
private MagiskManager magiskManager;
private MagiskManager mm;
private SuLogAdapter adapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -47,7 +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);
magiskManager = getApplication();
mm = getApplication();
adapter = new SuLogAdapter(mm.suDB);
recyclerView.setAdapter(adapter);
updateList();
@@ -55,13 +55,12 @@ public class SuLogFragment extends Fragment {
}
private void updateList() {
List<SuLogEntry> logs = magiskManager.suDB.getLogList();
adapter.notifyDBChanged();
if (logs.size() == 0) {
if (adapter.getSectionCount() == 0) {
emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
recyclerView.setAdapter(new SuLogAdapter(logs).getAdapter());
emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
@@ -74,7 +73,7 @@ public class SuLogFragment extends Fragment {
updateList();
return true;
case R.id.menu_clear:
magiskManager.suDB.clearLogs();
mm.suDB.clearLogs();
updateList();
return true;
default:

View File

@@ -11,7 +11,7 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.PolicyAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.container.Policy;
import java.util.List;
@@ -32,15 +32,15 @@ public class SuperuserFragment extends Fragment {
unbinder = ButterKnife.bind(this, view);
PackageManager pm = getActivity().getPackageManager();
MagiskManager magiskManager = getApplication();
MagiskManager mm = getApplication();
List<Policy> policyList = magiskManager.suDB.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, magiskManager.suDB, pm));
recyclerView.setAdapter(new PolicyAdapter(policyList, mm.suDB, pm));
emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}

View File

@@ -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);
}
}
}

View File

@@ -13,7 +13,7 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.utils.Shell;
import java.util.List;
@@ -38,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();
@@ -55,10 +56,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
int snack;
if (isChecked) {
module.removeDisableFile();
module.removeDisableFile(rootShell);
snack = R.string.disable_file_removed;
} else {
module.createDisableFile();
module.createDisableFile(rootShell);
snack = R.string.disable_file_created;
}
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
@@ -68,10 +69,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
boolean removed = module.willBeRemoved();
int snack;
if (removed) {
module.deleteRemoveFile();
module.deleteRemoveFile(rootShell);
snack = R.string.remove_file_deleted;
} else {
module.createRemoveFile();
module.createRemoveFile(rootShell);
snack = R.string.remove_file_created;
}
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();

View File

@@ -1,5 +1,6 @@
package com.topjohnwu.magisk.adapters;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
@@ -12,10 +13,10 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.ExpandableViewHolder;
import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.Policy;
import java.util.HashSet;
import java.util.List;
@@ -50,7 +51,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
holder.setExpanded(expandList.contains(policy));
holder.itemView.setOnClickListener(view -> {
if (holder.mExpanded) {
if (holder.isExpanded()) {
holder.collapse();
expandList.remove(policy);
} else {
@@ -92,7 +93,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
dbHelper.updatePolicy(policy);
}
});
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
holder.delete.setOnClickListener(v -> new AlertDialogBuilder((Activity) v.getContext())
.setTitle(R.string.su_revoke_title)
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
.setPositiveButton(R.string.yes, (dialog, which) -> {
@@ -119,7 +120,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
return policyList.size();
}
static class ViewHolder extends ExpandableViewHolder {
static class ViewHolder extends RecyclerView.ViewHolder implements ExpandableView {
@BindView(R.id.app_name) TextView appName;
@BindView(R.id.package_name) TextView packageName;
@@ -127,18 +128,23 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
@BindView(R.id.master_switch) Switch masterSwitch;
@BindView(R.id.notification_switch) Switch notificationSwitch;
@BindView(R.id.logging_switch) Switch loggingSwitch;
@BindView(R.id.expand_layout) ViewGroup expandLayout;
@BindView(R.id.delete) ImageView delete;
@BindView(R.id.more_info) ImageView moreInfo;
private Container container = new Container();
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
container.expandLayout = expandLayout;
setupExpandable();
}
@Override
public void setExpandLayout(View itemView) {
expandLayout = itemView.findViewById(R.id.expand_layout);
public Container getContainer() {
return container;
}
}
}

View File

@@ -2,9 +2,10 @@ 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;
@@ -13,101 +14,165 @@ 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.module.Repo;
import com.topjohnwu.magisk.receivers.DownloadReceiver;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
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<>();
notifyDBChanged();
}
@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) {
Activity activity = (Activity) mContext;
new ProcessRepoZip(activity, uri, true).exec();
}
},
repo.getZipUrl(),
Utils.getLegalFilename(filename)))
.setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive(
mContext,
new DownloadReceiver() {
@Override
public void onDownloadDone(Uri uri) {
Activity activity = (Activity) mContext;
new ProcessRepoZip(activity, uri, false).exec();
}
},
repo.getZipUrl(),
Utils.getLegalFilename(filename)))
.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;
@@ -116,7 +181,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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,84 @@
package com.topjohnwu.magisk.asyncs;
import android.support.v4.app.FragmentActivity;
import com.topjohnwu.jarsigner.ByteArrayStream;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.WebService;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Proxy;
import java.net.HttpURLConnection;
import dalvik.system.DexClassLoader;
public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
public static final int SNET_VER = 2;
private static final String SNET_URL = "https://github.com/topjohnwu/MagiskManager/releases/download/v5.4.0/snet.apk";
private static final String PKG = "com.topjohnwu.snet";
private File dexPath;
private DexClassLoader loader;
public CheckSafetyNet(FragmentActivity activity) {
super(activity);
dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk");
}
@Override
protected void onPreExecute() {
MagiskManager mm = getMagiskManager();
if (mm.snet_version != CheckSafetyNet.SNET_VER) {
getShell().sh("rm -rf " + dexPath.getParent());
}
mm.snet_version = CheckSafetyNet.SNET_VER;
mm.prefs.edit().putInt("snet_version", CheckSafetyNet.SNET_VER).apply();
}
@Override
protected Exception doInBackground(Void... voids) {
try {
if (!dexPath.exists()) {
HttpURLConnection conn = WebService.request(SNET_URL, null);
ByteArrayStream bas = new ByteArrayStream();
bas.readFrom(conn.getInputStream());
conn.disconnect();
dexPath.getParentFile().mkdir();
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath))) {
bas.writeTo(out);
out.flush();
}
}
loader = new DexClassLoader(dexPath.toString(), dexPath.getParent(),
null, ClassLoader.getSystemClassLoader());
} catch (Exception e) {
return e;
}
return null;
}
@Override
protected void onPostExecute(Exception err) {
try {
if (err != null) throw err;
Class<?> helperClazz = loader.loadClass(PKG + ".SafetyNetHelper");
Class<?> callbackClazz = loader.loadClass(PKG + ".SafetyNetCallback");
Object helper = helperClazz.getConstructors()[0].newInstance(
getActivity(), Proxy.newProxyInstance(
loader, new Class[] { callbackClazz }, (proxy, method, args) -> {
getMagiskManager().safetyNetDone.publish(false, args[0]);
return null;
}));
helperClazz.getMethod("attest").invoke(helper);
} catch (Exception e) {
e.printStackTrace();
getMagiskManager().safetyNetDone.publish(false, -1);
}
super.onPostExecute(err);
}
}

View File

@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.asyncs;
import android.content.Context;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.WebService;
@@ -11,49 +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/update/magisk_update.json";
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.remoteMagiskVersionString = magisk.getString("version");
magiskManager.remoteMagiskVersionCode = magisk.getInt("versionCode");
magiskManager.magiskLink = magisk.getString("link");
magiskManager.releaseNoteLink = magisk.getString("note");
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");
magiskManager.remoteManagerVersionString = manager.getString("version");
magiskManager.remoteManagerVersionCode = manager.getInt("versionCode");
magiskManager.managerLink = manager.getString("link");
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 (showNotification && magiskManager.updateNotification) {
if (magiskManager.magiskVersionCode < magiskManager.remoteMagiskVersionCode) {
Utils.showMagiskUpdate(magiskManager);
}
if (BuildConfig.VERSION_CODE < magiskManager.remoteManagerVersionCode) {
Utils.showManagerUpdate(magiskManager);
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