Compare commits

...

1598 Commits
v18.1 ... v20.4

Author SHA1 Message Date
topjohnwu
ba7cb47383 Make version reporting consistent 2020-03-23 01:17:13 -07:00
topjohnwu
48d417f9af Add symlink for backwards compatibility
The native code has to run with an old verison of Magisk Manager,
add this back so things will work properly.
2020-03-22 21:00:40 -07:00
Heimen Stoffels
df4db6bf6b Added Dutch translation for stub 2020-03-22 13:45:26 -07:00
Heimen Stoffels
b8ef491bc7 Updated Dutch translation 2020-03-22 13:45:26 -07:00
kam821
ea1ebb8d00 Polish translation - fix missing string
Add previously deleted string, due incorrent (duplicated) variable name.
Described in: 31142180cb
2020-03-22 13:45:02 -07:00
osm0sis
91b6d2852a scripts: add nand/mtd support to uninstaller 2020-03-22 13:43:13 -07:00
Zackptg5
d7cd1b37f8 add missing flags 2020-03-22 13:41:55 -07:00
topjohnwu
160ff7bb07 Update abort function to cleanup module installs
CLose #2373
2020-03-22 00:08:04 -07:00
topjohnwu
31142180cb Fix strings 2020-03-21 13:13:26 -07:00
Vladimír Kubala
38b0fa04a8 Small translation fix 2020-03-21 13:10:04 -07:00
fessmm
29817245ba update de strings 2020-03-21 13:09:37 -07:00
Ilya Kushnir
925fe6f152 Update RU strings 2020-03-21 04:34:45 -07:00
孟武.尼德霍格.龍
93fd574b75 更新繁體中文字串
更新繁體中文字串(適用278版)
2020-03-21 04:34:09 -07:00
kam821
0de88bcbb9 Polish translation - add missing strings, small improvements. 2020-03-21 04:33:43 -07:00
osm0sis
0b70bd2b60 scripts: make remaining header/section dividers uniform
- match other recent formatting updates from topjohnwu
2020-03-21 04:32:20 -07:00
osm0sis
84ecba4629 scripts: fix addon.d again by ensuring all arguments get passed
- /proc/$$/cmdline is \0 terminated argument strings except for the last argument which has no terminus, so the last argument was being dropped by `while read` which requires input to be \n terminated
- switch to a for loop, which will use the \n delimiter but also read the last argument; all arguments are still protected by quoting
- clean up potentially breaking recovery env since $OLD_PATH no longer exists
2020-03-20 10:51:55 -07:00
topjohnwu
f7142e69b6 Fix module install in util_functions.sh 2020-03-19 03:53:15 -07:00
topjohnwu
ed7e560849 Fix ensure_bb implementation
Close #2549, close #2560
2020-03-19 03:53:15 -07:00
osm0sis
47e50e8511 scripts: add nand/mtd support to installer
- Magisk's busybox now has nanddump, flash_eraseall and nandwrite, so use these to support character devices

Closes #1526
2020-03-15 12:37:19 -07:00
topjohnwu
72f6770d61 Fix string resources 2020-03-15 00:39:56 -07:00
topjohnwu
7da35e5468 Extract full module installation logic 2020-03-15 00:23:07 -07:00
Simon Shi
7768274b2f Fix build issue 2020-03-14 11:17:51 -07:00
topjohnwu
33f006655d Update README 2020-03-13 02:12:35 -07:00
topjohnwu
612b51d48f Disable MagiskHide by default
Since SafetyNet CTS is impossible to achieve, leaving MagiskHide on
by default no longer serves a purpose.

For more details regarding the latest SafetyNet changes, please check:
https://twitter.com/topjohnwu/status/1237656703929180160
https://twitter.com/topjohnwu/status/1237830555523149824

MagiskHide's functionality will continue to exist within the Magisk
project as it is still extremely effective to hide modifications in
userspace (including SafetyNet's basicIntegrity check).

Future MagiskHide improvements _may_ come, but since the holy grail
has been taken, any form of improvement is now a very low priority.
2020-03-13 01:48:14 -07:00
topjohnwu
8101f3f67d Set proper permissions 2020-03-12 00:51:46 -07:00
GaryOderNichts
e3c8d723e3 Add linebrake notice for module.prop
This made some trouble when creating a module.prop on Windows. The file could not be read properly by magisk manager and my module folder had an \r at the end which made it unremovable through Magisk Manager.
2020-03-12 00:34:56 -07:00
Tornike Khintibidze
4579825758 Updated Georgian strings 2020-03-12 00:33:04 -07:00
Ilya Kushnir
ef91c33f55 Update RU strings 2020-03-12 00:31:55 -07:00
dark-basic
511d5993df Update Strings-es.xml 2020-03-12 00:31:34 -07:00
Viktor De Pasquale
9f4958e869 Updated safetynet success color to primary 2020-03-12 00:30:00 -07:00
Fox2Code
c07775f5e3 Add missing ro.vendor(.boot).warranty_bit props
Co-authored-by: John Wu <topjohnwu@gmail.com>
2020-03-12 00:28:43 -07:00
topjohnwu
e261579e72 Use standalone mode in boot scripts 2020-03-11 00:11:15 -07:00
topjohnwu
cf54cad3ce deleteprop -> delprop 2020-03-09 02:05:24 -07:00
topjohnwu
a0998009c1 Small native code reorganization 2020-03-09 01:50:30 -07:00
topjohnwu
d6fdbfe9b7 Utilize standalone mode for emulator.sh 2020-03-08 23:27:06 -07:00
Vladimír Kubala
07228279a3 Update Slovak translation 2020-03-08 23:26:08 -07:00
JoanVC100
6877ef790f Add strings 2020-03-08 23:25:25 -07:00
cristisilaghi
a3809648dd Update Romanian 2020-03-08 23:25:05 -07:00
YU-YEN HSU
df15606b00 prop compare fix 2020-03-08 22:58:37 -07:00
YU-YEN HSU
4dc0d13688 Xiaomi cross region flash hacks 2020-03-08 22:58:37 -07:00
topjohnwu
541fa5cb1f Update dependencies 2020-03-08 22:54:14 -07:00
Alessandro Astone
ab9442d4ae Fixup mounting system on Lineage Recovery
* Lineage Recovery 17.1, like AOSP Q recovery, has '/' as a shared
   mount point, causing `mount --move` to fail.
   If it fails, directly mount system to /system_root via
   /dev/block/ symlinks, like AnyKernel and OpenGapps

Co-authored-by: John Wu <topjohnwu@gmail.com>
2020-03-08 22:38:47 -07:00
osm0sis
f5c099e9a7 scripts: fix addon.d after merge to trampoline
- pass addon.d arguments through trampoline or nothing will happen
- exit immediately after handing over from trampoline
- better grep for recovery OUTFD which should work in all cases
- output to logcat when booted and no binaries are found
- use /postinstall/tmp path to call functions from addon.d-v2 in progress
- remove unnecessary check for $MAGISKBIN since we're already executing from within it
- make sure we're not in $TMPDIR again before we delete it
- use $MAGISKBIN wherever possible in case it ever needs to be changed
2020-03-08 22:33:19 -07:00
Shaka Huang
9582379e1b Fix error patching boot.img
Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2020-03-08 22:27:18 -07:00
topjohnwu
db9a4b31f9 Update scripts to use BusyBox standalone mode 2020-03-08 22:25:06 -07:00
Viktor De Pasquale
409cb06ea0 Fixed layout not reacting to nested scroll on su screen 2020-03-04 23:51:06 -08:00
Viktor De Pasquale
88d917b662 Added permission check for installing/downloading modules 2020-03-04 23:50:50 -08:00
topjohnwu
faf077b494 Min ver is 19.0, don't need legacy commands 2020-02-29 15:41:15 -08:00
topjohnwu
ee1f45aa91 Add new commandline option to get tmpfs root 2020-02-29 15:33:11 -08:00
topjohnwu
915fd3020b Small string resource reorganization
Close #2454
2020-02-29 14:49:06 -08:00
micheleberrettis1
642788abec Typo fix.
Fixed two typos in the Italian translation.
2020-02-29 02:09:08 -08:00
Vladimír Kubala
3cd11dd9a0 Update Slovak translation 2020-02-29 02:08:52 -08:00
kam821
bf2c5ce368 Updated Polish translation
Synced with latest strings file, some minor fixes.
2020-02-29 02:08:36 -08:00
cristisilaghi
65c510a211 Update Romanian strings 2020-02-29 02:08:23 -08:00
topjohnwu
6fbc38d764 Add more notice/messages 2020-02-29 02:04:31 -08:00
topjohnwu
200bf993d8 Show unsupported message when running low versions 2020-02-28 21:09:52 -08:00
topjohnwu
38af82e152 Update AS 2020-02-28 17:49:19 -08:00
topjohnwu
fc05f377fb Update env fix handling logic 2020-02-28 17:44:03 -08:00
topjohnwu
5c0e86383c Add test button toggle in code 2020-02-28 11:53:25 -08:00
topjohnwu
64f5ff5475 Use global A/B detection 2020-02-28 10:30:53 -08:00
topjohnwu
758777111a Improve application startup 2020-02-27 12:54:42 -08:00
topjohnwu
b90e0430f8 Don't do layered cards 2020-02-27 01:43:00 -08:00
topjohnwu
0ce7da1bf6 Upgrade AGP 2020-02-25 15:14:24 -08:00
Viktor De Pasquale
e6464c5c7f Fixed module filter list not respecting single column layout 2020-02-25 15:03:31 -08:00
topjohnwu
c6b3f06b95 Cleanup stuffs 2020-02-22 01:28:33 -08:00
topjohnwu
581419b6a3 Update dependencies 2020-02-21 23:40:20 -08:00
topjohnwu
696ab677be New pre-init magic mount implementation 2020-02-21 00:49:58 -08:00
topjohnwu
0d229dac3b Support Android 11 SELinux paths
This is NOT proper Android 11 support
2020-02-21 00:49:33 -08:00
topjohnwu
3b8ea599f0 Fix switch_root implementation 2020-02-20 21:08:59 -08:00
topjohnwu
3e70a61e33 Fix strings 2020-02-18 16:14:11 -08:00
dark-basic
76f35d02b7 Update strings-es 2020-02-18 16:00:40 -08:00
Ilya Kushnir
356b417a04 Update RU strings 2020-02-18 16:00:23 -08:00
Tornike Khintibidze
56147a80b5 Updated Translations 2020-02-18 16:00:09 -08:00
dark-basic
91728991d7 Update Strings-es STUB version
Little change.

----
For translators of other languages, simply modify a sentence. There is nothing new to translate in this sector.
2020-02-18 15:59:38 -08:00
JoanVC100
0f7e59d288 Update + Fixes ca-strings 2020-02-18 15:59:01 -08:00
Gozzwip
f33028c645 some changes 2020-02-18 15:58:47 -08:00
Davy Defaud
f9149ad433 French translation 2020-02-18 15:58:17 -08:00
topjohnwu
0d7474cc88 Fix all locale issues 2020-02-18 14:02:08 -08:00
topjohnwu
1e7e06d1cc Proper canary version detection 2020-02-17 22:05:32 -08:00
topjohnwu
8453282fa6 Improve flash console screen 2020-02-16 19:04:26 -08:00
topjohnwu
40f971d18a Add entrypoint for testing
Should do it with proper unit test, but duh
2020-02-15 21:57:03 -08:00
topjohnwu
ce7cb1eeae Remove device section 2020-02-12 13:26:10 -08:00
Viktor De Pasquale
d2701616da Fixed bottom navigation colors so it doesn't blend together with the misused layout underneath 2020-02-12 10:48:24 -08:00
Fox2Code
10eb159e1b Disable Grant Button for 1 seconds after popup display 2020-02-11 21:45:10 -08:00
topjohnwu
36897ceb19 Add slight stroke to navigation card 2020-02-11 21:32:44 -08:00
topjohnwu
9a8274130b Manually set referenced resource ID for barriers 2020-02-11 20:54:23 -08:00
topjohnwu
c8d050c3e3 Fix strings resources 2020-02-11 20:05:17 -08:00
孟武.尼德霍格.龍
a46cd63c9d 更新繁體中文字串
更新繁體中文字串到 740559e3bc 基準
2020-02-11 20:00:53 -08:00
zrq8
e9e6eaf079 Update Simplified Chinese Translation 2020-02-11 20:00:40 -08:00
Mevlüt TOPÇU
cb5897af93 Update Turkish translation
Hi,

Merge please.

Thanks
2020-02-11 20:00:31 -08:00
Vladimír Kubala
d701d6eb82 Update Slovak translation 2020-02-11 19:59:52 -08:00
Ilya Kushnir
470ebb54e2 Update RU strings 2020-02-11 19:58:51 -08:00
dark-basic
632cab398e ReFormat Strings 2020-02-11 19:58:38 -08:00
Taras
189c4cc9d8 Update UK strings 2020-02-11 19:58:23 -08:00
topjohnwu
70d5e2dee8 Remove board info from home screen 2020-02-11 19:57:33 -08:00
topjohnwu
c586106e51 Remove confusing scrambled "Manager" text 2020-02-11 19:55:21 -08:00
topjohnwu
ffa85a616a Update home screen layout (yet again) 2020-02-11 19:46:29 -08:00
Viktor De Pasquale
e5ea3e4a43 Fixed button text color on flash screen 2020-02-11 10:42:17 -08:00
Viktor De Pasquale
0492e63862 Added unified switches to install screen 2020-02-11 10:42:05 -08:00
Viktor De Pasquale
9952387356 Updated layouts to fit new widget that should visually represent a switch
The switch is not actually a switch, but a representation of internal state, the layouts continue to accept touch events as beforehand.
2020-02-11 10:42:05 -08:00
Viktor De Pasquale
d7653e6e42 Cleaned up unused resources 2020-02-11 10:42:05 -08:00
Viktor De Pasquale
e9fc40d285 Removed grid scale gestures and reverted back to * simple list as a default
* disgusting (:
2020-02-11 10:42:05 -08:00
topjohnwu
740559e3bc Fix int detection in scripts 2020-02-10 16:45:44 -08:00
topjohnwu
9471577b3b Properly detect advanced device info 2020-02-10 16:33:58 -08:00
topjohnwu
e85d5e54e2 Update root shell preparation 2020-02-10 16:31:41 -08:00
topjohnwu
5fb071d80b Merge app scripts 2020-02-10 03:36:28 -08:00
Fox2Code
022151fefd Prevent fake clicks on SuRequest 2020-02-10 02:08:53 -08:00
topjohnwu
3b8d2fe8b7 Add ramdisk detection 2020-02-10 01:56:34 -08:00
topjohnwu
d51d549a28 Refactor string resources 2020-02-10 01:43:28 -08:00
topjohnwu
b5ac24f239 Fix strings 2020-02-09 21:11:27 -08:00
dark-basic
3ca99005f8 Update strings.xml
New lines added.
2020-02-09 21:06:47 -08:00
Ilya Kushnir
0b9f2921d2 Update RU strings 2020-02-09 21:06:34 -08:00
kam821
389501ad0c Polish translation - Added missing strings 2020-02-09 21:06:20 -08:00
Hen Ry
082e4eb05c Update strings.xml
Fix
2020-02-09 21:06:06 -08:00
Oliver Cervera
47f885a566 Update Italian translation 2020-02-09 21:05:52 -08:00
Taras
bc964b8588 Update Ukrainian (UK) translation 2020-02-09 21:05:36 -08:00
zrq8
b57b3313e4 Update Simplified Chinese Translation 2020-02-09 21:05:21 -08:00
JoanVC100
f185cefa11 Missing string 2020-02-09 21:05:09 -08:00
cristisilaghi
9d256e02d7 Add missing string for Romanian 2020-02-09 21:04:58 -08:00
Vladimír Kubala
086c64c0be Update Slovak translation 2020-02-09 21:04:43 -08:00
Tornike Khintibidze
798fe57025 Update Georgian translation 2020-02-09 21:04:26 -08:00
Eun Gang Ku
a03f744648 Update strings.xml
Add new strings
2020-02-09 21:03:57 -08:00
topjohnwu
64f35744c4 Reorganize home screen layout 2020-02-09 17:03:05 -08:00
Viktor De Pasquale
b512528148 Updated toolbar layout to match the new aesthetic 2020-02-09 03:20:38 -08:00
Viktor De Pasquale
fdfa037dca Added very slight hint of the card being selectable 2020-02-09 03:20:28 -08:00
Viktor De Pasquale
db4ef1443d Removed unnecessary code 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
810468c279 Added offline states for magisk and manager sections 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
8146d0830d Fixed wrong horizontal bias 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
7e946b040c Updated uninstall button to match aesthetic 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
97d24a7d4d Removed single-use reboot menu
This addition will be used in modules as soon as the homepage gets merged
2020-02-09 03:20:14 -08:00
Viktor De Pasquale
f8bea66313 Fixed menu inflating unnecessarily on every click 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
dd9129017f Added a condition to hide reboot button when no root is available 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
cbe3602cb7 Fixed views hiding the view below with them 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
1d831d65f3 Added overflow menu for reboot 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
c35d020731 Added uninstall button to magisk details 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
c18db555a4 Updated sections' title colors 2020-02-09 03:20:14 -08:00
Viktor De Pasquale
373092af16 Updated homepage layout
The updated layout has extended features such as reboot (not implemented yet), more details with not text ellipsis and easy extendability with further parameters, detail or whatever
More improvements to homescreen to come in upcoming commits.
2020-02-09 03:20:14 -08:00
topjohnwu
1a2e157cda 4000th commit! 🎉
Just for celebration, empty commit
2020-02-09 03:08:39 -08:00
topjohnwu
b3bc1a3907 Merge addon.d scripts 2020-02-09 03:07:49 -08:00
topjohnwu
4dd8d75cc0 Update scripts 2020-02-08 03:26:39 -08:00
topjohnwu
e5f50bb7e0 Update busybox 2020-02-07 21:57:26 -08:00
osm0sis
45d5b4bea6 scripts: recovery addon.d-v2 and env fixes
- recovery addon.d-v2 requires /system and /system_root stay mounted
- find OUTFD from recovery update_engine for addon.d-v2 output
- fix finding OUTFD on addon.d failure with toybox ps
- simplify heredoc creation
- update to longer apex BOOTCLASSPATH
- save and restore any mountpoint symlinks encountered

Closes #2284
2020-02-07 21:56:28 -08:00
zrq8
ed58cf953a Add missing string resources 2020-02-03 13:25:29 +08:00
cristisilaghi
ec26bc5ab7 Corrections for Romanian 2020-02-03 13:25:11 +08:00
topjohnwu
84e4bd3d41 Move readlinkat fix into xwrap 2020-02-03 13:24:02 +08:00
Shaka Huang
0ecfb63cd6 Fix crash during boot in x86 platform
readlinkat() may return random value instead of the number of bytes placed in buf and crashing the system in two ways:
1. segmentation fault (buf[-7633350] = ‘\0’)
2. wrong link of watchdogd, resulting dog timeout

Confirmed working in ZenFone 2 x86 series, may fix #2247 and #2356

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2020-02-03 13:02:30 +08:00
topjohnwu
ebdd6ec40c Fallback to getprop to get SDK_INT
Close #2274, close #2279
2020-02-03 12:58:59 +08:00
kam821
0586760347 Polish translation - Minor corrections/improvements 2020-02-02 16:06:36 +08:00
Tornike Khintibidze
d535f244ad Corrected translation 2020-02-02 16:06:12 +08:00
Mevlüt TOPÇU
613d46824d Update
Hi

Update Turkish language translations

Merge please

Thanks
2020-02-02 16:05:35 +08:00
Wagg13
041355f182 Final Language Update PT-BR 2020-02-02 16:04:54 +08:00
Viktor De Pasquale
6977dc082f Fixed texts being incorrect if injected from context 2020-02-02 16:01:50 +08:00
Viktor De Pasquale
d3dffe8165 Updated legacy theme to match error color instead of having separate secondary color 2020-02-02 16:00:15 +08:00
Viktor De Pasquale
6812f9d202 Updated su request dialog to match overall app theme 2020-02-02 16:00:04 +08:00
Viktor De Pasquale
555e7cc907 Fixed dialog not being centered
Close #2369
2020-02-02 15:59:44 +08:00
topjohnwu
6180558068 Add support for genfscon sepolicy rules
Close #2367
2020-02-02 01:16:42 +08:00
Shaka Huang
cf589f8c64 Fix error loading libsqlite.so
Vendors are always adding “extra libraries” in /vendor/lib* for their own sake, in this case AS*S loaded with customized `libicuuc.so` for Zenf*ne 5z and led to the failure of dynamic loading libsqlite.so:

<quote>
db: dlopen failed: cannot locate symbol "UCNV_FROM_U_CALLBACK_ESCAPE_63" referenced by "/apex/com.android.runtime/lib64/libandroidicu.so"...
</quote>

Signed-off-by: Shaka Huang <shakalaca@gmail.com>

* Minor optimizations

Co-authored-by: John Wu <topjohnwu@gmail.com>
2020-02-01 14:36:34 +08:00
topjohnwu
e864919c0b Jellybean supports modules 2020-02-01 14:22:31 +08:00
topjohnwu
c72d83b637 Update docs 2020-02-01 01:42:40 +08:00
osm0sis
f2d2f28e23 scripts: fixes for Tegra partition naming + bootsigner on Android 10
- adjust mount scripts to support SOS, APP and CAC Tegra partition naming (vendor is still vendor, oddly)
- -Xnodex2oat is removed on Android 10 in AOSP (despite it still erroneously showing in dalvikvm --help); older devices will still run safely without it
- Android 10 dynamically linked binaries need APEX mounts and variables so add this to recovery_actions/cleanup (thanks @Zackptg5)
- clean up known systemless root leftovers because we're helpful
2020-02-01 01:09:12 +08:00
osm0sis
a7435dad6d magiskboot: fix lzop detection 2020-02-01 01:09:12 +08:00
osm0sis
793f0b605c init: fix Tegra "APP" /system partition mounting
- thanks rootfan in https://github.com/topjohnwu/Magisk/issues/2063#issuecomment-573232567

Closes #2243
2020-02-01 01:09:12 +08:00
topjohnwu
5b56ca7ffc Use MAX_FDT_GROWTH instead of hardcode value 2020-02-01 00:58:33 +08:00
topjohnwu
5c988510b3 Preserve fdt paddings
Some Motorola devices (Qualcomm kernel with CONFIG_MMI_DEVICE_DTBS
configuration enabled) need 1k of padding to the DTBs to allow for
environment variables to be runtime added by the bootloader.
Those extra paddings will be removed during the process of dtb patch,
devices won’t be able to boot-up and return to fastboot mode immediately
after flashed the flawed boot.img.

Credits to @shakalaca, close #2273
2020-02-01 00:48:21 +08:00
topjohnwu
290624844b Reorganize dtb code 2020-02-01 00:15:52 +08:00
topjohnwu
497efc9f5e Make scrambled text prettier 2020-01-31 04:48:02 +08:00
topjohnwu
19d76b635c Fix de strings 2020-01-31 04:29:06 +08:00
Davy Defaud
4875def31c Complete and improve French translation
- fix some typos
- translate the two last strings
- fit French orthotypographic rules (use true apostrophes and hyphens…)
2020-01-31 04:24:10 +08:00
Vladimír Kubala
155c0e3609 Update Slovak language 2020-01-31 04:22:34 +08:00
kam821
00ea15dc19 Update and fix Polish language
- Added missing strings.
- Fixed some incorrect translations
- Improved grammar.

Many lines rewritten to keep original (EN) meaning as much as possible.
2020-01-31 04:20:06 +08:00
Hen Ry
f04c4cb78a Update de strings 2020-01-31 04:19:40 +08:00
topjohnwu
6e4777692e Change recreate logic
Although this new behavior is a little more annoying, at least
it properly kills the activity and restarts it with updated configs.
2020-01-31 04:17:17 +08:00
Viktor De Pasquale
4638fdf2d7 Fixed dialog content being squished unnecessarily
...by updating constraint layout
...lol
2020-01-31 04:13:08 +08:00
wiki de pasquale
0783d385d5 Removed security note
Note, and the backdrop, has been removed, since users which have chosen device that doesn't receive security updates in, at least 2 months, are getting triggered by their own choices (:
2020-01-31 04:12:49 +08:00
Viktor De Pasquale
cf918e7df8 Updated text "variant" transparency 2020-01-31 04:09:45 +08:00
Viktor De Pasquale
1ba9faf35b Added legacy theme (Fraxure)
Theme is, in color, identical to legacy colors.
2020-01-31 04:09:45 +08:00
Viktor De Pasquale
6e48294f2a Removed unnecessary files and merged styles 2020-01-31 04:09:45 +08:00
topjohnwu
dea607b148 Small SignAPK improvements 2020-01-31 04:07:12 +08:00
topjohnwu
e938e717b0 Refactor PatchAPK code 2020-01-31 03:37:39 +08:00
topjohnwu
2eed09ef1b Upgrade AS 2020-01-30 22:04:31 +08:00
topjohnwu
8a6b3644be Strip only debug and verbose logging 2020-01-29 22:16:53 +08:00
topjohnwu
1d89fe503b Fix manager hiding
Workaround bizarre optimization bugs
2020-01-29 20:55:20 +08:00
topjohnwu
788db036fd Don't use Zopfli 2020-01-29 17:38:36 +08:00
topjohnwu
c38c473e11 Fix compile error 2020-01-29 17:38:36 +08:00
Eun Gang Ku
aef1f8f701 Update strings.xml 2020-01-29 13:35:01 +08:00
Eun Gang Ku
83f9767254 Update strings.xml
Add small corrections.
2020-01-29 13:34:49 +08:00
JoanVC100
3e0352eee6 Update strings + Corrections 2020-01-29 01:51:17 +08:00
Rom
28faff6425 Fix French translation 2020-01-29 01:51:07 +08:00
topjohnwu
d0112f989c Cleanup classes 2020-01-29 01:49:59 +08:00
Viktor De Pasquale
9c4c310f46 Fixed messages on modules screen replicating indefinitely 2020-01-29 01:12:48 +08:00
Viktor De Pasquale
7bf7bfb9c6 Updated Flash / SuRequest activities with app themes
CompatActivity/Fragment logic has been moved to respective BaseUI. Some deprecated and unused styles have been removed in favor or newer themes.
2020-01-29 01:12:21 +08:00
Mevlüt TOPÇU
fbe776db0b Update Turkish language
Hi

Update Turkish language

Merge please

Thanks
2020-01-27 21:54:44 +08:00
topjohnwu
1e2de1bb14 Preserve everything in package 'a'
Close #2301
2020-01-27 21:25:41 +08:00
topjohnwu
e395c9442f Upstream system_properties 2020-01-27 19:50:03 +08:00
Tornike Khintibidze
30286f0ea5 Fixed translations 2020-01-27 18:24:26 +08:00
cristisilaghi
60ee742855 Update RO strings 2020-01-27 18:23:52 +08:00
Rom
a913ede48f French translation update 2020-01-27 18:23:43 +08:00
Wagg13
9592583783 Language update PT-BR
Minor improvements and some corrections that better match words in the language.

I adapt it as I test it.
2020-01-27 18:23:34 +08:00
zrq8
ad49d3ad26 Update Simplified Chinese Translation 2020-01-27 18:23:17 +08:00
dark-basic
21ee73c2a3 Translation Correction 2020-01-27 18:23:02 +08:00
Viktor De Pasquale
f5d0cc9f32 Updated helper lists so they are lazily populated 2020-01-27 18:22:29 +08:00
vvb2060
b90c65370e Fix build on Windows 2020-01-26 12:27:07 +08:00
John Wu
88920e0546 Merge pull request #2320 from Displax/RU
Update RU strings
2020-01-26 12:19:58 +08:00
dark-basic
d27773de03 Add missing string-es resources 2020-01-26 12:19:43 +08:00
Tornike Khintibidze
8abdaeb044 Translated newest string 2020-01-26 12:19:22 +08:00
孟武.尼德霍格.龍
9682d2f84a 更新繁體中文字串
新增一處字串
2020-01-26 12:18:57 +08:00
Ilya Kushnir
a86b9e81e9 Update RU strings 2020-01-25 17:30:59 +02:00
topjohnwu
a8bb7c68a3 Add missing string resources 2020-01-25 23:03:39 +08:00
topjohnwu
bdad29adab Fix pt-rBR strings 2020-01-25 23:03:14 +08:00
Tornike Khintibidze
fadcfe5f7a Added new Georgian (ქართული) translation 2020-01-25 22:56:40 +08:00
Wagg13
fbd83b5ff3 Update language Portuguese (pt-br) 2020-01-25 22:56:22 +08:00
Ilya Kushnir
c351174fa4 Preliminary Russian translation refactoring 2020-01-25 22:56:00 +08:00
zrq8
cc4f99fe28 Update Simplified Chinese Translation 2020-01-25 22:55:41 +08:00
dark-basic
b2a9b88fe5 Updated Spanish translations 2020-01-25 22:55:27 +08:00
孟武.尼德霍格.龍
da06e0ec76 更新繁體中文字串
-針對 v7.5.2(270)以後的 Manager 進行翻譯的增補
-祝您新年快樂
2020-01-25 22:55:01 +08:00
Viktor De Pasquale
851ee81486 Updated removing of "empty list" messages
Before this commit, the loader removed messages _after_ it updated the
 list. Coincidentally the list updating mechanism is asynchronous to
 some extent and so slower devices might've had the message removed
 after changes have been dispatched which confused the recyclerview and
 caused the crash.
Now, the loader is stripped of the responsibility update the list
 holding helper messages. The responsibility is for the user itself to
 notify listeners and then clear the helper list. This should hopefully
 delay the removal to the point where choreographer had enough time to
 traverse through the hierarchy.

Stupid recycler view / layout managers. Literally unnecessary crash.
2020-01-25 22:31:19 +08:00
topjohnwu
0dc9f5c324 Rename some string IDs 2020-01-23 02:34:18 +08:00
topjohnwu
36513c2301 Don't direct reference R id 2020-01-23 02:23:42 +08:00
topjohnwu
3a10597aed Remove unused resources 2020-01-23 02:14:00 +08:00
topjohnwu
2291be5d26 Merge string resources 2020-01-23 01:40:36 +08:00
topjohnwu
345c3ef15e Remove old settings page 2020-01-23 00:57:32 +08:00
topjohnwu
c1dad11cb3 Merge branch 'md2' 2020-01-22 14:55:06 +08:00
jjhitel
12b219e7b2 Update Korean translation 2020-01-22 14:50:33 +08:00
孟武.尼德霍格.龍
f8b48cf18d 更新繁體中文字串
更新繁體中文字串的顯示
2020-01-22 14:50:16 +08:00
topjohnwu
12a9792c7d Remove old install dialog 2020-01-22 14:49:46 +08:00
topjohnwu
ba55e2bc32 Backup proper magiskinit in A-only 2SI 2020-01-22 05:12:04 +08:00
Viktor De Pasquale
c5e5b70e08 Added safe mode notice to modules 2020-01-21 22:01:55 +01:00
Viktor De Pasquale
327b186240 Fixed theme mode title 2020-01-21 21:50:13 +01:00
Viktor De Pasquale
5c1417e276 Updated home layout 2020-01-21 21:47:57 +01:00
topjohnwu
0a2c99f1dc Use __LP64__ to detect 64 bit 2020-01-22 01:20:14 +08:00
topjohnwu
836bfbdd02 Wrapper is no longer needed 2020-01-22 01:17:30 +08:00
topjohnwu
b13a35057a Support building standalone resetprop 2020-01-21 00:48:52 +08:00
topjohnwu
c3e77b1ec1 Add BusyBox SELinux support
Close #1523
2020-01-20 20:48:05 +08:00
topjohnwu
fb60bea659 Update external/selinux 2020-01-20 18:36:16 +08:00
topjohnwu
b2ddba4cbf Proper repo fetching behavior 2020-01-19 03:15:51 +08:00
topjohnwu
053251d566 Merge ViewModel Koin modules 2020-01-18 04:07:15 +08:00
topjohnwu
cf161a5dd9 Show url dialog only if necessary 2020-01-18 03:59:02 +08:00
topjohnwu
e4bcdbd0c4 Make settings page more reasonable 2020-01-18 03:06:33 +08:00
topjohnwu
cae43b26f4 Improve settings item code 2020-01-18 01:34:46 +08:00
topjohnwu
b95cf9b9a3 Show detail descriptions in settings 2020-01-17 17:02:40 +08:00
topjohnwu
e6f443cb24 More backwards compatibility 2020-01-17 00:40:16 +08:00
topjohnwu
087ccd69c9 Cleanup resources 2020-01-16 00:07:40 +08:00
topjohnwu
7532477a2f Make release builds work 2020-01-15 00:51:27 +08:00
topjohnwu
433ae89e53 Make things run on API 17 2020-01-15 00:05:44 +08:00
topjohnwu
de853a2651 Fix crash when manually refresh repo db 2020-01-14 22:03:29 +08:00
topjohnwu
47c3045980 Log full stack trace for unhandled exception 2020-01-14 20:14:20 +08:00
topjohnwu
dd50c19ba3 Consolidate stubs 2020-01-13 23:10:17 +08:00
topjohnwu
707d7b3342 Separate core components 2020-01-13 22:01:46 +08:00
topjohnwu
ba1a2fbce4 Remove deprecate APIs 2020-01-13 04:00:35 +08:00
topjohnwu
84f1e78660 Consolidate base viewmodel implementation 2020-01-13 03:56:03 +08:00
topjohnwu
3490ba0a56 Redesign is now the new norm 2020-01-13 00:43:09 +08:00
topjohnwu
1449486958 Replace old design with redesign (p3) 2020-01-12 21:52:32 +08:00
topjohnwu
9094cf7ce3 Replace old design with redesign (p2) 2020-01-12 16:07:30 +08:00
topjohnwu
df0a5b59f8 Replace old design with redesign (p1) 2020-01-12 15:00:49 +08:00
topjohnwu
0827044caf Make Room incremental 2020-01-12 04:54:20 +08:00
topjohnwu
342ae7c8cd Update AS 2020-01-12 04:51:52 +08:00
topjohnwu
fc690b9f02 Update dependencies 2020-01-12 03:50:12 +08:00
topjohnwu
22c9d836e0 Merge branch 'master' into feature/redesign 2020-01-12 03:02:03 +08:00
topjohnwu
984997e73b Update paths
Close #2244
2020-01-11 12:37:08 +08:00
topjohnwu
b39f407596 Load libsqlite dynamically 2020-01-11 03:20:59 +08:00
osm0sis
615ad0cc5a core: remove remaining legacy workarounds/leftovers 2020-01-10 23:31:43 +08:00
topjohnwu
0b41cd8564 Fix sk strings 2020-01-10 01:55:23 +08:00
topjohnwu
7db523071d Update changelog 2020-01-10 01:41:39 +08:00
JoanVC100
974ee58b9c New string added 2020-01-10 01:37:32 +08:00
Kamil Kras
1e88f2c382 Updated polish translation
Added translation for:
unsupport_magisk_msg
settings_su_biometric_title
settings_su_biometric_summary
no_biometric
2020-01-10 01:37:20 +08:00
Vladimír Kubala
0bdcfcaaf5 Update Slovak translation 2020-01-10 01:37:05 +08:00
Albert I
5f9c78d04f app: l10n: Update Indonesian translations
Signed-off-by: Albert I <kras@raphielgang.org>
2020-01-10 01:36:55 +08:00
Viktor De Pasquale
afa178fdec Fixed the checkbox being wrongly recognized as clickable 2020-01-09 18:06:30 +01:00
topjohnwu
3a0e3c98f7 Minor adjustments to prevent crashes 2020-01-09 23:42:27 +08:00
topjohnwu
fafa92d44b Simplify rootfs persist mount 2020-01-08 22:42:54 +08:00
Viktor De Pasquale
fcedd06e72 Added grid column count settings
*Cough, cough* Use pinch to zoom gesture instead, not a fan of this.
2020-01-06 20:00:33 +01:00
Viktor De Pasquale
6a2acbe929 Added tiny hint that magisk can be uninstalled using the icon 2020-01-06 19:31:06 +01:00
Viktor De Pasquale
4cfff40475 Updated special chars to their full-width variants
Close #2219
2020-01-06 19:06:19 +01:00
Viktor De Pasquale
904948dc7d Added empty states for all remaining screens
Fixed some issues in the process as the MergeObservableList doesn't support additions or deletions, duh...
2020-01-06 19:03:36 +01:00
Viktor De Pasquale
7342509b2e Added resetting state of the recyclerview scroll listener
In some edge-cases the listener can still think that the content is loading.
2020-01-06 18:37:45 +01:00
Viktor De Pasquale
ed837ba26f Updated the logic that refreshes the modules
Also added empty states for installed and made updatable modules visible all the time to avoid unnecessary transitions
2020-01-06 17:46:08 +01:00
Viktor De Pasquale
13262fdb18 Fixed the dialog not being actually closed on click outside
Misplaced methods ftw
2020-01-06 16:41:44 +01:00
Viktor De Pasquale
baf18a8762 Fixed cardview resizing itself idiotically in constraint layout 2020-01-06 16:33:55 +01:00
Viktor De Pasquale
c0b56b927f Updated the material library back to alpha03 version
The aforementioned fragment has fixed issue with layouts being oversized on API21 (maybe a bit lower and higher as well, did not test) which was notable on homepage.
Unfortunately it deprecated most of the logic behind hiding of the top action view. Since it inherited and overridden the functionality from HideBottomViewOnScrollBehavior it no longer called the old methods and so the whole class was rendered _useless_. Fortunately we didn't need the whole backing implementation so the parent class was changed to the bare minimum. Hopefully this incident will not repeat.

Thanks goes to material team for introducing breaking changes in feature update.
2020-01-06 16:24:27 +01:00
topjohnwu
242e64d72f Make write return something sane 2020-01-06 17:09:09 +08:00
topjohnwu
2262af728e Eliminate undefined behavior 2020-01-06 05:31:38 +08:00
topjohnwu
ea9947081f Use widgets from AndroidX 2020-01-05 16:27:28 +08:00
topjohnwu
e04f943980 Backwards support back to API 21
Things still crash pre-21
2020-01-05 16:05:22 +08:00
topjohnwu
b38e940088 Fix font files 2020-01-05 14:24:36 +08:00
Viktor De Pasquale
bc0bb92f7a Updated indication of whether the module is enabled 2020-01-04 16:46:13 +01:00
Viktor De Pasquale
8737be2623 Updated policy (apps) layout to be more compact
Added pinch in to increase list span count / out to decrease
  The setting will be remembered across the whole app (every list that uses Staggered Grid)
Updated indication of whether the policy has root access enabled permitted or not
  Displays crossed out app logo if not permitted
2020-01-04 16:07:53 +01:00
Viktor De Pasquale
eb929160b3 Reverted updating material library 2020-01-04 13:30:33 +01:00
Viktor De Pasquale
b8b0f257db Updated navigation behavior to be consistent and easily manageable 2020-01-04 13:30:21 +01:00
Viktor De Pasquale
67b5f39df2 Updated device info view to be expanded by default 2020-01-04 11:52:29 +01:00
topjohnwu
7e9b3f1a60 Merge components 2020-01-04 04:48:13 +08:00
topjohnwu
bce777d7c6 Set stub version in stub 2020-01-03 02:19:10 +08:00
topjohnwu
465aaeff82 Remove dexter dependency 2020-01-03 02:06:53 +08:00
topjohnwu
40c64d50d5 Merge branch 'master' into feature/redesign 2020-01-02 14:52:50 +08:00
topjohnwu
15bd2da824 Update magiskboot docs 2020-01-02 13:46:59 +08:00
topjohnwu
bd438ca288 Update docs 2020-01-02 13:45:08 +08:00
topjohnwu
e0d02a61a9 Add v7.5.0 changelog 2020-01-02 12:09:36 +08:00
topjohnwu
b3328a0ec2 Make sure shell command won't block 2020-01-02 02:19:56 +08:00
nikk gitanes
3c2041933f Remote focus fixes (classic UI) 2020-01-01 15:06:24 +08:00
孟武.尼德霍格.龍
e88b1cc443 繁體中文字串更新 2020-01-01 15:05:07 +08:00
Davy Defaud
71b05b18a0 Spelling, typographical and wording fixes
- spelling fixes
- typographical fixes : thin spaces before exclamation and interrogation marks, true apostrophes instead of single quotes, non-breaking spaces to avoid orphan words, etc.
- rewording for a better French translation
- fix various misinterpretation
2020-01-01 15:04:34 +08:00
Davy Defaud
b07b528e2a Add missing translation for "dling" string 2020-01-01 15:04:34 +08:00
Davy Defaud
1aeb6315ff Spelling & typographical fixes
- spelling fixes : complête → complète
- typographical fixes : thin spaces before exclamation and interrogation marks
- rewording for a better French translation
2020-01-01 15:04:34 +08:00
topjohnwu
1b4a3d2d9f More precise env detection in non-root 2020-01-01 14:19:24 +08:00
topjohnwu
3049a81c3b Update several scripts
- Update backup format as we might be patching multiple partitions
- Update uninstaller to remove files in persist (sepolicy.rule)
- Better handling for dtb/dtbo partition patching
2020-01-01 14:02:44 +08:00
topjohnwu
2db1e5cb74 Minor module related fixes 2019-12-30 13:21:39 +08:00
topjohnwu
78c64d39ec Add split command to magiskboot
Allow splitting image.*-dtb files to kernel and dtb
2019-12-30 13:04:39 +08:00
topjohnwu
46ba726232 Match exact "SKIPUNZIP=1" to prevent confusion 2019-12-29 15:16:04 +08:00
topjohnwu
eb26e62889 Update documentation 2019-12-29 03:28:03 +08:00
topjohnwu
7f667fed18 Allow customize.sh to skip unzip
Close #2184
2019-12-29 00:45:49 +08:00
topjohnwu
b2cb2b8b75 Reduce socket name length
Some detectors simply ban long abstract sockets
2019-12-28 21:27:55 +08:00
Zackptg5
d19f65ce4a Ignore twrp fstabs 2019-12-28 13:47:05 +08:00
topjohnwu
025b060506 Exclude META-INF in unzip 2019-12-28 02:33:35 +08:00
topjohnwu
7fa2625a03 Fix strings 2019-12-27 20:37:33 +08:00
topjohnwu
33d62d7f21 Handle sepolicy.rule when disable/remove in app 2019-12-27 19:03:45 +08:00
topjohnwu
b336655a79 Brand new module installer script
The new module installer script completely changes the way how module
installer zips are structured. More info will come later in docs.

The new installer script also supports installing sepolicy.rule to
persist partitions in order to make the module work on the next boot.
2019-12-27 17:53:27 +08:00
topjohnwu
3beffd84d6 Copy sepolicy rules to persist every boot 2019-12-22 03:44:07 -05:00
topjohnwu
02761f5f35 Fix French resources
Close #2169
2019-12-21 06:01:18 -05:00
topjohnwu
3b9f7885e0 Stop using chdir 2019-12-21 05:29:38 -05:00
topjohnwu
7668e45890 Cleanup legacy code 2019-12-17 17:15:31 -05:00
topjohnwu
695c8bc5d0 Detect package name for copying binaries
Close #2152
2019-12-17 16:38:12 -05:00
topjohnwu
06c42d05c3 Drop image based Magisk support 2019-12-15 21:01:12 -05:00
JoanVC100
404104208f Update ca-strings + Fixes 2019-12-15 19:49:12 -05:00
Rom
b4d0ad9713 Update French translation 2019-12-15 19:49:05 -05:00
Viktor De Pasquale
89b1fa341b Added assigning repo to installed modules to show readme
Close #1089
2019-12-13 15:19:56 +01:00
Viktor De Pasquale
3bda7cb26b Removed exclusive usage of 29 level API 2019-12-13 14:41:49 +01:00
topjohnwu
4f4f54a059 Remove unused code 2019-12-13 08:31:24 -05:00
topjohnwu
12fda29280 Add support for pre-init custom sepolicy patches
Close #1685
2019-12-13 06:05:12 -05:00
topjohnwu
af060b3132 General QoL changes 2019-12-13 00:37:06 -05:00
topjohnwu
8c500709e4 Remove SAR compatibility mode 2019-12-12 03:25:48 -05:00
topjohnwu
490e6a6f23 Add new API to load sepolicy rule file 2019-12-09 04:14:30 -05:00
topjohnwu
08177c3dd8 Mount persist partition mirror pre-init 2019-12-09 04:09:23 -05:00
topjohnwu
d22b9c26b6 Pull out common logic 2019-12-06 15:31:49 -05:00
Viktor De Pasquale
85a350b6c8 Fixed minor RTL issues 2019-12-06 20:53:22 +01:00
Viktor De Pasquale
eae4eff92f Fixed custom dialog behaving oddly while displaying scrollable content 2019-12-06 20:34:25 +01:00
Viktor De Pasquale
848be8f806 Fixed rtl for reveal animations 2019-12-06 18:06:59 +01:00
topjohnwu
4bb8ad19cf Small init refactoring 2019-12-06 12:02:34 -05:00
Viktor De Pasquale
c79b79b37e Cleaned up extensions and utilities in redesign 2019-12-06 16:28:41 +01:00
Viktor De Pasquale
8a03c366b8 Updated settings item location >in code< 2019-12-06 15:39:12 +01:00
Viktor De Pasquale
37677f389c Finished rebranding core-only mode to safe mode
In compliance with #2131

Mentioned features are not contained within this commit
2019-12-06 15:00:55 +01:00
topjohnwu
3e275b7dba Update a bunch of stuffs 2019-12-06 00:30:00 -05:00
topjohnwu
11b7076a43 Fix broken getxattr calls 2019-12-05 17:34:50 -05:00
Mevlüt TOPÇU
291c718ba2 Update Turkish language
Hi,

Update Turkish language

Merge please

Thanks
2019-12-05 17:21:42 -05:00
Hen Ry
fcd6071c57 Update de strings 2019-12-05 17:21:31 -05:00
topjohnwu
476b61c4c9 Support system_root with NVIDIA partition names
Fix #2063
2019-12-05 17:20:32 -05:00
topjohnwu
8cc5f096a2 Some minor changes 2019-12-05 17:20:32 -05:00
Alvin Wong
474d65207e Fix MagiskHide unmounting paths under /product
Fixes #2107
2019-12-03 05:42:10 -05:00
topjohnwu
03428329ef Add new verity and encryption patterns
Close #2118
2019-12-03 05:39:39 -05:00
Viktor De Pasquale
2692234b8c Updated hide items to follow suit with the rest of scrollable content 2019-12-02 18:53:55 +01:00
Viktor De Pasquale
bfb5d7e5ac Reverted tinting headlines 2019-12-02 18:51:22 +01:00
Viktor De Pasquale
8c818e707f Updated homepage to be less aggressive 2019-12-02 18:39:22 +01:00
Viktor De Pasquale
3efea47ca8 Updated settings to level functionality with the legacy 2019-12-02 18:35:48 +01:00
topjohnwu
8d21988656 Support patching DTB/DTBO partition format 2019-12-02 04:34:21 -05:00
Viktor De Pasquale
89da45f9ac Fixed state not being propagated correctly on startup 2019-11-29 21:04:47 +01:00
Viktor De Pasquale
34a0a00e3c Updated constraint layout to fix layout issue in dialog 2019-11-29 21:04:32 +01:00
Viktor De Pasquale
dec1094a59 Added "input" settings item, that opens custom input dialog
Updated order of some items in settings
2019-11-29 20:22:24 +01:00
Viktor De Pasquale
02e323133d Updated selector "selection" design 2019-11-29 14:49:41 +01:00
Viktor De Pasquale
cb96b536a2 Added fair amount of settings implemented from the UI side
Updated dialog to create recycler as it behaves better than regular listview
2019-11-28 21:53:31 +01:00
Viktor De Pasquale
627b40799c Fixed checkbox (switch) colors 2019-11-28 18:58:04 +01:00
Viktor De Pasquale
73c4b21285 Added (partially) settings screen
Most importantly added design and functionality backing for these items
2019-11-27 19:47:20 +01:00
Viktor De Pasquale
78d7c45be3 Merge remote-tracking branch 'john/master' into feature/redesign 2019-11-26 14:34:38 +01:00
topjohnwu
72edbfc455 Some platforms do not like null Bundles 2019-11-25 19:09:54 -05:00
topjohnwu
276535dad6 Fix incorrect kmsg path
/proc/kmsg -> /dev/kmsg
2019-11-25 19:09:02 -05:00
topjohnwu
e373e59661 Make sure file descriptors are setup properly 2019-11-25 19:07:06 -05:00
Viktor De Pasquale
ac5ecf222e Fixed style for announcement card 2019-11-25 17:54:04 +01:00
Viktor De Pasquale
a20594ed48 Added emphasis on support section 2019-11-25 17:25:49 +01:00
Viktor De Pasquale
cb59cc92a3 Updated action cards to be more colorful 2019-11-25 16:58:57 +01:00
topjohnwu
34bb18448c Fix compile errors 2019-11-23 17:18:55 -05:00
topjohnwu
01253f050a Use smart pointers 2019-11-23 04:57:52 -05:00
Viktor De Pasquale
cc7e47bbb6 Added themes
All files (that used styles) were refactored to use styles directly so themes can only actually adjust colors
 - Elaborate themes would be super hard to maintain and would certainly break over time
2019-11-22 19:29:53 +01:00
topjohnwu
5bee1c56a9 Properly use RAII to reduce complication 2019-11-22 03:01:49 -05:00
Lennoard
474cc7d56d Updated pt-BR strings (based on current
values/strings.xml)
2019-11-21 17:44:27 -05:00
topjohnwu
bffdedddb4 Fix fwrite/fread params 2019-11-21 17:43:31 -05:00
topjohnwu
fd72f658c0 Fix SQL command when creating magiskdb 2019-11-21 14:40:12 -05:00
Viktor De Pasquale
42606162b2 Fixed text color in logs not changing with theme 2019-11-21 18:21:08 +01:00
Viktor De Pasquale
e82bc1b7bc Fixed issues after merge 2019-11-21 18:07:13 +01:00
Viktor De Pasquale
4f0e1c6c61 Merge remote-tracking branch 'john/master' into feature/redesign
# Conflicts:
#	app/build.gradle
#	app/src/main/java/com/topjohnwu/magisk/Hacks.kt
#	app/src/main/java/com/topjohnwu/magisk/data/database/RepoDatabase.kt
#	app/src/main/java/com/topjohnwu/magisk/data/repository/LogRepository.kt
#	app/src/main/java/com/topjohnwu/magisk/di/DatabaseModule.kt
#	app/src/main/java/com/topjohnwu/magisk/extensions/RxJava.kt
#	app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt
#	app/src/main/java/com/topjohnwu/magisk/extensions/XJava.kt
#	app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt
#	app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt
#	app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt
#	app/src/main/res/xml/app_settings.xml
2019-11-21 17:46:59 +01:00
Viktor De Pasquale
550f6aff7e Updated showing / hiding filters 2019-11-21 17:35:29 +01:00
Viktor De Pasquale
67c50d7504 Added magisk log screen 2019-11-21 17:31:37 +01:00
Viktor De Pasquale
94f0c61619 Added ignoring emulators for env_fix dialog 2019-11-21 14:30:12 +01:00
Viktor De Pasquale
8a86b30fd1 Fixed core UI elements not behaving properly after recreating 2019-11-21 14:24:14 +01:00
topjohnwu
d3b5cf82d8 Small adjustments 2019-11-21 06:17:28 -05:00
topjohnwu
d26d804cc2 Migrate to generic stream implementation 2019-11-21 06:08:02 -05:00
topjohnwu
4f9a25ee89 Create generic streams on top of stdio
WIP
2019-11-20 21:48:49 -05:00
Viktor De Pasquale
6379108a75 Added new log screen 2019-11-20 22:42:44 +01:00
topjohnwu
bb9ce0e897 Make sepolicy dump more efficient 2019-11-20 03:47:15 -05:00
Viktor De Pasquale
fbeaad077f Updated themes so they are separated from styles 2019-11-19 18:53:50 +01:00
Viktor De Pasquale
8918113a31 Added colored borderless ripple effect 2019-11-19 17:56:32 +01:00
Viktor De Pasquale
c5385b5b4c Added custom markdown window for redesign 2019-11-19 17:41:24 +01:00
Viktor De Pasquale
35475e1d25 Added option to include simple view to MagiskDialog 2019-11-19 17:41:09 +01:00
Viktor De Pasquale
fb2c292f35 Updated dialog base to handle large content 2019-11-19 17:40:42 +01:00
Viktor De Pasquale
afc3fb10c7 Updated icon padding for all buttons 2019-11-19 17:16:07 +01:00
Viktor De Pasquale
0a239c2fef Added QOL improvements
- fast scroll in module/filter list
- auto closing keyboard on scroll
2019-11-19 17:15:44 +01:00
Viktor De Pasquale
f5342a09d3 Added back safe mode notice 2019-11-19 16:07:19 +01:00
Viktor De Pasquale
f72de687c5 Fixed module lists not being strictly typed in builder 2019-11-19 15:56:10 +01:00
topjohnwu
d6fb9868bf Small sepolicy refactor and fixes 2019-11-19 05:20:18 -05:00
topjohnwu
9aff1a57d3 Cleanup headers 2019-11-19 02:04:47 -05:00
topjohnwu
7681fde4d0 Record mounts to be cleaned up in a vector 2019-11-19 00:16:20 -05:00
topjohnwu
d3b7b41927 Fix kmsg logging in magiskinit 2019-11-18 17:18:56 -05:00
Viktor De Pasquale
833269fd0a Updated install from storage button to be more expressive 2019-11-18 17:49:03 +01:00
Viktor De Pasquale
332c1a6c59 Removed overcomplicated updates loading
The mechanism was replaced by loading updated directly by id to the initial list. There are two factors why yesterday-me was dumb:

1) By asynchronously loading update state, you have no control over it - hence no search
2) It's incredibly wasteful; running that hardcore search on every query? Not cool
...and from UX stand-point having updates inlined right under installed modules is by far better than nitpicking it from the list or in the search
2019-11-18 17:21:23 +01:00
Viktor De Pasquale
0f1f43057e Updated handling queries so first query is always instant 2019-11-18 16:29:27 +01:00
Viktor De Pasquale
784a7a7f24 Added back press closing filters in hide and module screens 2019-11-17 13:53:41 +01:00
Viktor De Pasquale
8e34baa59f Fixed bottom padding being too small 2019-11-17 13:48:52 +01:00
Viktor De Pasquale
2926772bba Added checks for updatable state on remote repos 2019-11-17 13:46:56 +01:00
topjohnwu
da159e4655 Better environment status detection 2019-11-16 17:38:10 -05:00
Viktor De Pasquale
a7f4496db7 Added info dialog for repos 2019-11-16 20:51:56 +01:00
Viktor De Pasquale
f972f02fff Fixed clipping version string so it better shows the update's impact
Incremental canary bugfix will be:
b4b2c4 > f5d2e6
Version bump will be always:
20.2 > 20.3 (regardless of canary/beta/stable)
2019-11-16 20:21:09 +01:00
Viktor De Pasquale
1c77e26c05 Added sorting order to modules 2019-11-16 20:07:59 +01:00
Viktor De Pasquale
59c5363933 Updated colors and styles
Namely added secondary button
2019-11-16 20:07:35 +01:00
Viktor De Pasquale
b744bb0a5a Fixed loading showing in incorrect view-states 2019-11-16 19:20:44 +01:00
Viktor De Pasquale
0f140b408c Added installing external modules from storage 2019-11-16 19:16:59 +01:00
osm0sis
7f6a6016d6 magiskboot: add simple workaround for Samsung offset header variant
- some Samsung devices (e.g. Galaxy S5 SMG-900H) use a slightly different AOSP bootimg.h variant with `#define BOOT_NAME_SIZE 20` instead of 16
- since all known examples of these device images do not have anything in the NAME or CMDLINE fields, and the bootloader also accepts standard AOSP images, simply offset the SHA1/SHA256 detection by 4 bytes to avoid false positives from these images, remain an equally effective detection shortcut, and ensure a proper SHA1 checksum on repack

aosp-dtbhdt2-4offhash-seandroid-256sig-samsung_gs5-smg900h-boot.img
UNPACK CHECKSUM [00000000b11580f7d20f70297cdc31e02626def0356c82b90000000000000000]
REPACK CHECKSUM [73b18751202e56c433f89dfd1902c290eaf4eef3e167fcf03b814b59a5e984b6]
AIK CHECKSUM    [b11580f7d20f70297cdc31e02626def0356c82b9000000000000000000000000]

This patch should result in a `magiskboot unpack -n boot.img; magiskboot repack boot.img` new-boot.img matching the AIK CHECKSUM above.
2019-11-16 03:23:49 -05:00
Nick
44ed0a3279 Update RU strings
Minor improvements and fixes
2019-11-16 03:23:32 -05:00
dark-basic
9964e1bb8e Update strings.xml 2019-11-16 03:23:20 -05:00
Viktor De Pasquale
8b8f725499 Fixed log items not being refreshed
Close #2079
2019-11-16 03:20:43 -05:00
topjohnwu
bab856bce2 Move biometric settings higher in the list 2019-11-16 03:19:25 -05:00
Viktor De Pasquale
711799b194 Added forced loading per user's demand
Added reselecting action (scroll up real fast)
2019-11-15 22:26:00 +01:00
topjohnwu
3d285b91c6 Use ContextCompat 2019-11-15 11:01:39 -05:00
vvb2060
1dc531930d Update zh-rCN translation 2019-11-15 10:55:51 -05:00
Ilya Kushnir
3d3345acac Update RU strings 2019-11-15 10:55:41 -05:00
Viktor De Pasquale
2105cacce3 Fixed fab background color in dark mode
Now it's recognizable from the background
2019-11-14 19:10:49 +01:00
Viktor De Pasquale
9d1d1710eb Added new search functionality to module screen 2019-11-14 18:56:03 +01:00
Viktor De Pasquale
c69dcf3e20 Added hiding keyboard when "done" button pressed 2019-11-14 15:19:48 +01:00
Viktor De Pasquale
eec5b37da1 Fixed inconsistent animations in hide 2019-11-14 15:12:53 +01:00
topjohnwu
b29f0ca4d1 Support using BiometricPrompt 2019-11-14 05:42:39 -05:00
topjohnwu
576efbdc1b Move su logs out of magiskdb 2019-11-14 00:01:06 -05:00
topjohnwu
a7f0510a3e Update build.gradle 2019-11-13 17:17:21 -05:00
topjohnwu
2ef088cb60 Update RepoDao 2019-11-13 13:23:58 -05:00
topjohnwu
7c320b6fc4 Reformat RxJava extensions 2019-11-13 13:22:51 -05:00
Viktor De Pasquale
e1bda4ee8b Added new filter for hide section
Parts of which will be reused in modules down the line
2019-11-13 18:29:30 +01:00
topjohnwu
5a4c82b860 Bump stub version 2019-11-13 03:01:38 -05:00
孟武.尼德霍格.龍
9b297b752e Update strings.xml 2019-11-13 02:37:35 -05:00
vvb2060
1d6ba58ccd Update zh-rCN translation 2019-11-13 02:37:10 -05:00
topjohnwu
1542447822 Reuse buffer 2019-11-13 02:36:45 -05:00
topjohnwu
a6f0aff659 Only store UID for current user 2019-11-13 02:36:34 -05:00
Viktor De Pasquale
54930024f5 Added biometric dialog instead of fingerprint one 2019-11-12 18:01:24 +01:00
Viktor De Pasquale
c5f2f63458 Fixed slow scrolling and list updates on hide screen 2019-11-12 17:23:27 +01:00
Viktor De Pasquale
b2b81a5d0f Fixed "enabled" state for download action button 2019-11-12 16:45:28 +01:00
Viktor De Pasquale
265dca3723 Removed intermediate loading item
- adding intermediate items causes recyclerview renderer to display artifacts (copies of some views)
2019-11-12 15:58:32 +01:00
topjohnwu
171ddab32b Reorganize code handling su requests 2019-11-12 03:20:07 -05:00
topjohnwu
2aee0b0be0 Refactor code for handling MagiskDB 2019-11-11 15:46:02 -05:00
vvb2060
817cdf7113 fix multiuser owner_managed mode 2019-11-11 14:12:26 -05:00
Viktor De Pasquale
495e734428 Updated module sections so it looks more consistent 2019-11-11 19:36:40 +01:00
Viktor De Pasquale
82120cf47f Added processing of the download states 2019-11-11 18:01:23 +01:00
Viktor De Pasquale
027a5695f2 Added progressbars to repo items 2019-11-11 18:00:36 +01:00
Viktor De Pasquale
d6d82edff5 Fixed file service not broadcasting indeterminate states 2019-11-11 17:59:44 +01:00
Viktor De Pasquale
a12eb3fc6f Fixed incorrect indeterminate progressbar color 2019-11-11 17:59:09 +01:00
Viktor De Pasquale
6c84574366 Added loading item to modules 2019-11-11 16:22:33 +01:00
topjohnwu
1a38f25bd9 Properly invoke method 2019-11-10 14:59:19 -05:00
topjohnwu
ad40e53349 Update hacks 2019-11-09 18:17:16 -05:00
topjohnwu
a2ddf362d8 Make a.a not extend AppComponentFactory
Fix #2053
2019-11-09 16:13:15 -05:00
Ilya Kushnir
65eca31635 Updating RU translation 2019-11-09 04:40:10 -05:00
osm0sis
8b0b4a2c39 SignBoot: also catch empty streamed signature as indicating not signed
- compare against new byte[] array as a quick tell, since when streaming from a partition with an unsigned image "signature" would of course read without issue but then remain filled by zero padding, resulting in the following:
    java.io.IOException: unexpected end-of-contents marker
        at org.bouncycastle.asn1.ASN1InputStream.readObject(Unknown Source:14)
        at com.topjohnwu.signing.SignBoot$BootSignature.<init>(SignBoot.java:235)
        at com.topjohnwu.signing.SignBoot.verifySignature(SignBoot.java:144)
        at com.topjohnwu.signing.BootSigner.main(BootSigner.java:15)
        at a.a.main(a.java:20)
2019-11-09 04:39:41 -05:00
Viktor De Pasquale
bc5cbe9fba Updated module item design to follow suit with the rest of the app 2019-11-08 19:19:19 +01:00
Viktor De Pasquale
f83f92d3fa Updated modules screen so it displays all the content in one recyclerview
Added "endless" scrolling support
 - this is done in order to display everything very swiftly and load as user needs it
 - for the most part we'll download only ~10 items and load the rest as scroll progresses, this accomplishes the illusion that whole list is being populated
Added sections and updated repo view
2019-11-08 19:04:30 +01:00
topjohnwu
c0216c0653 Get XMLs directly 2019-11-08 02:59:09 -05:00
topjohnwu
61de63a518 Cleanup manifest 2019-11-08 02:15:30 -05:00
topjohnwu
d952cc2327 Properly solve the connection problem 2019-11-07 17:41:59 -05:00
Viktor De Pasquale
19fd4dd89c Partially reverted removing "moveToState" 2019-11-06 18:52:58 +01:00
Viktor De Pasquale
f941f5c0b0 Fixed observer not being called immediately 2019-11-06 18:37:11 +01:00
Viktor De Pasquale
c7cad7e4aa Updated modules so they are properly arranged to respective sections
Small updates to module UI
2019-11-06 17:22:26 +01:00
Viktor De Pasquale
1c8988d3f7 Updated "night" style of elevated card 2019-11-05 19:39:06 +01:00
Viktor De Pasquale
70a3dbe2b0 Added primitive implementation of modules screen 2019-11-05 19:38:02 +01:00
Viktor De Pasquale
efbb3ab25f Fixed red tint regarding system security not being spanned across the whole card 2019-11-05 16:19:41 +01:00
topjohnwu
46447f7cfd Proper string buffer size 2019-11-05 01:46:46 -05:00
topjohnwu
a6e62e07a2 Sort modules ignore case
Close #2024
2019-11-04 17:14:18 -05:00
topjohnwu
b1d25e0503 Reuse ALPHANUM 2019-11-04 15:42:40 -05:00
topjohnwu
25c557248c Use ContentProvider call method for communication
Previously, we use either BroadcastReceivers or Activities to receive
messages from our native daemon, but both have their own downsides.
Some OEMs blocks broadcasts if the app is not running in the background,
regardless of who the caller is. Activities on the other hand, despite
working 100% of the time, will steal the focus of the current foreground
app, even though we are just doing some logging and showing a toast.
In addition, since stubs for hiding Magisk Manager is introduced, our
only communication method is left with the broadcast option, as
only broadcasting allows targeting a specific package name, not a
component name (which will be obfuscated in the case of stubs).

To make sure root requests will work on all devices, Magisk had to do
some experiments every boot to test whether broadcast is deliverable or
not. This makes the whole thing even more complicated then ever.

So lets take a look at another kind of component in Android apps:
ContentProviders. It is a vital part of Android's ecosystem, and as far
as I know no OEMs will block requests to ContentProviders (or else
tons of functionality will break catastrophically). Starting at API 11,
the system supports calling a specific method in ContentProviders,
optionally sending extra data along with the method call. This is
perfect for the native daemon to start a communication with Magisk
Manager. Another cool thing is that we no longer need to know the
component name of the reciever, as ContentProviders identify themselves
with an "authority" name, which in Magisk Manager's case is tied to the
package name. We already have a mechanism to keep track of our current
manager package name, so this works out of the box.

So yay! No more flaky broadcast tests, no more stupid OEMs blocking
broadcasts for some bizzare reasons. This method should in theory
work on almost all devices and situations.
2019-11-04 14:32:28 -05:00
Viktor De Pasquale
b0e7c65504 Added icon for "all processes hidden" state 2019-11-04 17:40:13 +01:00
Viktor De Pasquale
b18b044b63 Updated filter card to be more compact 2019-11-04 17:39:51 +01:00
Viktor De Pasquale
8f5f8db717 Fixed dark mode colors 2019-11-04 17:39:17 +01:00
Viktor De Pasquale
016e28383b Added animated progressbar 2019-11-04 16:58:39 +01:00
Viktor De Pasquale
f1427e9279 Updated hide item layout 2019-11-04 16:45:54 +01:00
Viktor De Pasquale
169e9ab5ad Updated hide fragment layout and design of the filter window 2019-11-04 16:02:23 +01:00
topjohnwu
472cde29b8 Allow non supported Magisk to use Magisk Manager
Close #1576
2019-11-04 03:24:27 -05:00
linar10
73525d19e9 Update strings.xml 2019-11-03 17:15:17 -05:00
topjohnwu
26618f8d73 Don't do broadcast tests from app
Running broadcast tests from the app does not accurately verifies
whether the broadcasts can be delivered when the app is not running in
the foreground, which is why we are running the test.

The only sane way to verify broadcasts is to trigger the broadcast test
directly from the daemon on boot complete. If it is not deliverable,
then activity mode shall be chosen.

In the meantime, cleanup AndroidManifest.xml
2019-11-03 17:01:09 -05:00
topjohnwu
6f7c13b814 Refactor JarMap 2019-11-03 04:45:35 -05:00
osm0sis
e7d668502c SignBoot: improve error catching/reporting
- `!= remain` shouldn't indicate "not signed", it should indicate a read error as with `!= hdr.length`
- attempt to catch unsigned images at signature read, before they make it to `BootSignature bootsig = new BootSignature(signature);` and result in the following:
    java.io.IOException: unexpected end-of-contents marker
            at org.bouncycastle.asn1.ASN1InputStream.readObject(Unknown Source:14)
            at com.topjohnwu.signing.SignBoot$BootSignature.<init>(SignBoot.java:230)
            at com.topjohnwu.signing.SignBoot.verifySignature(SignBoot.java:139)
            at com.topjohnwu.signing.BootSigner.main(BootSigner.java:15)
            at a.a.main(a.java:20)
2019-11-03 04:22:21 -05:00
osm0sis
6fd357962f scripts: fix signing in recovery with addon.d-v1
- change to $TMPDIR in addon.d.sh since recovery addon.d-v1 backup + restore leaves you in /tmp/addon.d which the restore then deletes, which would break $BOOTSIGNER execution with the following:
    libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 1078 (main), pid 1078 (main)
    Segmentation fault
- also move $BOOTSIGNER execution to after `cd $MAGISKBIN` to ensure it's in a working directory in all cases
- addon.d.sh data mount wasn't doing anything since /data has to already be mounted for the script to be running, so move it into /system/addon.d/99-magisk.sh stub script where it might be useful on recoveries that don't mount /data initially

Fixes #2013
2019-11-03 03:00:08 -05:00
topjohnwu
0c9feedb37 Support restarting app when obfuscated 2019-11-03 02:55:22 -05:00
Viktor De Pasquale
dad52724db Updated hide fragment with more robust filtering UI 2019-11-02 18:31:20 +01:00
Vladimír Kubala
14ba002cbc Update Slovak translation 2019-11-02 11:59:20 -04:00
Viktor De Pasquale
d48e9d5d72 Removed button patterns defying MD 2019-11-02 15:59:07 +01:00
topjohnwu
7da97489cc Add v7.4.0 release notes 2019-11-02 01:24:56 -04:00
topjohnwu
a9f11b28c8 Fix busybox scripts again 2019-11-02 01:16:54 -04:00
topjohnwu
b31d986c8d Update scripts 2019-11-02 00:41:51 -04:00
Oliver Cervera
2dad751889 Update Italian translation
- updated existing strings based on english updates
- added new strings
2019-11-02 00:28:07 -04:00
osm0sis
c85b1c56af signing: fixes for bootimg hdr_v1 and hdr_v2
- increase SignBoot bootimg header version maximum from 4 to 8 (upstream AOSP is already at 3) and make a variable for future ease
- hdr read size of 1024 bytes was too small as hdr_v1 and hdr_v2 have increased the used header page areas to 1632 and 1648 bytes, respectively, so raise this to the minimum page size of 2048 and also make a variable for future ease
- do not return "not signed" for all caught exceptions, show StackTrace for future debugging then still return false for script purposes
- correct "test keys" boot image signing strings (scripts and app) to "verity keys"
2019-11-02 00:27:56 -04:00
osm0sis
6dd34aec47 scripts: refactor and major addon.d fixes
- remove redundant addon.d.sh script bits that were covered elsewhere ($TMPDIR in util_functions.sh, find_dtbo_image in patch_dtbo_image)
- refactor addon.d.sh and flash_script.sh for simplicity and readability, and put common flashing script in util_functions.sh (as patch_boot_image), which should greatly help avoid them getting out of sync going forward and fixes compressing ramdisk support and post-patch cleanup for addon.d
- add check_data to addon.d.sh since moving stock_boot* and stock_dtbo* backups depend on it and so weren't occuring with addon.d
- fix find_manager_apk with working fallback for recovery addon.d execution (where `magisk --sqlite` will not work for hidden Manager), Manager DynAPK hiding, and print a useful log warning if an APK can't be found
2019-11-02 00:27:56 -04:00
topjohnwu
4cd154675f Random dname 2019-11-01 18:52:37 -04:00
Viktor De Pasquale
24e2c3a5e9 Removed unused icons 2019-11-01 21:30:29 +01:00
Viktor De Pasquale
064523ef25 Updated checkbox height 2019-11-01 21:15:02 +01:00
Viktor De Pasquale
85f293a44e Updated policy colors and internal ids 2019-11-01 21:10:00 +01:00
Viktor De Pasquale
8e412bee5f Updated radio button sizes 2019-11-01 19:15:05 +01:00
Viktor De Pasquale
7d5555f82e Added safety notice and support section description 2019-11-01 19:02:30 +01:00
Viktor De Pasquale
6720725d27 Added clarifying tooltips and captions 2019-11-01 18:12:52 +01:00
Viktor De Pasquale
fe5c65d798 Fixed use of RxBus for toggling policies 2019-11-01 17:58:42 +01:00
Viktor De Pasquale
253f3cf1ba Fixed inconsistent icon sizes 2019-11-01 17:55:25 +01:00
Viktor De Pasquale
d8d72f92b3 Fixed policy toggle being impossible to cancel 2019-11-01 14:47:59 +01:00
topjohnwu
a30f5b175f Fix busybox makefiles 2019-11-01 09:38:01 -04:00
topjohnwu
8277896ca1 Make sure uninstall.sh is executed on remove 2019-11-01 03:07:12 -04:00
topjohnwu
493068c073 Attempt to rescan zygote multiple times
Close #1654
2019-11-01 02:12:28 -04:00
topjohnwu
f4299fbea8 Update BusyBox to 1.31.1 2019-10-31 18:11:10 -04:00
topjohnwu
10ce11d671 Fix config/locale issues
Close #1977
2019-10-31 17:13:06 -04:00
Viktor De Pasquale
db2e48b49f Added manager mode recognition 2019-10-31 20:58:17 +01:00
Viktor De Pasquale
5e089451af Added loaders to superuser and hide 2019-10-31 20:53:57 +01:00
Viktor De Pasquale
6aa22267f4 Updated Hide screen to be fully functioning
...although still misses search :(
2019-10-31 20:34:07 +01:00
topjohnwu
0f34457a10 Directly store strings in viewmodel 2019-10-31 15:33:13 -04:00
topjohnwu
34c65e13bc Fix strings
Close #2012
2019-10-31 12:39:54 -04:00
John Wu
17a77e2577 Shortcut booleans 2019-10-31 02:44:25 -04:00
John Wu
0f219e5ae6 Better argument parsing logic 2019-10-31 02:44:25 -04:00
osm0sis
353c3c7d81 magiskboot: add unpack -n to help with repack validity tests
- support unpack without decompression to allow easy testing of magiskboot's header, structure and hashing handling by comparing repack checksum versus origbootimg
- make -n first to match repack
2019-10-31 02:44:25 -04:00
Rom
0a89edf3b0 Update French translation 2019-10-31 02:04:00 -04:00
topjohnwu
e7155837d7 Make sure magisk daemon won't get killed by init
According to this comment in #1880:
https://github.com/topjohnwu/Magisk/issues/1880#issuecomment-546657588

If Linux recycled our PPID, and coincidentally the process that reused
the PPID is root, AND init wants to kill the whole process group,
magiskd will get killed as a result.

There is no real way to block a SIGKILL signal, so we simply make sure
our daemon PID is the process group leader by renaming the directory.

Close #1880
2019-10-31 01:57:47 -04:00
Viktor De Pasquale
f76c020dd7 Added implementation of hide screen
Very much wip and doesn't work at all
2019-10-30 21:58:42 +01:00
Viktor De Pasquale
722fba7805 Updated bottom nav width to not spread useless spaces 2019-10-30 21:09:00 +01:00
Viktor De Pasquale
86551909fc Added safe mode notice to modules screen 2019-10-30 17:59:03 +01:00
Viktor De Pasquale
588e94c11d Updated locations of certain elements
Settings are now only on home screen as it directly relates to what user might want to do. It is highly unlikely that they would jump from any other screen to settings.
Log is no longer main destination as it's not used very widely; it's been moved to Superuser screen. This screen now encapsulates all root-related stuff.

Home screen is now strictly info-based, except install buttons, of course.
2019-10-30 17:11:42 +01:00
topjohnwu
31e003bda5 Fix bug in version detection 2019-10-30 05:24:22 -04:00
topjohnwu
490e4d3180 Target the proper channel in stub 2019-10-30 05:00:52 -04:00
topjohnwu
dc9f69bab0 Minor changes 2019-10-30 04:15:53 -04:00
topjohnwu
fdf04f77f2 Send bitmap to notifications and shortcuts
On API 23+, the platform unifies the way to handle drawable
resources across processes: all drawables can be passed via Icon.
This allows us to send raw bitmap to the system without the need to
specify a resource ID. This means that we are allowed to NOT include
these drawable resources within our stub APK, since our full APK can
draw the images programmatically and send raw bitmaps to the system.
2019-10-30 01:02:53 -04:00
Viktor De Pasquale
9e66310c28 Updated fragment container 2019-10-29 16:58:46 +01:00
Viktor De Pasquale
93c422dce6 Added post-merge fixes 2019-10-29 16:52:42 +01:00
Viktor De Pasquale
7d6eebdae3 Fixed unreasonable change resulting in major breakage all around the app 2019-10-29 16:50:01 +01:00
Viktor De Pasquale
f11bb609c9 Merge remote-tracking branch 'john/master' into feature/redesign
# Conflicts:
#	app/build.gradle
#	app/src/main/java/com/topjohnwu/magisk/ClassMap.kt
#	app/src/main/java/com/topjohnwu/magisk/Info.kt
#	app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt
#	app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt
2019-10-29 15:53:53 +01:00
topjohnwu
5e87483f34 Move addAssetPath to shared 2019-10-29 07:37:19 -04:00
topjohnwu
f7aa451591 Update strings 2019-10-29 07:36:50 -04:00
topjohnwu
321d11c2c6 Move Mapping class 2019-10-29 07:21:14 -04:00
Viktor De Pasquale
b910a92731 Fixed ui issues in unrooted state 2019-10-27 11:00:16 +01:00
topjohnwu
ee447bc4ce Improve Keygen yet again 2019-10-26 21:11:32 -04:00
Nathan Muccino
31153e4366 Minor grammatical changes
The plural form of the words 'documentation' and 'following' are used very rarely if ever and I don't believe that they should be used in this particular context.
2019-10-26 19:26:27 -04:00
topjohnwu
7693024c29 Replace general resources with platform 2019-10-26 19:23:57 -04:00
Mevlüt TOPÇU
9628700a2f Update Turkish language
Hi,

Merge please

Thanks
2019-10-26 19:03:52 -04:00
Taras
38576173cb Update Ukrainian translation 2019-10-26 19:03:37 -04:00
topjohnwu
19a769c12e Update dependencies 2019-10-26 19:02:11 -04:00
topjohnwu
3c1db7d2f7 Fix some A/B devices unable to boot into recovery
Some newer recovery ramdisk no longer have /sbin/recovery.
Add /system/bin/recovery as an additional indication for recovery.

Close #1920
2019-10-26 17:12:35 -04:00
topjohnwu
626507093a Don't need to wrap another layer of context 2019-10-26 15:37:12 -04:00
Viktor De Pasquale
ee7d297ca8 Partially reverted developer section changes 2019-10-26 21:14:01 +02:00
Viktor De Pasquale
a70c0174e1 Added device info card 2019-10-26 21:03:25 +02:00
Viktor De Pasquale
da707afa3f Updated install ui to better fit app's theme 2019-10-26 17:40:29 +02:00
Viktor De Pasquale
a41597431c Added more information to magisk/manager cards 2019-10-26 17:33:27 +02:00
Viktor De Pasquale
d0b817381e Added "caching" of the safetynet response 2019-10-26 16:03:07 +02:00
Viktor De Pasquale
60a2e9b5dc Updated home info cards to be more compressed 2019-10-26 15:14:20 +02:00
Viktor De Pasquale
df3a37b0a3 Updated developer section to be horizontally scrollable instead of vertically
In order to make room for more information
2019-10-26 12:41:34 +02:00
Viktor De Pasquale
5f4718cd13 Added string resources for install screen 2019-10-25 19:17:13 +02:00
Viktor De Pasquale
3cc5cb3123 Updated the install flow
Now the binary is downloaded after user selects a method. It also shows download progress as the file's being downloaded
2019-10-25 19:13:54 +02:00
Viktor De Pasquale
8a2872afa4 Removed pre-download while installing magisk 2019-10-25 17:46:20 +02:00
Viktor De Pasquale
85941c4729 Removed lol code 2019-10-25 15:40:46 +02:00
topjohnwu
588b3d14a3 Fix typo 2019-10-24 15:37:32 -04:00
vvb2060
815efa7791 Update zh-rCN translation 2019-10-24 13:04:36 -04:00
topjohnwu
97a691ce2f Improve keygen for signing repackaged manager 2019-10-24 13:04:15 -04:00
Viktor De Pasquale
82eeefb544 Added system version to the details section for safetynet checks 2019-10-24 18:40:15 +02:00
topjohnwu
9d948f2c2b Temporary disable verification when hiding app
For some reason, Google Play Protect randomly blocks our self-signed
repackaged Magisk Manager APKs. Since we are root, the sky is our
limit, so yeah, disable package verification temporarily when installing
patched APKs, LOLz

Close #1979
2019-10-24 12:23:03 -04:00
Viktor De Pasquale
f6061ba00e Fixed bottom navigation popping up when it shouldn't 2019-10-24 18:07:36 +02:00
Viktor De Pasquale
9e3afcfe7a Added safetynet implementation 2019-10-24 18:00:51 +02:00
topjohnwu
0b87108174 Move things around 2019-10-24 05:21:42 -04:00
topjohnwu
7fc7809cfc More precise channel targeting 2019-10-24 04:25:05 -04:00
topjohnwu
c30be20e49 Minor CachedValue fix 2019-10-24 04:02:01 -04:00
topjohnwu
25c64db0a1 Treat outdated stub as outdated manager 2019-10-24 03:54:16 -04:00
topjohnwu
676e9c6593 Provide upgrade path for stubs 2019-10-24 02:47:40 -04:00
topjohnwu
d459859361 Show stub version 2019-10-24 00:54:40 -04:00
topjohnwu
2be0cef446 Add proper intent filters to stub 2019-10-23 17:55:26 -04:00
topjohnwu
294db93fde Copy instead of move
We might be copying from CE to DE storage, which cannot be moved
2019-10-23 17:20:55 -04:00
Viktor De Pasquale
21f2f86cb8 Added safetynet implementation
The implementation itself was moved from fragment to self contained event. The result resolution might be moved to the event as well
2019-10-23 21:17:53 +02:00
Viktor De Pasquale
04576ca828 Added install implementation 2019-10-23 19:14:39 +02:00
Viktor De Pasquale
067cb0cd9d Fixed magisk button states 2019-10-23 16:20:01 +02:00
topjohnwu
7f971f7173 Make sure our constructor is preserved 2019-10-23 07:51:32 -04:00
topjohnwu
5c7b59524d Fix strings 2019-10-23 07:15:28 -04:00
topjohnwu
5133e5910e Don't relaunch app immediately 2019-10-23 07:12:00 -04:00
osm0sis
1512c350df magiskboot: add SPRD dt support
- per https://github.com/USA-RedDragon/sprd-mkbootimg-tools/blob/master/dtbtool.c
- touch up hdr and table naming to be more uniform
2019-10-23 06:58:31 -04:00
あきと ミズキト
a5fc7891a6 build: Addressed file not found 2019-10-23 06:57:47 -04:00
Abhishek Dubey
3eb9633231 Add Hindi Translation 2019-10-23 06:53:46 -04:00
onevt
ac67b48247 Fix swedish translation typo 2019-10-23 06:53:07 -04:00
topjohnwu
81b65ea646 Exclude stub id mappings from git 2019-10-23 06:45:47 -04:00
topjohnwu
45c1f6bc27 Fix restore manager when running as stub 2019-10-23 06:43:08 -04:00
topjohnwu
0d31e5c8b1 Properly migrate update channels when repackaging 2019-10-23 06:41:25 -04:00
topjohnwu
6378abf454 Make stub support directBootAware 2019-10-23 05:52:32 -04:00
topjohnwu
f8fcaadb5b Hide manager with stub if feasible 2019-10-23 05:50:06 -04:00
topjohnwu
0b5fd3ee76 Only allow hide/restore app if connected 2019-10-23 05:43:01 -04:00
topjohnwu
d010cb7e42 Update stub 2019-10-23 05:19:54 -04:00
topjohnwu
71136d7347 Manually trigger broadcast tests if necessary 2019-10-22 16:04:20 -04:00
topjohnwu
a18c552ddf Guard env state behind cached objects 2019-10-22 15:37:55 -04:00
Viktor De Pasquale
17fb8f2298 Added new magisk install flow 2019-10-22 20:46:09 +02:00
Viktor De Pasquale
fbfc4e72ca Updated appbar design to be more android-like 2019-10-22 18:09:26 +02:00
Viktor De Pasquale
d2e171eabc Added a way to listen to download service from homepage and behave accordingly 2019-10-22 17:29:45 +02:00
Viktor De Pasquale
e50094af80 Added install fragment 2019-10-22 16:29:01 +02:00
Viktor De Pasquale
93edf72993 Rationalize download failure 2019-10-22 16:26:28 +02:00
Viktor De Pasquale
a230d63cf9 Fixed having an error doesn't inform external listeners 2019-10-22 16:22:28 +02:00
topjohnwu
9656878ef3 Actually apply the input name 2019-10-22 05:06:17 -04:00
Viktor De Pasquale
7ded7de39a Added custom dialog for setting app's name after repackaging 2019-10-22 04:52:19 -04:00
topjohnwu
0f74e89b44 Introduce component agnostic communication
Usually, the communication between native and the app is done via
sending intents to either broadcast or activity. These communication
channels are for launching root requests dialogs, sending root request
notifications (the toast you see when an app gained root access), and
root request logging.

Sending intents by am (activity manager) usually requires specifying
the component name in the format of <pkg>/<class name>. This means parts
of Magisk Manager cannot be randomized or else the native daemon is
unable to know where to send data to the app.

On modern Android (not sure which API is it introduced), it is possible
to send broadcasts to a package, not a specific component. Which
component will receive the intent depends on the intent filter declared
in AndroidManifest.xml. Since we already have a mechanism in native code
to keep track of the package name of Magisk Manager, this makes it
perfect to pass intents to Magisk Manager that have components being
randomly obfuscated (stub APKs).

There are a few caveats though. Although this broadcasting method works
perfectly fine on AOSP and most systems, there are OEMs out there
shipping ROMs blocking broadcasts unexpectedly. In order to make sure
Magisk works in all kinds of scenarios, we run actual tests every boot
to determine which communication method should be used.

We have 3 methods in total, ordered in preference:
1. Broadcasting to a package
2. Broadcasting to a specific component
3. Starting a specific activity component

Method 3 will always work on any device, but the downside is anytime
a communication happens, Magisk Manager will steal foreground focus
regardless of whether UI is drawn. Method 1 is the only way to support
obfuscated stub APKs. The communication test will test method 1 and 2,
and if Magisk Manager is able to receive the messages, it will then
update the daemon configuration to use whichever is preferable. If none
of the broadcasts can be delivered, then the fallback method 3 will be
used.
2019-10-21 13:59:04 -04:00
topjohnwu
953c40b083 Allow upgrade Magisk daemon in emulator 2019-10-21 13:58:57 -04:00
Viktor De Pasquale
2bb39bee2f Updated redesign button design 2019-10-21 19:30:14 +02:00
Viktor De Pasquale
ce2ca5446a Fixed checkbox's theme implementation in dark mode 2019-10-21 19:22:56 +02:00
Viktor De Pasquale
8a014ff786 Added most of the remaining functionality for Magisk install dialog 2019-10-21 19:22:16 +02:00
topjohnwu
271b0287d8 Pass in stub version just in case 2019-10-20 17:47:55 -04:00
topjohnwu
96a8a2a8b8 Make SuRequest default to Translucent.NoTitleBar
Close #1959
2019-10-20 17:35:38 -04:00
Viktor De Pasquale
dc09ec7598 Added theme mode picker dialog
Redesigned settings' selector for dark mode a bit
2019-10-20 17:28:18 +02:00
Viktor De Pasquale
27fb0474d5 Added more standard night-mode system 2019-10-20 17:27:39 +02:00
Viktor De Pasquale
7f0a87742a Fixed design issues in dialogs
Dark theme not being properly implemented
Icons were not set
2019-10-20 17:26:00 +02:00
Viktor De Pasquale
47e236788c Added uninstall dialog 2019-10-20 16:47:02 +02:00
topjohnwu
75306f658f Revert "Drop API 17 (Android 4.2) support"
Turns out that we cannot use AndroidKeystore anyways, so we don't
actually need to drop API 17. Revert this change.
2019-10-20 07:13:03 -04:00
topjohnwu
325d9a0b86 Generate keys for signing hidden Magisk Manager 2019-10-20 06:56:33 -04:00
Viktor De Pasquale
236ad57608 Added showing download progress in the home ui 2019-10-20 12:40:50 +02:00
Viktor De Pasquale
6d03798314 Added internal download pseudo broadcasts 2019-10-20 12:40:26 +02:00
Viktor De Pasquale
c954a4f7bc Updated icons and texts for magisk hide and safetynet 2019-10-20 11:29:04 +02:00
Viktor De Pasquale
ba588d1097 Updated position of quick links on superuser screen 2019-10-20 11:24:45 +02:00
Viktor De Pasquale
44f7c9a545 Added animations for toolbar transitions 2019-10-20 11:14:49 +02:00
Viktor De Pasquale
b910db322b Fixed snackbar behavior in contrast with bottom navigation 2019-10-20 10:57:29 +02:00
Viktor De Pasquale
c44a942fb7 Added entry for safetynet attestation 2019-10-19 22:28:01 +02:00
Viktor De Pasquale
d713ad3499 Added "advanced" install options for installing magisk 2019-10-19 22:14:23 +02:00
Viktor De Pasquale
ddf40df649 Updated colors and elevation to be less distracting 2019-10-19 21:12:30 +02:00
Viktor De Pasquale
7c6d85221d Updated policy items design 2019-10-19 21:07:06 +02:00
Viktor De Pasquale
b66b82a6e9 Added logic to superuser screen 2019-10-19 20:51:28 +02:00
Viktor De Pasquale
c44b85ea87 Fixed paddings on su screen 2019-10-19 18:29:48 +02:00
topjohnwu
a02493fbaa Workaround R8 bug 2019-10-19 05:44:56 -04:00
topjohnwu
9c27d691dd Drop API 17 (Android 4.2) support 2019-10-19 03:11:54 -04:00
Viktor De Pasquale
fcbf56e93a Added superuser screen implementation
* partially
2019-10-18 19:38:55 +02:00
Viktor De Pasquale
a539ffb188 Updated styles due to low accessibility 2019-10-18 18:15:22 +02:00
Viktor De Pasquale
512f533a80 Added hide fragment for future use 2019-10-18 17:04:41 +02:00
Viktor De Pasquale
96ef9cdbee Fixed insets not being implicitly asked for by the framework resulting in no coverage for other than main fragments 2019-10-18 16:39:08 +02:00
topjohnwu
935bd01f59 Post process release APKs 2019-10-17 18:02:31 -04:00
topjohnwu
eeb5d669f6 Assign signing keystore location in config 2019-10-17 16:20:01 -04:00
Viktor De Pasquale
28fcbbcf7b Added basic preferences to settings 2019-10-17 19:26:35 +02:00
Viktor De Pasquale
0f4326151f Added titles 2019-10-17 19:26:25 +02:00
Viktor De Pasquale
e0e27774ad Added remaining stubs for the redesign 2019-10-17 18:57:00 +02:00
Viktor De Pasquale
1223b48b2c Fixed dialog automatically dismissing itself 2019-10-17 15:52:52 +02:00
Viktor De Pasquale
d8338f0b48 Fixed event duplication 2019-10-17 15:47:11 +02:00
Viktor De Pasquale
38019f7f42 Added env check to homepage 2019-10-17 15:37:10 +02:00
topjohnwu
78daa2eb62 Do not use string resources for app label
This not only simplifies hiding stub APKs (no resource IDs involved),
but also opens the opportunity to allow users to customize whatever
app name they want after it is hidden.
2019-10-17 04:47:46 -04:00
topjohnwu
40eda05a30 Make main app fully independent from the stub
- Skip 0x7f01XXXX - 0x7f05XXXX resource IDs in the main app; they are
reserved for stub resources
- Support sending additional data from host to guest
- Use resource mapping passed from host when they are being sent
to the system framework (notifications and shortcuts)
2019-10-17 02:55:42 -04:00
topjohnwu
9f9de8c43b Obfuscate WorkManager components
Remove unused components and hack the context sent into WorkManager
2019-10-16 17:03:55 -04:00
Viktor De Pasquale
23978ef4d2 Updated bottom padding for home fragment 2019-10-16 19:04:37 +02:00
Viktor De Pasquale
3b4cb23112 Fixed error in navigation implementation 2019-10-16 18:53:38 +02:00
Viktor De Pasquale
974cb1167f Added post-merge fixes 2019-10-16 17:53:35 +02:00
Viktor De Pasquale
6ccbc272c6 Merge remote-tracking branch 'john/master' into feature/redesign
# Conflicts:
#	app/build.gradle
#	app/src/main/AndroidManifest.xml
#	app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt
#	app/src/main/java/com/topjohnwu/magisk/model/navigation/MagiskNavigationEvent.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt
#	app/src/main/java/com/topjohnwu/magisk/view/MagiskDialog.kt
#	app/src/main/res/layout/dialog_magisk_base.xml
2019-10-16 17:33:54 +02:00
Viktor De Pasquale
0eb28c3265 Added navigation delegation to bypass default one
By making a delegate like such we protect ourselves against intrusions in views' logic
2019-10-16 17:27:11 +02:00
Viktor De Pasquale
2daa131fb2 Added layout behavior to dismiss toolbars when scrolling 2019-10-16 16:08:07 +02:00
Viktor De Pasquale
51247d36c5 Added disabled state for sections where unrooted user shouldn't have access 2019-10-16 15:47:41 +02:00
topjohnwu
a910c8ccd8 Support stub APK upgrades 2019-10-16 05:07:29 -04:00
topjohnwu
43bda2d4a4 Allow component classname obfuscation 2019-10-16 04:38:31 -04:00
topjohnwu
c7033dd757 Allow injecting custom channel URL for debug 2019-10-16 01:54:59 -04:00
topjohnwu
5673a9bace Move system accessible resources to shared 2019-10-15 05:49:23 -04:00
topjohnwu
34ff764515 Stabilize resource IDs 2019-10-15 04:37:12 -04:00
topjohnwu
1b3a009da7 Remove unused WorkManager components 2019-10-15 04:36:09 -04:00
topjohnwu
a49002bb2c Reorganize string resources 2019-10-15 03:33:22 -04:00
Omar Kharrab
7342fc2307 Update Arabic translation 2019-10-15 02:57:43 -04:00
topjohnwu
9867a3bd60 Pedantic boot_img_hdr multi-version support 2019-10-15 01:46:29 -04:00
topjohnwu
5ffb9eaa5b Support loading Magisk Manager from stub on 9.0+
In the effort of preventing apps from crawling APK contents across the
whole installed app list to detect Magisk Manager, the solution here
is to NOT install the actual APK into the system, but instead
dynamically load the full app at runtime by a stub app. The full APK
will be stored in the application's private internal data where
non-root processes cannot read or scan.

The basis of this implementation is the class "AppComponentFactory"
that is introduced in API 28. If assigned, the system framework will
delegate app component instantiation to our custom implementation,
which allows us to do all sorts of crazy stuffs, in our case dynamically
load classes and create objects that does not exist in our APK.

There are a few challenges to achieve our goal though. First, Java
ClassLoaders follow the "delegation pattern", which means class loading
resolution will first be delegated to the parent loader before we get
a chance to do anything. This includes DexClassLoader, which is what
we will be using to load DEX files at runtime. This is a problem
because our stub app and full app share quite a lot of class names.
A custom ClassLoader, DynamicClassLoader, is created to overcome this
issue: it will always load classes in its current dex path before
delegating it to the parent.

Second, all app components (with the exception of runtime
BroadcastReceivers) are required to be declared in AndroidManifest.xml.
The full Magisk Manager has quite a lot of components (including
those from WorkManager and Room). The solution is to copy the complete
AndroidManifest.xml from the full app to the stub, and our
AppComponentFactory is responsible to construct the proper objects or
return dummy implementations in case the full APK isn't downloaded yet.

Third, other than classes, all resources required to run the full app
are also not bundled with the stub APK. We have to call an internal API
`AssetManager.addAssetPath(String)` to add our downloaded full APK into
AssetManager in order to access resources within our full app. That
internal API has existed forever, and is whitelisted from restricted
API access on modern Android versions, so it is pretty safe to use.

Fourth, on the subject of resources, some resources are not just being
used by our app at runtime. Resources such as the app icon, app label,
launch theme, basically everything referred in AndroidManifest.xml,
are used by the system to display the app properly. The system get these
resources via resource IDs and direct loading from the installed APK.
This subset of resources would have to be copied into the stub to make
the app work properly.

Fifth, resource IDs are used all over the place in XMLs and Java code.
The resource IDs in the stub and full app cannot missmatch, or
somewhere, either it be the system or AssetManager, will refer to the
incorrect resource. The full app will have to include all resources in
the stub, and all of them have to be assigned to the exact same IDs in
both APKs. To achieve this, we use AAPT2's "--emit-ids" option to dump
the resource ID mapping when building the stub, and "--stable-ids" when
building the full APK to make sure all overlapping resources in full
and stub are always assigned to the same ID.

Finally, both stub and full app have to work properly independently.
On 9.0+, the stub will have to first launch an Activity to download
the full APK before it can relaunch into the full app. On pre-9.0, the
stub should behave as it always did: download and prompt installation
to upgrade itself to full Magisk Manager. In the full app, the goal
is to introduce minimal intrusion to the code base to make sure this
whole thing is maintainable in the future. Fortunately, the solution
ends up pretty slick: all ContextWrappers in the app will be injected
with custom Contexts. The custom Contexts will return our patched
Resources object and the ClassLoader that loads itself, which will be
DynamicClassLoader in the case of running as a delegate app.
By directly patching the base Context of ContextWrappers (which covers
tons of app components) and in the Koin DI, the effect propagates deep
into every aspect of the code, making this change basically fully
transparent to almost every piece of code in full Magisk Manager.

After this commit, the stub app is able to properly download and launch
the full app, with most basic functionalities working just fine.
Do not expect Magisk Manager upgrades and hiding (repackaging) to
work properly, and some other minor issues might pop up.
This feature is still in the early WIP stages.
2019-10-14 03:49:17 -04:00
Viktor De Pasquale
37fa227fb5 Added refreshing upon connection restore 2019-10-12 16:30:18 +02:00
Viktor De Pasquale
9dd272b357 Fixed main cards collapsing on themselves 2019-10-12 16:22:12 +02:00
Viktor De Pasquale
277298feae Updated night style for elevated cards 2019-10-12 16:11:05 +02:00
Viktor De Pasquale
ff24bc0b68 Updated card design on homepage 2019-10-12 16:10:44 +02:00
topjohnwu
b05b688267 Fix issues in stub APK 2019-10-12 03:58:45 -04:00
Simon Shi
f3d7f85063 Fix incorrect link path for /sbin/.core 2019-10-12 01:00:15 -04:00
topjohnwu
de969a9dab Downgrade recyclerview 2019-10-12 00:53:04 -04:00
topjohnwu
59fd38bbf8 Add v7.3.5 changelog 2019-10-11 16:12:32 -04:00
topjohnwu
06dc6df270 Allow dalvik runtime to load snet 2019-10-11 03:58:04 -04:00
topjohnwu
ff8460b361 Update dependencies 2019-10-11 03:29:55 -04:00
topjohnwu
674d272eaa Support pre-5.0 without GMS
Fix #1912
2019-10-11 01:46:15 -04:00
topjohnwu
c3e00c279d Legacy adb shell does not have uname 2019-10-11 01:45:06 -04:00
dark-basic
175d920c94 Update strings.xml
I'M BACK.
New translations were added.
2019-10-10 17:17:09 -04:00
Viktor De Pasquale
700c51f95c Added animated home icons 2019-10-10 22:00:39 +02:00
topjohnwu
04920883ea Change code for handling tar files 2019-10-10 15:07:45 -04:00
Viktor De Pasquale
659914afbe Updated navigation icons 2019-10-10 19:08:15 +02:00
Viktor De Pasquale
ee06aed94b Updated toolbar and bottom bar design implementation
TBD:
Both toolbars should move away from the screen when scrolling
2019-10-10 17:34:06 +02:00
Viktor De Pasquale
af1f5d5ab2 Fixed showing magisk version when not installed 2019-10-10 16:51:20 +02:00
topjohnwu
5e44b0b9d5 Use raw literals for scripts 2019-10-09 17:38:45 -04:00
topjohnwu
23c1a1dab8 Some code reorganizing 2019-10-09 16:01:21 -04:00
topjohnwu
f5d054b93c Add support for PXA DTBs 2019-10-08 23:49:21 -04:00
topjohnwu
d25ae5e0a9 Add __attribute__((packed)) just in case 2019-10-08 16:55:25 -04:00
topjohnwu
c42a51dcbb Add support to patch DTBH DTBs
Apparently, Qualcomm is not the only on creating weird DTB formats,
Samsung also have their own DTBH format for Exynos platforms.

Close #1902
2019-10-08 16:43:27 -04:00
topjohnwu
da3fd92b31 Prevent unsigned overflow
Close #1898
2019-10-08 15:55:27 -04:00
topjohnwu
4a45ba3c14 Update magisk_files commit hashes 2019-10-08 14:53:04 -04:00
Viktor De Pasquale
4292ddd0ae Added custom install dialogs 2019-10-08 20:29:55 +02:00
Viktor De Pasquale
4a68fd65b6 Updated UI so magisk cannot be updated unless latest manager is installed 2019-10-08 18:51:31 +02:00
Viktor De Pasquale
0e33632e79 Added package name when it differs from the default one 2019-10-08 18:30:23 +02:00
Viktor De Pasquale
a9b20dae33 Fixed showing update information 2019-10-08 18:29:58 +02:00
Madis
dbc8bed234 Estonian update 2019-10-07 23:04:19 -04:00
Gaurav
f8b4190a11 Fix Typos 2019-10-07 23:03:09 -04:00
Mevlüt TOPÇU
479972e3ae Update Turkish language
Hi

Merge please

Thank's
2019-10-07 23:02:29 -04:00
Viktor De Pasquale
3ea28b0afb Fixed permission event not being executed 2019-10-07 22:58:14 -04:00
Viktor De Pasquale
2b3cc28966 Fixed snackbar not showing up for dumping files 2019-10-07 22:58:14 -04:00
Viktor De Pasquale
751642b39a Fixed back button not working on flash screen 2019-10-07 22:58:14 -04:00
topjohnwu
d6c2c821a4 Minor improvements in QCDT logic 2019-10-07 22:57:01 -04:00
Alessandro Astone
dfc65b95f7 qcdt: pad the last dtb too 2019-10-07 22:48:54 -04:00
Alessandro Astone
b45d922463 qcdt: include padding in the table length fields 2019-10-07 22:48:54 -04:00
Viktor De Pasquale
e595937740 Added versions to home screen
To overview (when updatable)
  - It is very hard to spot a difference in versions so versions are now regarded as commit messages (after dash [-]) when applicable
      - This will result in more clear, understandable text
      - Bleeding edge (canary) user would see:

        ffed229 > ffe02ed or 19.4 > ffe02ed

        as opposed to:

        19.4-ffed229 (19404)
        19.5-ffe02ed (19501)
      - Regular beta+ user would see:

        19.4 > 19.5
To bottom of the screen
  - This change is with respect to regular user. They don't care which version they run as long as they know that "up-to-date" is a gold standard
  - It takes tons of real-estate on the screen which takes away the glance-ability from the overview.
2019-10-07 20:09:12 +02:00
Viktor De Pasquale
72eb584e65 Fixed fonts for the thousandth time 2019-10-07 19:23:57 +02:00
topjohnwu
f87ee3fcf9 Refactor boot image unpack/repack code base 2019-10-07 04:35:02 -04:00
topjohnwu
e0927cd763 Add support to patch QCDT
Old Qualcomn devices have their own special QC table of DTB to
store device trees. Since patching fstab is now mandatory on Android 10,
and for older devices all early mount devices have to be included into
the fstab in DTBs, patching QCDT is crucial for rooting Android 10
on legacy devices.

Close #1876 (Thanks for getting me aware of this issue!)
2019-10-07 00:38:02 -04:00
Viktor De Pasquale
8999a57f06 Added in-app settings shortcut from system settings 2019-10-06 12:20:05 +02:00
Viktor De Pasquale
8024089bde Added indication of whether the manager is hidden 2019-10-06 12:06:31 +02:00
Viktor De Pasquale
5e01f785ae Added handling for state with no connection 2019-10-06 12:06:09 +02:00
Viktor De Pasquale
d35d1b8860 Added more styles to be used on top of primary color 2019-10-06 11:14:11 +02:00
Viktor De Pasquale
88027f2151 Fixed fonts 2019-10-05 23:31:05 +02:00
topjohnwu
21099eabfa Small changes in DTB code 2019-10-05 17:24:53 -04:00
Viktor De Pasquale
cd41e7108b Fixed fonts 2019-10-05 23:13:17 +02:00
topjohnwu
abbd2e6b72 Update AS 2019-10-05 17:02:08 -04:00
Viktor De Pasquale
6da566faff Fixed overlay color for home item 2019-10-05 22:59:28 +02:00
Viktor De Pasquale
df7a866617 Fixed widget order
Content mustn't overlay appbar
2019-10-05 22:59:04 +02:00
Viktor De Pasquale
1cc8f13d54 Added section icons 2019-10-05 22:20:57 +02:00
Viktor De Pasquale
086ce63c6c Updated material library 2019-10-05 22:04:34 +02:00
Viktor De Pasquale
f1dcecc6cf Added link opening on homepage 2019-10-05 22:04:03 +02:00
Viktor De Pasquale
fe1ce08a6c Added self-handling event types 2019-10-05 21:53:33 +02:00
Viktor De Pasquale
1d64ddb7f5 Fixed dimensions and padding throughout the homescreen 2019-10-05 12:53:40 +02:00
Viktor De Pasquale
823b121cc7 Added support section content 2019-10-05 12:42:27 +02:00
Viktor De Pasquale
149d35c687 Updated strings 2019-10-05 11:39:33 +02:00
Viktor De Pasquale
3a18e68751 Updated arrangement of manager/magisk sections 2019-10-04 19:57:27 +02:00
Viktor De Pasquale
6afcc83955 Added logic to redesigned home
(partially)
2019-10-04 19:36:26 +02:00
Viktor De Pasquale
277d8773f2 Added automated loading to new compat-based redesign 2019-10-04 19:35:22 +02:00
Viktor De Pasquale
f161cf8b0a Removed no-root state 2019-10-04 18:56:35 +02:00
Viktor De Pasquale
dc62ae95a6 Added icons for navigation 2019-10-04 18:25:06 +02:00
Viktor De Pasquale
f4ecc315d0 Replaced temporary id names 2019-10-04 18:03:06 +02:00
Viktor De Pasquale
cb2a1e57fe Added text switchers for descriptions 2019-10-04 17:56:30 +02:00
Viktor De Pasquale
1396faf433 Added animated icon for magisk (and its uninstall) 2019-10-04 17:12:28 +02:00
Viktor De Pasquale
dc8d2ae683 Added basic navigation 2019-10-03 19:38:57 +02:00
Viktor De Pasquale
191c7c50b6 Added night theme colors 2019-10-03 19:17:11 +02:00
Viktor De Pasquale
c6725b0518 Added icons for magisk/manager 2019-10-03 19:08:35 +02:00
Viktor De Pasquale
4820a6e01c Updated toolbar to look more android-like 2019-10-03 18:41:04 +02:00
Viktor De Pasquale
57a9b5bc0c Added home screen 2019-10-03 17:31:45 +02:00
Viktor De Pasquale
8c224da5d5 Added compat layer for activities and fragments
This change is made so logic is not placed within the "old" base substrate. Changes made in the redesign could potentially affect the already working part which we obviously do not want.
2019-10-03 16:42:47 +02:00
Viktor De Pasquale
14e49f3c80 Added redesign base
... also basic switching to redesign was added, haha
2019-10-02 19:42:38 +02:00
Viktor De Pasquale
cc8f1adca3 Added more styles regarding homescreen 2019-10-02 18:15:16 +02:00
topjohnwu
5b7ddbbb01 Fix status report UI 2019-09-30 15:32:28 -04:00
Viktor De Pasquale
6352fbb3b2 Added additional sorting for installed modules 2019-09-30 14:07:14 -04:00
Viktor De Pasquale
122e2f7a8e Updated styles and simplified dimension usage 2019-09-30 19:37:57 +02:00
Viktor De Pasquale
b4e1585e2b Added custom font 2019-09-30 19:36:51 +02:00
topjohnwu
d3f49334e2 Move function as extension 2019-09-28 12:17:34 -04:00
topjohnwu
c4356171b3 Update dependencies block 2019-09-28 05:01:51 -04:00
topjohnwu
5c5625911d Fix back button behavior 2019-09-28 05:01:25 -04:00
topjohnwu
6a10cc9c55 Remove dependency Dexter 2019-09-28 04:23:21 -04:00
topjohnwu
6b317f918e Rename base class names 2019-09-28 03:50:11 -04:00
topjohnwu
08b528dc4f Reorganize classes
- Move base classes to its own package
- Move most logic out of MagiskActivity to MainActivity
2019-09-28 03:37:24 -04:00
topjohnwu
fc886a5a47 Merge Teanity into sources 2019-09-28 01:56:16 -04:00
topjohnwu
0cb90e2e55 Update BasePreferenceFragment 2019-09-27 19:54:03 -04:00
topjohnwu
64113a69b4 Remove unused warnings 2019-09-26 13:54:40 -04:00
topjohnwu
544bb7459c Don't pass by reference 2019-09-26 03:49:05 -04:00
Viktor De Pasquale
578a50b464 Added hiding actions on notifications typed "Download" 2019-09-26 03:15:46 -04:00
topjohnwu
3d4081d0af Fix patch verity and forceencrypt 2019-09-26 03:14:56 -04:00
topjohnwu
b763b81f56 Use mutex_guard to lock su_info 2019-09-26 01:49:50 -04:00
topjohnwu
947dae4900 Rename classes and small adjustments 2019-09-25 23:55:39 -04:00
Viktor De Pasquale
a5830599c4 Added initial load of styles and attributes
Required for creating basic screens
2019-09-24 20:29:35 +02:00
topjohnwu
debd1d7d54 Update canary channel links 2019-09-24 03:09:02 -04:00
osm0sis
cba0d04000 magiskpolicy: rules: standardize update_engine sepolicy when rooted
The state of ROM A/B OTA addon.d-v2 support is an inconsistent mess currently:
- LineageOS builds userdebug with permissive update_engine domain, OmniROM builds userdebug with a more restricted update_engine domain, and CarbonROM builds user with a hybrid closer to Omni's
- addon.d-v2 scripts cannot function to the full extent they should when there is a more restricted update_engine domain sepolicy in place, which is likely why Lineage made update_engine completely permissive

Evidence for the above:
- many addon.d-v2 scripts only work (or fully work) on Lineage, see below
- Magisk's addon.d-v2 script would work on Lineage without issue, but would work on Carbon and Omni only if further allow rules were added for basic things like "file read" and "dir search" suggesting these ROMs' addon.d-v2 is severely limited
- Omni includes a /system/addon.d/69-gapps.sh script with the ROM itself (despite shipping without GApps), and with Magisk's more permissive sepolicy and no GApps installed it will remove important ROM files during OTA, resulting in a bootloop; the issue with shipping this script was therefore masked by Omni's overly restrictive update_engine sepolicy not allowing the script to function as intended

The solution:
- guarantee a consistent addon.d-v2 experience for users across ROMs when rooted with Magisk by making update_engine permissive as Lineage has
- hopefully ROMs can work together to come up with something standard for unrooted addon.d-v2 function
2019-09-23 07:55:25 -04:00
topjohnwu
695e7e6da0 Create product mirror if /system/product exist 2019-09-23 06:52:24 -04:00
topjohnwu
4cd4bfa1d7 Add ':' to allowed characters for magiskhide process name 2019-09-22 16:17:51 -04:00
topjohnwu
16b400964b Update vars for 2SI 2019-09-22 06:45:23 -04:00
topjohnwu
cf2d02c0dd Don't wipe ramdisk when A-only SAR 2019-09-22 06:17:54 -04:00
topjohnwu
0fcd0de0d1 Fix potential crash when traversing cpio entries 2019-09-22 06:15:19 -04:00
topjohnwu
748a35774f Support patching fstab in ramdisk for A-only 2SI 2019-09-22 05:30:04 -04:00
topjohnwu
a52a3e38ed Change some class names 2019-09-22 05:20:51 -04:00
topjohnwu
ee0cef06a6 Add support for A-only 2SI 2019-09-22 05:15:31 -04:00
topjohnwu
0e5a113a0c Support patching mnt_point in fstab in dtb 2019-09-22 04:17:15 -04:00
topjohnwu
a1ccd44013 Change MagiskBoot patch behavior
Use environment variables to toggle configurations for patching ramdisk
2019-09-21 05:55:23 -04:00
topjohnwu
4d91e50d6d Update dtb patch to not use in-place modification 2019-09-21 05:30:04 -04:00
topjohnwu
120668c7bc Revise dtb commands CLI 2019-09-20 03:53:58 -04:00
topjohnwu
d81ccde569 Pretty print dtb content 2019-09-20 03:05:14 -04:00
topjohnwu
e8581b4adb Fix links in docs 2019-09-19 05:48:21 -04:00
topjohnwu
19906575a3 Update v7.3.4 changelogs 2019-09-19 05:29:45 -04:00
topjohnwu
9329094a4e Update documentations 2019-09-19 05:00:29 -04:00
topjohnwu
b44f5122fd Pass int directly as pointer 2019-09-19 00:13:42 -04:00
topjohnwu
17981730a4 Remove load_persist_props in post-fs-data
Close #1607
2019-09-17 13:50:53 -04:00
topjohnwu
53de6da26c Only print relevant info according to header version 2019-09-17 05:11:09 -04:00
topjohnwu
3e30ccdeee Make parsing behaves according to header
Close #1778. Close #1848
2019-09-17 05:01:04 -04:00
topjohnwu
baaaf7d5de Fully match zygote/usap process names 2019-09-17 01:50:45 -04:00
hoijui
45d8d139a9 Cross-link-ify install instructions 2019-09-17 01:28:41 -04:00
topjohnwu
fe644e10d0 Make sure post-fs-data is first ran
Close #1601
2019-09-17 00:21:07 -04:00
impulsiva
f383d11d10 Update TR strings
Fixed several typos and mistranslated strings.
2019-09-13 16:29:25 -04:00
topjohnwu
ef1b928532 LD_LIBRARY_PATH patch for apex should not propagate
Fix #1832
2019-09-13 15:22:49 -04:00
topjohnwu
6e46d394b1 Fix su_info cache yet again... 2019-09-13 14:05:28 -04:00
topjohnwu
f109038d12 Hardcode shell uid to 2000 2019-09-13 03:14:58 -04:00
topjohnwu
e31e687602 Allow ADB shell to remove modules and reboot 2019-09-13 03:14:21 -04:00
topjohnwu
86bfb22d4c Override module when .replace is found 2019-09-12 16:08:30 -04:00
topjohnwu
3f057367e3 Update dependencies 2019-09-12 12:50:44 -04:00
topjohnwu
3d7ed5820e Update busybox
Close #1520
2019-09-11 23:06:49 -04:00
topjohnwu
0118f2efa7 Merge styles 2019-09-09 19:58:19 -04:00
topjohnwu
15312e4709 Remove unused resources 2019-09-09 17:57:25 -04:00
topjohnwu
bf1568a73a Fix strings 2019-09-09 17:43:16 -04:00
Salim B
13a2520ea5 Fix typo and add link to GH issues 2019-09-09 17:39:15 -04:00
Frieder Bluemle
f53238f206 Update Gradle wrapper to 5.6.2 2019-09-09 17:38:54 -04:00
Rom
9375748d9b Update French translation 2019-09-09 17:38:22 -04:00
Gozzwip
201df54e79 new strings added 2019-09-09 17:37:41 -04:00
vvb2060
0b54fe477b Update zh-rCN translation 2019-09-09 17:37:08 -04:00
Ilya Kushnir
4119e6669e Update RU strings 2019-09-09 17:36:57 -04:00
Taras
d33e5226b3 Update Ukrainian translation 2019-09-09 17:36:39 -04:00
topjohnwu
d73f39c706 Fix manager update after hidden
Fix #1828
2019-09-09 17:24:29 -04:00
topjohnwu
087b451e17 Fix strings 2019-09-08 01:19:33 -04:00
topjohnwu
86481c74ff Allow user to select recovery mode
Close #1674
2019-09-08 00:44:26 -04:00
topjohnwu
5b937fb1fa Random changes 2019-09-05 11:36:48 -04:00
topjohnwu
ff828116bc Only cache magisk zips 2019-09-05 11:26:35 -04:00
topjohnwu
ee39616a8b Update emulator.sh to support all AVD images 2019-09-04 11:12:09 -04:00
topjohnwu
cdb53ca049 Fix su_info cache bug 2019-09-04 11:04:59 -04:00
topjohnwu
8cf475f708 Add scripts to setup Magisk in AVD 2019-09-03 17:06:14 -04:00
topjohnwu
0cb449e1d6 We need to support pre-5.0 platforms 2019-09-03 16:28:27 -04:00
topjohnwu
e6adb7abca Make kotlin version a variable globally 2019-09-03 16:27:57 -04:00
topjohnwu
cfad7dd317 Sanitize magiskhide targets
Fix #1785
2019-09-01 14:16:12 +08:00
topjohnwu
dd35224f92 Minor adjustments to exec_sql 2019-09-01 13:58:50 +08:00
Chris Renshaw
1283590eeb scripts: prepare addon.d for recovery addon.d-v2 support
- naturally there's no `su` in recovery
- major refactor for common actions and simplicity
2019-09-01 02:19:59 +08:00
osm0sis
dca3fe396f scripts: hide expected x86 busybox error on arm
- Magisk Manager installs have busybox in the $PATH before extracting busybox from update-binary so an error from busybox ash (as sh) attempting to parse the x86 busybox like a shell script would be shown:
./bin/busybox: line 1: syntax error: unexpected "("
- this will only occur when ash tries to run a binary it can't handle, so basically only with x86 binary on an arm* device
2019-09-01 02:19:59 +08:00
cristisilaghi
8d87eae11b Update RO 2019-09-01 02:17:13 +08:00
Frieder Bluemle
fd7eaacae0 Update Gradle wrapper to 5.6.1 2019-09-01 01:17:22 +08:00
topjohnwu
fba33cbbe9 Fix strings 2019-09-01 01:15:15 +08:00
Gozzwip
950ffcd790 Translation is done 2019-09-01 01:12:15 +08:00
Gozzwip
c178299013 Translation is done 2019-09-01 01:12:08 +08:00
Rom
5d17c1f588 French translation update 2019-09-01 01:11:54 +08:00
linar10
a75c00d94e Update strings.xml 2019-09-01 01:11:40 +08:00
Albert I
cd19517414 app: l10n: Update Indonesian translations
* Update the wordings
* Delocalize "Core Only" strings
* Add 3 months worth of missing translations

Signed-off-by: Albert I <kras@raphielgang.org>
2019-09-01 01:11:33 +08:00
Gozzwip
155f39aab5 Some changes 2019-09-01 01:11:06 +08:00
Mevlüt TOPÇU
4514d0b467 Update Turkish language
Hi,

Merge please

Thanks.
2019-09-01 01:10:51 +08:00
zertyuiop
6f4a938a31 Added missing strings 2019-09-01 01:10:33 +08:00
VergeDX
1303ea95dd Update & Fix Chinese Translate. 2019-09-01 01:10:19 +08:00
Oliver Cervera
727fe1bd15 Update Italian translation
Added new strings
2019-09-01 01:10:10 +08:00
topjohnwu
64ebc977e9 Small magic mount adjustments 2019-08-31 21:53:47 +08:00
topjohnwu
e89c50d934 Support /system/product wihtout /product
Fix #1676
2019-08-29 22:56:34 +08:00
topjohnwu
c859ddfb8f Upgrade Kotlin 2019-08-27 02:30:10 +08:00
topjohnwu
a6126c5eda Cosmetic changes 2019-08-23 03:05:41 +08:00
topjohnwu
85d9bd9106 Fix compile errors 2019-08-23 00:30:21 +08:00
Viktor De Pasquale
39e9622205 Fixed magisk version
Added refreshing versions before and after the request to remote
2019-08-22 08:03:17 +02:00
topjohnwu
021994c9f3 Clean elf after building shared binaries 2019-08-22 02:51:17 +08:00
topjohnwu
2e7ce2a769 Update gradle files 2019-08-21 10:38:09 +08:00
topjohnwu
84f0ff2fad Fix manager package name database management 2019-08-12 03:31:59 -07:00
topjohnwu
e6561e5f84 Fix XML parsing Kotlin error 2019-08-12 03:14:51 -07:00
topjohnwu
5fa452aa74 Multiple minor changes 2019-08-12 01:54:33 -07:00
topjohnwu
2225ccb146 Flush settings to persistent storage 2019-08-12 00:05:19 -07:00
topjohnwu
5aafc78847 Cleanup const 2019-08-11 23:53:43 -07:00
topjohnwu
0d03833cff Name module zips with version code 2019-08-11 22:46:39 -07:00
topjohnwu
a797d5d396 Update snet extension 2019-08-08 04:18:32 -07:00
topjohnwu
f2494374f8 Eliminate any traces of Java in app 2019-08-08 00:59:23 -07:00
topjohnwu
48395ba860 Remove unused files 2019-08-08 00:29:27 -07:00
topjohnwu
5ba5f5f94e Observe network connnectivity
Observe internet connectivity will ping google.com
2019-08-07 22:26:44 -07:00
topjohnwu
42ce6fd334 Workaround stupid Moshi proguard rules 2019-08-07 22:26:25 -07:00
Viktor De Pasquale
f5c3ee3ae1 Added elements of UI to "hide list" 2019-08-07 03:07:18 -07:00
Viktor De Pasquale
3c7ece1605 Fixed not showing current version
Current version was not displaying under circumstances that involve loss of connection. Versions are displayed whether the device is connected or not.
2019-08-07 03:07:18 -07:00
Viktor De Pasquale
870efc49ea Fixed using mapping function incorrectly 2019-08-07 03:07:18 -07:00
Viktor De Pasquale
085ede6d93 Added simple ui blocks for whenever connection drops out 2019-08-07 03:07:18 -07:00
Viktor De Pasquale
4ef19d17da Added a flag for connection status
Reactively updated flag which only checks whether the "data" / "wifi" / "ethernet" is plugged in or enabled. If the user connects to the wifi but has no actual connection, the app will never know.
Please refrain from using other access methods (like pinging a host), it can get picked up by a VPN or other methods and possibly expose MM.
2019-08-07 03:07:18 -07:00
topjohnwu
223913c30a Remove unnecessary App usage 2019-08-05 00:21:38 -07:00
topjohnwu
010e4de4e1 Introduce DynamicClassLoader 2019-08-04 23:49:09 -07:00
topjohnwu
41134466ed Upgrade dependencies 2019-08-04 18:33:20 -07:00
topjohnwu
8f07747452 Remove net module 2019-08-04 18:33:20 -07:00
topjohnwu
eb5ce5be1e Fix saving logs
Fix #1722
2019-08-04 14:17:01 -07:00
topjohnwu
71d855e836 Cleanup more code 2019-08-04 13:47:14 -07:00
topjohnwu
33b7ab593c Migrate PatchAPK to Kotlin 2019-08-04 13:00:27 -07:00
topjohnwu
8706d834b4 Update Android Studio 2019-08-02 21:26:00 -07:00
topjohnwu
7cfab33ebb Make sure DownloadService always start with app context 2019-08-02 01:21:22 -07:00
topjohnwu
1ababc8c7f RepoDB does not need to run on main thread 2019-08-02 01:20:16 -07:00
topjohnwu
1f75e63c37 Fix crashes in MarkdownWindow
Fix #1628
2019-08-02 01:16:04 -07:00
topjohnwu
cb3f9b9740 More tweaking to Rx pipeline 2019-08-01 23:08:58 -07:00
topjohnwu
9784353223 Fix ActivityTracker
Koin does not support nullable types
2019-07-29 04:18:05 -07:00
topjohnwu
7d93ca5c73 Modernize MagiskInstaller 2019-07-29 04:05:54 -07:00
topjohnwu
ac20063e86 Disable cache for Magisk Manager 2019-07-29 03:56:35 -07:00
topjohnwu
debaec32af Remove old download progress update system 2019-07-29 00:42:53 -07:00
topjohnwu
0e9b71e7a9 Show notification on error 2019-07-29 00:37:01 -07:00
topjohnwu
85f5ff3c14 Download Magisk Manager via new service 2019-07-29 00:26:18 -07:00
Frieder Bluemle
3d81f167ea Update Gradle wrapper to 5.5.1 2019-07-28 15:32:33 -07:00
Taras
fb70a2e52d Update Ukrainian translation 2019-07-28 15:32:01 -07:00
JoanVC100
460e85a1b5 New lines added and fixs 2019-07-28 15:31:49 -07:00
cheese1
539b64bd57 update german language-file 2019-07-28 15:31:24 -07:00
linar10
90e38a06a2 Update strings.xml 2019-07-28 15:31:03 -07:00
zertyuiop
09ab910630 Added missing strings 2019-07-28 15:30:54 -07:00
topjohnwu
c15f80b33f Improve Rx pipeline 2019-07-28 14:49:06 -07:00
topjohnwu
b2e6ba3c4a Move no thanks from dialogs 2019-07-28 03:54:46 -07:00
topjohnwu
b16f696b0e Cleanups 2019-07-28 03:47:07 -07:00
topjohnwu
9adfb382e8 Only launch FlashActivity if app is foreground 2019-07-28 03:38:27 -07:00
topjohnwu
44368383f4 Fix fetching repo ordering 2019-07-28 02:21:55 -07:00
topjohnwu
d1ff7e0ffe Move extensions to its own package 2019-07-28 02:10:22 -07:00
topjohnwu
42e7db8d13 Modernize Repo class for Magisk modules
- Use Kotlin
- Use Room database
- Use retrofit for networking
- Use RxJava pipeline for repo updating
2019-07-28 01:54:34 -07:00
topjohnwu
0c17ea5755 Migrate Magisk Modules to Kotlin 2019-07-27 15:46:44 -07:00
topjohnwu
cdaff5b39c Update module download pipeline 2019-07-26 02:26:02 -07:00
topjohnwu
2b1b970e78 Update dependencies 2019-07-26 02:00:42 -07:00
topjohnwu
0aebc0a8e3 Use new service to download uninstall.zip 2019-07-25 03:10:24 -07:00
topjohnwu
c3a89f589e Download to proper filename 2019-07-25 01:54:42 -07:00
topjohnwu
971cd73fb3 Dismiss notification on error 2019-07-25 01:37:47 -07:00
topjohnwu
1947860d61 Dismiss notification after flashing 2019-07-25 01:05:06 -07:00
topjohnwu
55aaa421e8 Directly download to target location 2019-07-23 01:31:59 -07:00
topjohnwu
a8932706d8 Consolidate Magisk download subject 2019-07-23 00:55:12 -07:00
topjohnwu
a97972aac0 Update notification once per second 2019-07-23 00:33:28 -07:00
topjohnwu
094c3d559a Minor fixes and cleanups 2019-07-22 01:49:21 -07:00
topjohnwu
6fb032b3c2 Clean ups 2019-07-20 22:37:34 -07:00
topjohnwu
8ca188f4d4 Stream and process module zips 2019-07-20 21:04:06 -07:00
topjohnwu
746a1d8d59 Directly download to magisk.zip for flashing 2019-07-20 14:57:03 -07:00
topjohnwu
63c5e00d86 Update Android Studio 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
9d2e5d6665 Updated design for custom channel field so it matches the other dialog 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
f6045bf8b5 Added custom dialog for download location only 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
e83f40d5c5 Added actions for opening files in the file browser
No icons are added at this time, so crashes might occur
2019-07-20 14:57:03 -07:00
Viktor De Pasquale
e5118418b2 Added option to have custom download location
The location is automatically added to list of supported paths for caching
2019-07-20 14:57:03 -07:00
Viktor De Pasquale
7cd814d917 Updated service to use extra transformer so the service itself is not plagued by unnecessary code 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
78282c1a49 Removed unused entry 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
fd4214ccf3 Fixed minor bugs regarding notification cancellation 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
0785945635 Added appending installers to modules 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
967bdeae7b Updated service architecture and extracted useful tools to separate class 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
452db51669 Updated flash location so it's one layer deeper preventing accidental cache deletion 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
5875ced367 Fixed launching activities on newer systems 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
fbac6bcfd0 Fixed substrate handling multiple downloads at once 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
0dcd3ece9d Updated downloading modules 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
224fff89e3 Updated object usage for module subjects 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
22e73644f9 Added option to run service in foreground right away 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
6a0f6ab319 Updated magisk installer so it uses predownloaded file 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
88a394836f Replaced all install methods with the download service 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
f822c1c2e4 Added default to flash configuration 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
1d16d980b3 Added second slot flashing capability 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
501b18f986 Added default value to magisk subject 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
21ed759e53 Removed duplicate helper 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
8d50dfd93c Fixed overwriting file in download mode
Added prevention of copying itself to itself
2019-07-20 14:57:03 -07:00
Viktor De Pasquale
51e40dd98c Fixed crashes caused by file exposure beyond app bounds 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
b2048379af Fixed uris so in case there's no additional the data one (with zips) is selected instead 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
011539f6f1 Added permission requirements for using service 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
5457c3803f Added remaining methods of installation/flashing/uninstall to service
Updated parameters of patching step and fixed new ordered flashing format
2019-07-20 14:57:03 -07:00
Viktor De Pasquale
b3d777bb6c Updated configuration to hold data when necessary 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
12e00c3054 Updated method naming scheme
Added new configurations
Added flashing methods and annotated viewModel's uri as deprecated in function
2019-07-20 14:57:03 -07:00
Viktor De Pasquale
40b683111c Added an option to disable the new caching mechanism completely 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
9542ca773f Added new CompoundDownloadService which will encapsulate all downloads and should manage post-download events as well
As of now it's still in a development stage and isn't connected to anything
2019-07-20 14:57:03 -07:00
Viktor De Pasquale
8af832a496 Added several calls to FlashActivity so it manages its launch parameters by itself
Its reach will be deepened further in the future commits
2019-07-20 14:57:03 -07:00
Viktor De Pasquale
6836130fda Added overloaded method call for progress notification so it accepts foreign context 2019-07-20 14:57:03 -07:00
Viktor De Pasquale
724893879f Added option to intercept progress while copying files 2019-07-20 14:57:03 -07:00
topjohnwu
736729f5ef Maintain a list of pre-init mounts
Keep track of everything to unmount
2019-07-16 23:54:52 -07:00
topjohnwu
aa47966347 Fix raw_data move constructor 2019-07-16 23:30:54 -07:00
Gozzwip
d64d12afe8 Some fixes 2019-07-16 01:20:10 -07:00
topjohnwu
1f8df419c4 Extract x86 busybox first
Fix #1600
2019-07-16 01:16:29 -07:00
topjohnwu
7ba8202af5 Introduce new root overlay system 2019-07-16 01:08:28 -07:00
topjohnwu
d7b691cf59 Move libutil internal headers out of include path 2019-07-14 23:55:52 -07:00
osm0sis
7058d5e4cd magiskpolicy: rules: fix writing to loop devices using upstream sepolicy 2019-07-14 22:09:26 -07:00
topjohnwu
52fd508fea Do not use std::random_device
Directly read from urandom instead of using std::random_device.
libc++ will use iostream under-the-hood, which brings significant
binary size increase that is not welcomed, especially in magiskinit.
2019-07-14 21:56:21 -07:00
topjohnwu
41045b62dc Introduce more randomness
- Use C++ random generator instead of old and broken rand()
- Randomize string length to piss off stupid detectors
2019-07-14 17:42:49 -07:00
Viktor De Pasquale
188ea2644a Updated downloading magisk to pull the zip from cache if eligible 2019-07-08 11:40:02 -07:00
topjohnwu
4c8f357978 Update to support updated FrankeNDK 2019-07-07 17:38:57 -07:00
Marius
4bb2fd6ba6 Fix typos in german translation 2019-07-07 12:40:20 -07:00
osm0sis
33c9f74508 magiskpolicy: rules: fix rootfs operations with SAR Magisk
- while many newer devices cannot allow / (system partition) to be mounted rw due to compressed fs (e.g. erofs) or logical partitions, it should remain possible to alter rootfs files/directories on those that previously allowed it
2019-07-07 12:33:20 -07:00
osm0sis
f53fe67372 BootSigner: support setting name with no cert/key pair supplied 2019-07-07 12:33:02 -07:00
topjohnwu
51ff724691 Unblock all signals in root shell process
Fix #1563
2019-07-07 12:30:57 -07:00
topjohnwu
291bf93f9d Proper timing 2019-07-07 12:20:47 -07:00
topjohnwu
5fcd629f16 Rearrange su daemon routine 2019-07-07 12:20:19 -07:00
topjohnwu
ab90901793 Use C++ smart pointer for caching su_info 2019-07-07 00:31:49 -07:00
topjohnwu
4f206fd918 Fix compile errors 2019-07-06 23:04:24 -07:00
topjohnwu
7233285437 Use relative symbolic links 2019-07-04 17:58:46 -07:00
John Wu
8e348a11c2 Support non standard image headers
Some Samsung device uses the header version field as extra section size
2019-07-04 11:09:45 -07:00
osm0sis
085ea6d0a1 SignBoot: use verity keys not testkey to correctly follow AOSP 2019-07-04 11:09:45 -07:00
osm0sis
aaf88b1895 BootSigner: add ability to change target name
- supports signing /recovery images
- add as final argument and default to /boot if not supplied so installer scripts remain the same
2019-07-04 11:09:45 -07:00
osm0sis
4f4a9412a3 SignBoot: updates from AOSP for boot_img_hdr_v1 and v2
"Allow recovery-dtbo in recovery.img to be signed" by Hridya Valsaraju:
9bb9f8f857

"boot_signer should support boot header version 2" by Hridya Valsaraju
590e58454d
2019-07-04 11:09:45 -07:00
topjohnwu
a92e039363 Split util headers 2019-07-01 22:58:19 -07:00
topjohnwu
33aa4ca4b7 Move libmincrypt into separate repo 2019-06-30 19:53:03 -07:00
topjohnwu
05658cafc7 Fix typo causing sbin clone failure 2019-06-30 19:24:14 -07:00
topjohnwu
ff3710de66 Minor code changes across all sources 2019-06-30 19:09:31 -07:00
topjohnwu
db8dd9f186 Init code rearrangement 2019-06-30 11:39:13 -07:00
topjohnwu
e8b73ba6d1 Add separate product partition support 2019-06-29 14:19:10 -07:00
topjohnwu
f1112fdf37 Logical Resizable Android Partitions support
The way how logical partition, or "Logical Resizable Android Partitions"
as they say in AOSP source code, is setup makes it impossible to early
mount the partitions from the shared super partition with just
a few lines of code; in fact, AOSP has a whole "fs_mgr" folder which
consist of multiple complex libraries, with 15K lines of code just
to deal with the device mapper shenanigans.

In order to keep the already overly complicated MagiskInit more
managable, I chose NOT to go the route of including fs_mgr directly
into MagiskInit. Luckily, starting from Android Q, Google decided to
split init startup into 3 stages, with the first stage doing _only_
early mount. This is great news, because we can simply let the stock
init do its own thing for us, and we intercept the bootup sequence.

So the workflow can be visualized roughly below:

Magisk First Stage --> First Stage Mount --> Magisk Second Stage --+
   (MagiskInit)         (Original Init)         (MagiskInit)       +
                                                                   +
                                                                   +
     ...Rest of the boot... <-- Second Stage <-- Selinux Setup  <--+
      (__________________ Original Init ____________________)

The catch here is that after doing all the first stage mounting, /init
will pivot /system as root directory (/), leaving us impossible to
regain control after we hand it over. So the solution here is to patch
fstab in /first_stage_ramdisk on-the-fly to redirect /system to
/system_root, making the original init do all the hard work for
us and mount required early mount partitions, but skips the step of
switching root directory. It will also conveniently hand over execution
back to MagiskInit, which we will reuse the routine for patching
root directory in normal system-as-root situations.
2019-06-29 01:25:54 -07:00
osm0sis
a48c4f9e05 magiskboot: don't clobber /overlay with cpio restore anymore
- Magisk "dirty" flashes would remove the /overlay directory which might have been put there by a custom kernel or other mod
- this is a leftover from when Magisk itself used /overlay for placing init.magisk.rc, so just remove this file specifically and leave the rest intact
2019-06-27 18:59:54 -04:00
Rom
19a521d2e9 French translation update 2019-06-27 18:59:29 -04:00
cristisilaghi
dd6e55ac31 [ro] Add translators 2019-06-27 04:10:51 -04:00
osm0sis
b1e63f0f14 Manager: fix ModulesFragment reboot menu
- correct 'booloader' typo breaking bootloader entry
- remove extra bootloader entry Shell.su line which is unnecessary since it's covered by reboot()
- revert to using `reboot recovery` for recovery entry since `svc power reboot recovery` triggers a very disconcerting "Factory data reset" reboot dialog on many devices
- add Reboot to EDL mode option for good measure
2019-06-27 04:09:41 -04:00
topjohnwu
b0e49a4cc8 Kill blastula pool when magiskhide init 2019-06-27 00:49:27 -07:00
topjohnwu
1e94517a72 MagiskHide is coming back strong 2019-06-27 00:28:34 -07:00
topjohnwu
98f60216ac Temporary disable MagiskHide by default
Latest Android Q beta does not like when zygote is ptraced on
boot. Disable it for now until further investigation.
2019-06-25 23:32:07 -07:00
topjohnwu
e29b712108 Start Magisk in SAR 2019-06-25 23:31:59 -07:00
topjohnwu
a462435f2f Load custom sepolicy 2019-06-25 21:34:02 -07:00
topjohnwu
911b8273fe Fix typo in sbin clone 2019-06-25 03:35:25 -07:00
topjohnwu
09935e591a Proper SARInit test 2019-06-25 03:34:54 -07:00
topjohnwu
4a212dba35 Early mount partitions in SAR 2019-06-25 02:47:16 -07:00
topjohnwu
aac9e85e04 More Q cleanup 2019-06-25 02:38:34 -07:00
topjohnwu
bb67a837d3 Adjust class structures 2019-06-24 01:50:47 -07:00
topjohnwu
6cde695194 Remove Q dirty hacks in SARCompat 2019-06-24 01:31:42 -07:00
topjohnwu
a1a1ac0bbb Add sbin overlay to system-as-root 2019-06-24 01:21:33 -07:00
topjohnwu
9ec8bc2166 Boot MagiskInit as actual system-as-root
WIP, no customization. DO NOT USE YET!
2019-06-23 15:14:47 -07:00
topjohnwu
28cd6a75e7 Add missing functions in bionic 2019-06-23 14:54:48 -07:00
topjohnwu
4cc7aced15 Add new util function 2019-06-23 03:53:41 -07:00
topjohnwu
1058aeb04f Label current SAR impl as compat
The current system-as-root magiskinit implementation (converting
root directory in system partition to legacy rootfs setup) is now
considered as backwards compatible only.

The new implementation that is hide and Android Q friendly is coming soon.
2019-06-22 03:18:45 -07:00
topjohnwu
cfec0db947 Delay mounting sbin overlay 2019-06-22 03:14:33 -07:00
topjohnwu
120bd6cd68 v7.3.2 Changelog 2019-06-21 01:12:50 -07:00
JoanVC100
9aef06d1b8 Fix traductors 2019-06-21 04:00:54 -04:00
topjohnwu
e6e9dd751c Upgrade Kotlin 2019-06-21 00:53:40 -07:00
Viktor De Pasquale
5dd677756f Fixed multiple fetch tasks running at once
Disposing wouldn't help since the shell doesn't appear to handle concurrency well
2019-06-21 00:36:37 -07:00
Viktor De Pasquale
b77c590910 Fixed the searchView being collapsed after searching through it
Now they have their state synced with viewModel to allow continuity
2019-06-21 00:36:37 -07:00
Viktor De Pasquale
7e5f2822ae Fix superuser fragment crashes
Fix superuser screen encountering inconsistencies when refreshing the data rapidly
2019-06-21 00:36:01 -07:00
topjohnwu
12bbc7fd6b Update v7.3.1 changelog 2019-06-17 22:15:38 -07:00
topjohnwu
bf9ac8252b Cleanup UpdateInfo 2019-06-16 16:47:30 -07:00
topjohnwu
4a3f5dc619 Cleanups 2019-06-16 14:35:51 -07:00
Viktor De Pasquale
ca156befbd Fixed mapping generic pairs to policy crashing when no policy is found
The policy (app) is now deleted when found invalid (uninstalled)
2019-06-16 16:50:08 -04:00
Viktor De Pasquale
4db41e2ac4 Added attempted fix for parsing data off default thread 2019-06-16 16:50:08 -04:00
Viktor De Pasquale
982a43fce1 Moved diff computation of policy list to the background thread 2019-06-16 16:50:08 -04:00
Viktor De Pasquale
dd76a74e1c Fixed fast scroll button crashing while scrolling to undefined position 2019-06-16 16:50:08 -04:00
Viktor De Pasquale
70cb52b2c7 Fixed fast scroll button being visible when log is empty 2019-06-16 16:50:08 -04:00
topjohnwu
5c7f69acaa Separate SAR and legacy implementation 2019-06-16 12:45:32 -07:00
topjohnwu
f1d9015e5f Move load kernel info out of class 2019-06-15 22:25:09 -07:00
topjohnwu
e8d900c58e Fix typo 2019-06-15 18:12:12 -07:00
topjohnwu
a6241ae912 Fix magiskboot unpack option parsing 2019-06-15 16:15:12 -07:00
topjohnwu
4a697ca2ec Add 7.3.0 changelog 2019-06-14 22:39:31 -07:00
topjohnwu
58bec7f2c9 Update dependencies 2019-06-14 22:39:31 -07:00
Wenlin Shen
213f84985c Update Chinese (Traditional) translate
Update wordings to improve readability.
2019-06-13 21:33:24 -07:00
Viktor De Pasquale
074b1f8c61 Added one-click scroll to the bottom 2019-06-12 16:08:02 +02:00
topjohnwu
326eee8c83 Migrate a lot of classes to Kotlin 2019-06-12 03:29:38 -07:00
topjohnwu
00bff4912e Use svc for reboot if feasible
Close #1488
2019-06-12 00:55:21 -07:00
Viktor De Pasquale
0ce1720516 Fixed magisk log screen lines having multiple lines 2019-06-11 21:52:03 -07:00
osm0sis
ee407472cf magiskboot: allow forcing no recompression on ramdisk.cpio
- when input image had a compressed ramdisk magiskboot had no way to force the repack with the uncompressed ramdisk.cpio since it does not formally recognize cpio as its own format, so add a switch to support forcing repacking to any possible ramdisk format regardless of input image
2019-06-10 21:57:39 -07:00
osm0sis
f341f3b2dd magiskboot: accept forcing recognized but unsupported format compression
- when input image had a different supported format (e.g. gzip) magiskboot would not accept a manually compressed ramdisk or kernel in an unsupported format (e.g. lzop) despite being able to recognize it, so instead would double compress using whatever the input format was, breaking the image with, in effect, a ramdisk.cpio.lzo.gz
2019-06-10 21:56:51 -07:00
Ian Macdonald
8513946e09 'magiskboot hexpatch' will exit with status 1 when nothing patched. 2019-06-10 21:41:40 -07:00
nonnymoose
8ebd9c8927 Use original file type when creating device nodes 2019-06-10 21:41:17 -07:00
topjohnwu
1d54c5144e Fix background update checks 2019-06-10 21:25:42 -07:00
topjohnwu
e40d4318fa Let Kotlin target Java 8 2019-06-10 21:22:07 -07:00
topjohnwu
7756e10779 Rewrite configs with Kotlin delagate properties 2019-06-10 04:37:56 -07:00
topjohnwu
3e58d502d0 Update SettingsFragment to Kotlin 2019-06-09 03:04:37 -07:00
topjohnwu
1c8846dc57 Make PreferenceModel an interface 2019-06-08 16:30:12 -07:00
topjohnwu
2f320c7239 Update ClassMap 2019-06-08 15:34:15 -07:00
topjohnwu
e799918ab6 Update update check service 2019-06-08 15:28:59 -07:00
topjohnwu
86c4928e0f Fix locale settings
AppCompatActivity changed its impl again...
2019-06-08 02:11:10 -07:00
topjohnwu
0293eb5c51 Never refetch magisk version dynamically 2019-06-08 01:44:02 -07:00
topjohnwu
1ee75b6aa6 Download snet package without legacy impl 2019-06-08 01:39:22 -07:00
topjohnwu
4b30b224b5 Remove separate constant class 2019-06-08 00:41:03 -07:00
topjohnwu
16b232d2a3 Enable okhttp logging in debug only 2019-06-07 02:03:17 -07:00
topjohnwu
3f3b1f5b1d Sort policy with app name 2019-06-07 01:24:54 -07:00
topjohnwu
cec017b7bf More MagidkDB fixes 2019-06-07 01:05:54 -07:00
topjohnwu
3123cc1059 Update AndroidX dependencies 2019-06-07 00:27:07 -07:00
topjohnwu
caa9df86bc Switch to R8 friendly room-runtime 2019-06-07 00:17:00 -07:00
topjohnwu
f417389a7a Fix magisk database code in app 2019-06-06 00:39:24 -07:00
topjohnwu
662a5c8ea6 Upgrade Retrofit 2.6.0 2019-06-05 23:41:51 -07:00
topjohnwu
7edfbfb764 Upgrade SDK 2019-06-05 21:33:09 -07:00
topjohnwu
c1602d2554 Support execute commands in magiskhide env
Credits to #1454
2019-06-04 22:27:19 -07:00
topjohnwu
9f8d4e1022 Properly isolate mount namespace 2019-06-04 21:21:27 -07:00
Viktor De Pasquale
d1dfda405f Removed Kotpref and replaced it with PreferenceModel 2019-06-04 00:59:57 -07:00
Emanuel Hajnzic
28efded624 Update and cleanup for german strings.xml 2019-06-03 23:37:57 -07:00
topjohnwu
06c86ee267 Remove samsung.md 2019-06-03 23:37:16 -07:00
Ian Macdonald
5892780871 Added warnings about flashing only an AP file and using MTP.
MTP is now known to sometimes corrupt the AP file on transfer to the PC,
so we should warn users to prefer `adb`.

Furthermore, quite a few users are reporting a shrunken `/data`
file-system after flashing with Odin. This has been traced to the
flashing of only an AP file, which causes some versions of Odin to
shrink `/data`. The phenomenon is reproducable.
2019-06-03 23:35:33 -07:00
topjohnwu
4fcdcd9a8a Detect UID from data directories 2019-06-03 23:32:49 -07:00
topjohnwu
80d834fb55 Use kotshi instead of moshi-kotlin-codegen 2019-06-01 13:18:11 -07:00
topjohnwu
4122ebe18f Remove unused Room database code 2019-06-01 02:20:40 -07:00
topjohnwu
7d87777bf8 Improve proguard rules 2019-06-01 01:13:29 -07:00
topjohnwu
4a73d634e0 Tidy things up 2019-05-31 21:46:59 -07:00
topjohnwu
373dc10a40 Use moshi code-gen 2019-05-31 21:46:42 -07:00
Ian Macdonald
ed43ec8ea2 Populate Config variables based on update channel parameters.
With thanks to @diareuse.
2019-05-31 20:48:21 -07:00
topjohnwu
7918fc3528 Support building individual applets 2019-05-30 21:17:58 -07:00
osm0sis
bf58205b0a magiskboot: be clear lzop is not a supported compression format
- keep detection and always display detected format type to fascilitate external support
2019-05-30 20:31:24 -07:00
topjohnwu
c0d1ce96d1 Cleanup 2019-05-30 01:05:48 -07:00
topjohnwu
b31d3802eb Properly force refresh 2019-05-29 23:45:18 -07:00
Viktor De Pasquale
be1228c3b4 Reverted removing UpdateRepos temporarily 2019-05-29 18:40:16 +02:00
Viktor De Pasquale
15c94c6b34 Merge remote-tracking branch 'john/master' into development
# Conflicts:
#	build.gradle
2019-05-29 18:28:50 +02:00
Viktor De Pasquale
202d23426a Fixed update cards having their text resized 2019-05-29 16:35:02 +02:00
Viktor De Pasquale
fc26de48b2 Removed hiding advanced settings when no root is detected
This change was made in order to allow proper adjustment of boot image
2019-05-29 16:28:33 +02:00
vvb2060
76c88913f9 Ensure Magisk environment normal 2019-05-27 16:29:54 -07:00
topjohnwu
a3a1aed723 Don't check zygote in busy loop 2019-05-27 16:27:19 -07:00
topjohnwu
81aa56f60f Support EROFS system-as-root devices
Close #1381
2019-05-27 15:19:28 -07:00
Vladimír Kubala
73bb850209 Update Slovak translation 2019-05-27 15:04:30 -07:00
Gozzwip
8dfec12330 Some fixes
There is a missing string which I couldn't find in this file but in app it appears when you install a module, please check.
2019-05-27 15:04:12 -07:00
topjohnwu
ae24397793 Try to wait if block device is not ready
Close #1459
2019-05-27 15:01:49 -07:00
topjohnwu
3b0f888407 Minor update for parsing uevent 2019-05-27 02:55:46 -07:00
topjohnwu
845d1e02b0 Separate magiskinit components 2019-05-27 00:29:43 -07:00
topjohnwu
5d357bc41f Remove unused function 2019-05-26 22:01:42 -07:00
topjohnwu
6a54672b13 Cleanup unnecessary functions 2019-05-26 03:05:23 -07:00
topjohnwu
3d9a15df44 Remove unnecessary '--' in magiskhide 2019-05-26 02:59:38 -07:00
topjohnwu
449c7fda2f Enable proc_monitor test in debug mode only 2019-05-26 02:53:28 -07:00
topjohnwu
8b7b05da68 Separate hide policies 2019-05-26 02:47:57 -07:00
topjohnwu
92400ebcab Process monitor minor tweaks 2019-05-26 02:35:12 -07:00
topjohnwu
23d3e56967 Add new util function 2019-05-25 21:42:51 -07:00
topjohnwu
6785dc4967 Disable verbose ptrace logging 2019-05-25 21:42:24 -07:00
topjohnwu
dad20f6a2d Update zygote namespace
Close #1492
2019-05-25 18:30:43 -07:00
topjohnwu
bb15671046 Sleep when there is nothing to wait 2019-05-25 18:17:25 -07:00
topjohnwu
21984fac8b Add API for running independent proc_monitor test 2019-05-25 16:08:53 -07:00
Viktor De Pasquale
f392afe87f Added error message in case Markdown window fails to load 2019-05-25 19:20:36 +02:00
Viktor De Pasquale
6a243ec7bc Fixed inconsistent displaying of repos and improved their sorting 2019-05-25 18:09:45 +02:00
Viktor De Pasquale
8cd3b603df Fixed cached repos not being ordered by settings 2019-05-25 18:03:32 +02:00
Viktor De Pasquale
6e1aefe6d8 Added feature that prevents repositories from being downloaded every single time that user requests to show Module/Download fragment unless requested by user 2019-05-25 16:42:34 +02:00
Viktor De Pasquale
1c90b6eca3 Fixed notification popping up every time update is scheduled 2019-05-25 16:33:55 +02:00
Viktor De Pasquale
c33cf9f878 Fixed stable channel asking for custom URL when previously selected 2019-05-25 16:15:08 +02:00
Viktor De Pasquale
27cb40eec9 Removed test options from proguard 2019-05-24 16:02:47 +02:00
Viktor De Pasquale
c06081b75d Added more proguard restrictions and rules for kotlin and moshi 2019-05-24 15:54:08 +02:00
Viktor De Pasquale
a7eec2f0a0 Fixed initial crashes occurring due to improperly obfuscated constructors and inner fields 2019-05-24 15:53:08 +02:00
Viktor De Pasquale
4fd0fe3194 Fixed repo not being correctly marked as jsonclass hence it crashed when fetching obfuscated 2019-05-24 15:51:18 +02:00
Viktor De Pasquale
cc74593ddd Removed useless constructor parameter from home vm 2019-05-24 15:50:20 +02:00
Viktor De Pasquale
fdb7c5dba1 Added Timber as marked for stripping 2019-05-24 15:49:11 +02:00
Viktor De Pasquale
77470c7cfa Updated koin 2019-05-24 12:28:57 +02:00
Viktor De Pasquale
f0a734fdab Fixed clearing cache crashing due to operations on main thread 2019-05-24 12:28:40 +02:00
topjohnwu
75405b2b25 Upgrade AS 2019-05-24 02:48:10 -07:00
osm0sis
90ed4b3c49 magiskboot: clean up remaining unneeded ELF detection bits
- default for no format match is UNSUPP_RET (unsupported) so there is no needed to explicitly detect ELF still
2019-05-24 02:46:35 -07:00
Chris Renshaw
290a17a764 magiskboot: fix bootimg hdr v2 checksum generation
- new AOSP dtb section was missing from HASH_update
2019-05-24 02:46:35 -07:00
Viktor De Pasquale
aaabd836e4 Merge remote-tracking branch 'john/master' into development 2019-05-23 20:02:29 +02:00
Viktor De Pasquale
076e5cea3b Fixed selection not persisting throughout root requests 2019-05-23 20:01:47 +02:00
Viktor De Pasquale
8515971ccf Fixed deleting "one-time" root requests whilst removing outdated 2019-05-23 19:18:16 +02:00
Viktor De Pasquale
d86fb033ea Fixed conditions being inaccurately represented 2019-05-23 19:17:41 +02:00
Viktor De Pasquale
99d7d8ddbc Fixed background being transparent for su request 2019-05-23 18:32:51 +02:00
Viktor De Pasquale
df78fd2d41 Fixed setting custom channels and switching between official ones being broken 2019-05-23 18:11:23 +02:00
Viktor De Pasquale
dabe6267b9 Fixed error that prevented flashing 2019-05-23 16:50:31 +02:00
Viktor De Pasquale
0119ebddbe Added back clearing repository cache 2019-05-23 15:28:05 +02:00
topjohnwu
3216ef9f47 Upgrade AS 2019-05-23 01:08:07 -07:00
osm0sis
b79d1bcded magiskboot: clean up remaining unneeded ELF detection bits
- default for no format match is UNSUPP_RET (unsupported) so there is no needed to explicitly detect ELF still
2019-05-21 02:49:19 -07:00
Chris Renshaw
17e234f9d5 magiskboot: fix bootimg hdr v2 checksum generation
- new AOSP dtb section was missing from HASH_update
2019-05-21 02:49:19 -07:00
Viktor De Pasquale
ea1f75f80e Merge remote-tracking branch 'john/master' into development 2019-05-20 15:10:54 +02:00
topjohnwu
8c40db5730 Don't build snet in all 2019-05-20 01:57:05 -07:00
topjohnwu
6fe03d2795 Fix stub strings 2019-05-20 01:33:08 -07:00
topjohnwu
c595a87ccf Update Magisk Manager changelog 2019-05-20 01:05:27 -07:00
topjohnwu
fac07c3913 Update R8 version 2019-05-19 17:39:19 -07:00
topjohnwu
c63fdbbc6b Add traditional Chinese translations 2019-05-19 17:39:05 -07:00
osm0sis
2ff5d9606b magiskboot: add support for remaining Nook HD pre-image loaders 2019-05-19 17:38:41 -07:00
zertyuiop
ed43452c1a Added missing strings 2019-05-19 13:50:08 -07:00
Oliver Cervera
8f28d4028f Update Italian structure 2019-05-19 13:49:51 -07:00
Cristian Silaghi
b54543b18c Update RO language 2019-05-19 13:49:25 -07:00
topjohnwu
966d6593ca Fix strings 2019-05-13 23:21:01 -07:00
JoanVC100
ad95b1c9d1 Addition, reorganisation and fixing Catalan strings 2019-05-13 23:13:48 -07:00
Ingan121
3bfa38c60a Update strings.xml 2019-05-13 23:13:34 -07:00
topjohnwu
0bdbcad8be Don't specify Provider 2019-05-13 22:39:28 -07:00
Viktor De Pasquale
80855e89ec Merge remote-tracking branch 'john/master' into development
# Conflicts:
#	app/build.gradle
#	app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt
2019-05-13 16:50:08 +02:00
Viktor De Pasquale
0850401dc4 Fixed crash where new application asks for root access 2019-05-13 15:56:27 +02:00
Viktor De Pasquale
337fda2023 Removed unnecessary classes 2019-05-13 15:41:46 +02:00
Viktor De Pasquale
64f238191e Converted constants to kotlin 2019-05-13 15:39:33 +02:00
Viktor De Pasquale
eb169cb133 Converted classmap to kotlin 2019-05-13 15:34:53 +02:00
topjohnwu
80cd85b061 Try to use broadcast for su logging and notify
In commit 8d4c407, native Magisk always launches an activity for
communicating with Magisk Manager. While this works extremely well,
since it also workaround stupid OEMs that blocks broadcasts, it has a
problem: launching an activity will claim the focus of the device,
which could be super annoying in some circumstances.

This commit adds a new feature to run a broadcast test on boot complete.
If Magisk Manager successfully receives the broadcast, it will toggle
a setting in magiskd so all future su loggings and notifies will always
use broadcasts instead of launching activities.

Fix #1412
2019-05-13 02:01:10 -07:00
topjohnwu
89275270f3 Fix code to install GMS_Conscrypt 2019-05-12 16:19:27 -07:00
topjohnwu
e7339ba619 We don't need BouncyCastle provider on Android 2019-05-12 16:06:22 -07:00
topjohnwu
d9ad7d522c Update dependencies 2019-05-12 13:42:53 -07:00
Viktor De Pasquale
92789c3113 Added caching repositories to device 2019-05-12 20:21:55 +02:00
Viktor De Pasquale
c1c677e161 Removed old database helper 2019-05-12 19:45:07 +02:00
Viktor De Pasquale
2fe917ff82 Fixed updating values with sql 2019-05-12 19:42:05 +02:00
Viktor De Pasquale
0e6c205732 Fixed snackbar for changed su states being incorrect 2019-05-12 18:56:42 +02:00
Viktor De Pasquale
125ae0a173 Fixed conditions in sql queries 2019-05-12 18:34:28 +02:00
Viktor De Pasquale
0245e13591 Removed usage of old database object 2019-05-12 18:00:58 +02:00
Viktor De Pasquale
d546733287 Removed direct static usages of database from app 2019-05-12 17:25:26 +02:00
Viktor De Pasquale
c275326d59 Removed direct static usages of database from app 2019-05-12 16:56:56 +02:00
Viktor De Pasquale
d4561507b8 Raised deprecation level on old database 2019-05-12 14:37:24 +02:00
topjohnwu
ef0e22cc41 Slightly update scripts 2019-05-11 02:29:13 -07:00
topjohnwu
62db65bf18 Reset SafetyNet status on refresh 2019-05-11 01:55:44 -07:00
topjohnwu
d5371f752c Sort hide targets by app name 2019-05-11 01:53:37 -07:00
topjohnwu
a5f5e94115 Always reload string from resource 2019-05-11 01:50:01 -07:00
Viktor De Pasquale
2624706c69 Added missing repositories 2019-05-10 19:13:15 +02:00
Viktor De Pasquale
d39d885ec2 Removed repo db helper 2019-05-10 18:21:07 +02:00
Viktor De Pasquale
d83c744725 Replaced base settings fragment by its kotlin counterpart 2019-05-10 17:54:24 +02:00
Viktor De Pasquale
843995cdb9 Removed Event for good
http://bit.ly/2Ymrm61
2019-05-10 17:34:53 +02:00
Viktor De Pasquale
9491ba77e0 Removed locale manager loading languages in advance
Instead they are loaded on demand
2019-05-10 17:30:25 +02:00
Viktor De Pasquale
58a449d437 Merge branch 'remote-master' into development
# Conflicts:
#	app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt
#	app/src/main/java/com/topjohnwu/magisk/utils/XString.kt
2019-05-10 16:43:37 +02:00
Viktor De Pasquale
7f55e0f05b Fixed picking up wrong locale for dates 2019-05-10 16:41:31 +02:00
Viktor De Pasquale
67c3f40adb Fixed language won't change in certain views unless app restarts 2019-05-10 16:22:03 +02:00
topjohnwu
ff7a0ba599 Force apply preferred locale in applyOverrideConfiguration
Close #1442
2019-05-10 00:19:28 -07:00
topjohnwu
b152c63102 Upgrade AS 2019-05-09 23:16:21 -07:00
Shaka Huang
415ff23be5 Fix error mounting /data partition
For devices come with two /data mount points, magisk will bind the one in tmpfs and failed to load modules since this partition is empty.

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2019-05-09 20:29:10 -07:00
osm0sis
b0d6de783e Correct magiskboot help 2019-05-09 20:28:48 -07:00
osm0sis
ac28e6e5ca Fix uninstaller missing recent changes
- group unsupported formats into the same code (86f778c0aa (diff-93690a8d9f50c177ef97416af3be8726))
- support A only system-as-root devices (e72c6685ed (diff-93690a8d9f50c177ef97416af3be8726))
- remove unnecessary '--' from magiskboot actions (7f08c06943 (diff-93690a8d9f50c177ef97416af3be8726))
- get_flags need to be before find_boot_image (a4f5d47e72)

closes #1371, closes #1431, closes #1439
2019-05-09 20:28:48 -07:00
Viktor De Pasquale
4f9e8d2e8a Merge remote-tracking branch 'john/master' into development 2019-05-09 18:23:05 +02:00
Viktor De Pasquale
21be2f46f3 Moved fetch/toggle logic for hiding to repo
Fixed sorting
2019-05-09 18:21:38 +02:00
Viktor De Pasquale
a6e7680212 Fixed logs being bugged down by unreliable code 2019-05-09 17:38:13 +02:00
Viktor De Pasquale
e79e744e08 Fixed magisk db not returning stuff due to bad syntax 2019-05-09 17:13:02 +02:00
Viktor De Pasquale
7abdac72a4 Replaced log calls from magiskdb to repo 2019-05-09 17:01:34 +02:00
Viktor De Pasquale
90d85eaf7d Removed update repos as it can be done via repository 2019-05-09 15:56:06 +02:00
Viktor De Pasquale
e65f9740fb Updated build tools & enabled incremental kapt 2019-05-09 15:27:37 +02:00
Viktor De Pasquale
7538f89b56 Removed unnecessary calls from splash 2019-05-07 15:45:27 +02:00
Viktor De Pasquale
7c755a3991 Removed events from modules / replaced with retrofit/rx 2019-05-07 15:41:56 +02:00
Viktor De Pasquale
10e903c9fc Added direct fetch from network and fixed build issues 2019-05-06 20:12:31 +02:00
Viktor De Pasquale
b018124226 Added (ported back) features from initial design [retrofit,moshi,kotpref]
Marked most of the old classes using Networking as deprecated to clearly visualise their future removal
2019-05-06 19:03:28 +02:00
dark-basic
a9350f50c9 Update strings.xml
New Lines Added.
2019-05-05 12:28:57 -07:00
Andrea Cioccarelli
ed7babcbf1 Translation fixes 2019-05-05 12:24:37 -07:00
Alexander Pohl
61ebc335c4 Add hi6250 support
not only hi3660 and kirin970,980 need this, also kirin 659 does
2019-05-05 11:45:21 -07:00
Viktor De Pasquale
0167bd76f1 Removed unnecessary overriding of observable list and replaced it copy function within observable changed callback 2019-05-05 11:33:17 -07:00
Viktor De Pasquale
79d704008b Fixed rewritten java code being java-styled in kotlin
Fixed accessing kotlin code illegally via companion helper
2019-05-05 11:33:17 -07:00
Viktor De Pasquale
0a703585b0 Fixed items in navView not being checked 2019-05-05 11:33:17 -07:00
Viktor De Pasquale
5d632d0d90 Removed unnecessary overriding of observable list and replaced it copy function within observable changed callback 2019-05-05 12:46:28 +02:00
Viktor De Pasquale
4eecaea601 Fixed rewritten java code being java-styled in kotlin
Fixed accessing kotlin code illegally via companion helper
2019-05-05 12:17:32 +02:00
Viktor De Pasquale
63055818ec Fixed items in navView not being checked 2019-05-05 11:50:27 +02:00
Viktor De Pasquale
0beb08b687 Merge remote-tracking branch 'john/master' into development
# Conflicts:
#	app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
2019-05-05 11:26:37 +02:00
topjohnwu
b27801a27c Remove unused dependencies 2019-05-04 17:56:02 -07:00
topjohnwu
a0cfce7cbc Rewrite FlashZip in Kotlin 2019-05-03 04:42:57 -04:00
topjohnwu
8b7144c986 Rewrite ZipUtils in Kotlin 2019-05-03 04:10:27 -04:00
topjohnwu
d3f5f5ee59 Rewrite RootUtils in Kotlin 2019-05-03 03:36:39 -04:00
topjohnwu
a2a3c7f438 Collect both STDOUT and STDERR for logs 2019-05-03 02:05:51 -04:00
Viktor De Pasquale
4496f82d5b Added scrolling to latest items while flashing
Since the adapter might be set _after_ the request, as there is no guaranteed order, it's done with waiting recursion yuck
2019-05-03 00:50:46 -04:00
Viktor De Pasquale
09d531557d Fixed requesting permissions off main thread 2019-05-03 00:50:46 -04:00
Viktor De Pasquale
7fee82f731 Fixed shell long dumping to UI 2019-05-03 00:50:46 -04:00
Viktor De Pasquale
475054c48a Fixed backpress not working 2019-05-03 00:50:46 -04:00
Viktor De Pasquale
a743d05751 Fixed icon not being tintable resulting in transparent block 2019-05-03 00:50:46 -04:00
topjohnwu
d1ed502e03 Multidex debug only 2019-05-02 14:06:08 -04:00
vvb2060
37744c7ab6 exclude useless files 2019-05-02 13:43:45 -04:00
Viktor De Pasquale
bbc9e60a12 Added scrolling to latest items while flashing
Since the adapter might be set _after_ the request, as there is no guaranteed order, it's done with waiting recursion yuck
2019-05-02 16:23:20 +02:00
Viktor De Pasquale
6c975ecc4c Fixed requesting permissions off main thread 2019-05-02 16:20:30 +02:00
Viktor De Pasquale
23e8a4ce4b Fixed shell long dumping to UI 2019-05-02 16:20:11 +02:00
Viktor De Pasquale
50134a2f9b Fixed backpress not working 2019-05-02 16:03:56 +02:00
Viktor De Pasquale
628b37c4fa Fixed icon not being tintable resulting in transparent block 2019-05-02 15:14:35 +02:00
Viktor De Pasquale
1b4ae70a43 Merge remote-tracking branch 'john/master' into development 2019-05-02 14:45:28 +02:00
topjohnwu
b25c49725f Sort hidden items on the top 2019-05-02 06:38:42 -04:00
topjohnwu
b245782c7e Always show hidden apps 2019-05-02 06:16:58 -04:00
topjohnwu
a9f32baae0 Fix links 2019-05-02 04:42:54 -04:00
topjohnwu
e7ef71865d Update doc index 2019-05-02 04:41:59 -04:00
topjohnwu
88c4f72b37 Remove Butterknife 2019-05-02 04:06:59 -04:00
topjohnwu
abbcdf91a5 Remove SafetyNet.java 2019-05-02 03:45:15 -04:00
topjohnwu
b876df6e21 Fix Czech strings 2019-05-02 03:22:14 -04:00
topjohnwu
4bb81f35d7 Rename MagiskFragment to HomeFragment 2019-05-02 03:21:46 -04:00
topjohnwu
ff20267b3f Remove redundent classes 2019-05-02 02:42:00 -04:00
topjohnwu
2c9586d811 Update dependencies 2019-05-02 02:12:29 -04:00
topjohnwu
2813d2031a Merge branch 'WIP' 2019-05-02 02:03:20 -04:00
topjohnwu
4040a0242f Update app changelog 2019-05-01 14:11:10 -04:00
topjohnwu
781ec810d9 Remove unnecessary applets of MagiskInit 2019-05-01 13:55:59 -04:00
topjohnwu
9e90a71c04 Update installation instruction for latest release 2019-05-01 13:50:10 -04:00
zertyuiop
5571714b26 Update Russian translation
Added missing strings
2019-05-01 13:49:59 -04:00
xorcan
e0d1f02ef5 Update strings.xml 2019-05-01 13:49:51 -04:00
xorcan
1b729e5ff2 updade Turkish
latest
2019-05-01 13:49:44 -04:00
davidtrpcevski
51e587d4e8 Add full Macedonian translation 2019-05-01 13:49:34 -04:00
topjohnwu
ac9c55dbc1 Add info regarding signing certificates
Close #961
2019-05-01 03:27:06 -04:00
Viktor De Pasquale
065051a360 Merge remote-tracking branch 'john/master' into development 2019-05-01 09:05:22 +02:00
topjohnwu
0893ac3141 No more old module exists 2019-05-01 01:23:07 -04:00
topjohnwu
fb40e96917 Update outputs 2019-05-01 01:22:37 -04:00
topjohnwu
4ca25f74c6 More robust mounting scripts
Close #1376
2019-04-30 17:35:58 -04:00
osm0sis
7fda917b86 Fix addon.d error OUTFD derp 2019-04-30 17:09:25 -04:00
osm0sis
e6bd5f2c40 Display error if actual Magisk addon.d script cannot be run
- this would likely occur on an FDE device with block map OTAs (a la LineageOS) since they do not require/request decrypt
- for reference all other addon.d "v1" cases should work fine:
  1) FDE with openrecovery script works fine since it requests decrypt
  2) FBE with openrecovery script OR block map work fine since /data/adb remains accessible
2019-04-30 10:27:29 -04:00
topjohnwu
8a904ee384 Update native external dependencies 2019-04-30 01:31:07 -04:00
topjohnwu
00a9f18a1e Build with -Wall 2019-04-29 21:26:43 -04:00
topjohnwu
8d68ebb074 Revert ioctl rules 2019-04-29 21:25:57 -04:00
topjohnwu
5f53cfb4a9 Update sepolicy rules 2019-04-29 20:26:51 -04:00
topjohnwu
a2fa8d8be1 Stop fdsan complains 2019-04-29 20:04:39 -04:00
topjohnwu
70a3c78ebb Simplify magiskinit logging 2019-04-29 19:53:22 -04:00
Viktor De Pasquale
db218407b0 Fixed wrong link for github source 2019-04-27 12:13:30 +02:00
Viktor De Pasquale
d52210dd90 (Re)Added animations and shortcut endpoints
Fixed first backpress closing the app instead of showing default fragment
2019-04-27 12:09:49 +02:00
Viktor De Pasquale
f3cd9a096a Removed old Base[Activity/Fragment] 2019-04-27 11:49:25 +02:00
Viktor De Pasquale
e426090a18 Fixed checkboxes on homescreen not writing values to static fields 2019-04-27 11:43:55 +02:00
Viktor De Pasquale
cbe64fd559 Removed unnecessary assets 2019-04-27 11:38:31 +02:00
Viktor De Pasquale
63ea7a70bd Removed duplicated background from policy item 2019-04-27 11:34:26 +02:00
Viktor De Pasquale
fb0998f7a2 Fixed section titles that looked odd due to replicating paddings 2019-04-27 11:32:57 +02:00
Viktor De Pasquale
a9b00dd537 Updated deprecation statements and moved components init after attaching base context
This needed to be done in order to get the Koin working as it requires injection before calling onCreate
2019-04-27 11:27:42 +02:00
Viktor De Pasquale
52eb059515 Fixed items in superuser not disappearing when deleted 2019-04-26 21:29:13 +02:00
Viktor De Pasquale
7640246255 Fixed delete button size for policy items 2019-04-26 21:28:13 +02:00
Viktor De Pasquale
52c83b2916 Updated su screen with new arch
Added new Dialog for further use
2019-04-26 21:23:58 +02:00
Viktor De Pasquale
d9cded0fc9 Fixed styles for SU screen 2019-04-26 19:34:22 +02:00
Viktor De Pasquale
750c42caf1 Added annotations for marking code with it's current state 2019-04-26 19:33:42 +02:00
Viktor De Pasquale
bbf650c6cf Updated gradle & AS 2019-04-26 19:32:53 +02:00
Viktor De Pasquale
a25dace7e0 Merge remote-tracking branch 'john/master' into development 2019-04-24 20:39:27 +02:00
Viktor De Pasquale
14ff22fbcd Updated flash screen with new arch 2019-04-24 20:28:41 +02:00
Viktor De Pasquale
07eb7dda2d Added permission request event 2019-04-24 19:34:40 +02:00
topjohnwu
54d1207f92 Auto remove post_ota.sh 2019-04-24 01:59:47 -04:00
topjohnwu
003e44fb84 Remove requirement to use early-init daemon
We used to construct /sbin tmpfs overlay in early-init stage after
SELinux is properly initialized. However the way it is implemented
(forking daemon from magiskinit with complicated file waiting triggers)
is extremely complicated and error prone.

This commit moves the construction of the sbin overlay to pre-init
stage. The catch is that since SELinux is not present at that point,
proper selabel has to be reconstructed afterwards. Some additional
SEPolicy rules are added to make sure init can access magisk binaries,
and the secontext relabeling task is assigned to the main Magisk daemon.
2019-04-24 00:13:48 -04:00
topjohnwu
515f346dcc Monitor app_process
Some stupid Samsung ROMs will spawn multiple zygote daemons. Since we
switched to ptrace based process monitoring, we have to know all zygote
processes to trace. This is an attempt to fix this issue.

Close #1272
2019-04-22 16:36:23 -04:00
Viktor De Pasquale
d4058175b4 Fixed list query not being disposed so it could occasionally crash due to several changes rewriting each other 2019-04-22 18:28:40 +02:00
Viktor De Pasquale
2de984ae24 Added division of the modules section to updatable, installed and not installed 2019-04-22 18:20:23 +02:00
Viktor De Pasquale
761a8bf2a9 Merge remote-tracking branch 'john/master' into development 2019-04-22 17:04:08 +02:00
Viktor De Pasquale
6df7006b36 Cleaned up unnecessary classes 2019-04-22 17:03:21 +02:00
Viktor De Pasquale
aceb3ee863 Rewritten flashing internal modules to model
This is done in an effort to separate flash activity to smaller pieces.
2019-04-22 16:59:59 +02:00
Viktor De Pasquale
11d716a3c8 Updated splash screen with new arch 2019-04-22 16:00:48 +02:00
Viktor De Pasquale
7cc8c014eb Updated log screen with new arch 2019-04-22 14:11:41 +02:00
Viktor De Pasquale
f21241d944 Added divider to module actions 2019-04-22 10:47:38 +02:00
Viktor De Pasquale
a181fa0652 Fixed updating lists being to heavy for the UI thread
Moved list diff recalculation to the computing thread instead
2019-04-22 09:30:38 +02:00
Viktor De Pasquale
3f748b4d2a Fixed search in magisk hide not being case insensitive 2019-04-22 08:58:23 +02:00
Viktor De Pasquale
683450f9c6 Added search functionality to repos (downloads) 2019-04-22 08:57:32 +02:00
topjohnwu
6050c4e8ba Fix strings.xml 2019-04-21 21:01:49 -04:00
tarasyyyk
158af8819a added stub Ukrainian translation 2019-04-21 19:18:15 -04:00
tarasyyyk
7787bb31fa updated Ukrainian translation: 'Patch File' strings 2019-04-21 19:18:15 -04:00
cristisilaghi
a1fe3e7ccd Update Romanian 2019-04-21 19:18:04 -04:00
dark-basic
4316028b23 Update strings.xml
Restructured based on original string. New missing lines added
2019-04-21 19:17:56 -04:00
topjohnwu
f2b52755d6 Track all input devices with KEY_VOLUMEUP
This should in theory should support more devices for detecting the
volume up press on boot.

Close #1346
2019-04-21 19:09:08 -04:00
Viktor De Pasquale
adbd47a36c Updated modules and repos screen
Screens are merged via common viewModel, all data are immediately accessible to both of them
2019-04-20 23:44:08 +02:00
Viktor De Pasquale
ce693aa5e9 Updated policy items so listeners are not indirectly set to them and kept out of the instance of the parent object 2019-04-19 19:22:18 +02:00
Viktor De Pasquale
ad80804461 Cleaned up usage of rx subscribers 2019-04-19 16:43:44 +02:00
Viktor De Pasquale
2d55632430 Merge remote-tracking branch 'john/WIP' into development
# Conflicts:
#	gradle/wrapper/gradle-wrapper.properties
2019-04-19 16:34:15 +02:00
Viktor De Pasquale
e81f00ef1a Updated Hide screen with new arch 2019-04-19 16:32:01 +02:00
topjohnwu
93fb0e3d74 Fix release builds 2019-04-19 03:26:33 -04:00
topjohnwu
71ce0de606 Make debug buildable 2019-04-19 02:11:22 -04:00
topjohnwu
0407062c1d Merge branch 'master' into pull request #1342 2019-04-19 01:28:45 -04:00
topjohnwu
f315c4416b Upgrade libsu 2019-04-19 01:07:39 -04:00
Viktor De Pasquale
cda14af208 Fixed log tabbar titles having wrong color 2019-04-18 16:13:59 +02:00
Viktor De Pasquale
258f170cd7 Fixed elevation causing log screen look odd 2019-04-18 16:13:31 +02:00
Viktor De Pasquale
f76015d714 Fixed options menus appearing on screens that they shouldn't 2019-04-18 16:00:54 +02:00
Viktor De Pasquale
7e5e14163c Fixed titles not setting to activity toolbar 2019-04-18 15:51:02 +02:00
Viktor De Pasquale
bcd1064e94 Updated superuser fragment to new arch
Fixed theme issues along the way
2019-04-17 18:27:03 +02:00
Viktor De Pasquale
8a8441c875 Added failure callback to fingerprint dialog 2019-04-17 18:20:53 +02:00
Viktor De Pasquale
15aa813416 Migrated to compat shared prefs and fixed it not reacting to changes
Added back dark theme
2019-04-17 14:03:25 +02:00
Viktor De Pasquale
605faccffd Merge remote-tracking branch 'john/master' into development
# Conflicts:
#	app/build.gradle
#	app/src/main/java/com/topjohnwu/magisk/App.java
#	app/src/main/java/com/topjohnwu/magisk/model/adapters/ReposAdapter.java
#	app/src/main/java/com/topjohnwu/magisk/model/update/UpdateCheckService.java
#	app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.java
#	app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.java
#	app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.java
#	app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.java
#	app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.java
#	app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.java
#	app/src/main/java/com/topjohnwu/magisk/utils/ValueSortedMap.java
#	app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.java
#	app/src/main/java/com/topjohnwu/magisk/view/dialogs/MagiskInstallDialog.java
#	app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.java
#	build.gradle
2019-04-16 19:40:34 +02:00
Viktor De Pasquale
79f2d08c81 Fixed new fragment not clearing menu in toolbar 2019-04-16 19:26:53 +02:00
Viktor De Pasquale
0568ae5391 Fixed dependencies on old base 2019-04-16 19:21:20 +02:00
Viktor De Pasquale
5330dda9f8 Removed redundant casts 2019-04-16 19:03:52 +02:00
Viktor De Pasquale
ebab126579 Replaced xml navigation with self-handled 2019-04-16 19:00:32 +02:00
Viktor De Pasquale
0e5417a13e Updated progress style to match app theme and paddings to advanced settings 2019-04-16 16:21:53 +02:00
Viktor De Pasquale
9a968e0584 Added leanback activity that implements several functions which custom dialogs depend on 2019-04-15 20:26:22 +02:00
Viktor De Pasquale
ffec64d209 Added safetynet to the rewritten home fragment 2019-04-15 19:48:07 +02:00
Viktor De Pasquale
f332746188 Fixed current version showing null when magisk is not installed 2019-04-15 15:57:23 +02:00
Viktor De Pasquale
b2fa5b551e Added hiding of UI elements when no root access is detected 2019-04-14 13:17:51 +02:00
Viktor De Pasquale
36e83edddc Fixed dialog buttons after a theme change 2019-04-14 12:59:00 +02:00
Viktor De Pasquale
6b045eadef Added env fix prompt 2019-04-14 12:55:03 +02:00
Viktor De Pasquale
147264822c Fixed leaking base instance to the event listener 2019-04-14 12:29:07 +02:00
Viktor De Pasquale
36e4ccd800 Fixed touch events on includes not being propagated due to missing viewModel 2019-04-14 12:21:23 +02:00
Viktor De Pasquale
796c16237d Fixed same events not being able to propagate consecutively 2019-04-14 12:21:04 +02:00
Viktor De Pasquale
861ad9881c Updated design of the front page (with removed cards and added dividers)
Also updated material library and injected backported styles which were incompatible with the current UI for the most part and as it was over-carded all cards were removed and replaced with flat UI components.
This change is temporary and *will* be redone to the final redesign, in other words this is sufficient for the transition period.

All themers should refrain from trying to theme the app until the redesign is done. It will break your efforts with every other release.
2019-04-14 11:51:47 +02:00
Viktor De Pasquale
3101c538e9 Added (backported) styles from design concept 2019-04-14 11:28:45 +02:00
Viktor De Pasquale
42adc7382f Updated kotlin 2019-04-14 11:07:13 +02:00
Viktor De Pasquale
9bb4dfad13 Added back version checking (and version boxes) after transitioning homepage to MVVM
Fixed several errors caused along the way
2019-04-14 11:00:29 +02:00
topjohnwu
4e7dafb0e4 Use bitset instead of vector 2019-04-13 02:43:43 -04:00
Viktor De Pasquale
bd00ae8ede Updated Magisk fragment to Kotlin
Exported old update card to special xml include where binding takes care of everything that had to be done in code beforehand.
Added several easing functions and enums.
Backported some classes and functions from the old fork

Expect major breakage. Literally nothing works as the functionality needs to be implemented
2019-04-13 00:14:37 +02:00
Viktor De Pasquale
f309522268 Added (backported) values and styles for views 2019-04-12 22:06:57 +02:00
topjohnwu
a6395d35db Refactor with AS 3.5 2019-04-12 01:58:42 -04:00
Viktor De Pasquale
a028cd5cec Updated locations of nearly all files
This has been done in preparations for rewrite to kotlin and upcoming design changes.
Nothing should be broken but use caution.
2019-04-12 01:44:55 -04:00
Viktor De Pasquale
540000d26e Fixed butter knife not building with kotlin 2019-04-12 01:44:55 -04:00
Viktor De Pasquale
888c656aa8 Added kotlin support 2019-04-12 01:44:55 -04:00
Viktor De Pasquale
0efaddff23 Added binding between navigation view and navigation components
Removed bunch of code focusing on the hamburger not being stationary
2019-04-11 21:17:54 +02:00
Viktor De Pasquale
94ba7cb0c5 Added navigation endpoints 2019-04-11 20:10:14 +02:00
Viktor De Pasquale
2d58c725e0 Added koin, databinding and navigation components
Converted App class and Main activity to Kotlin. With that refactored fields within App class to allow lazy initialization

BEWARE: at this point the navigation is very much broken, won't let you anywhere beyond home screen
2019-04-11 20:01:49 +02:00
Viktor De Pasquale
e035523eb8 Added base framework 2019-04-11 18:52:30 +02:00
Viktor De Pasquale
bea5308ab7 Updated locations of nearly all files
This has been done in preparations for rewrite to kotlin and upcoming design changes.
Nothing should be broken but use caution.
2019-04-11 18:03:23 +02:00
Viktor De Pasquale
f006a85fec Fixed butter knife not building with kotlin 2019-04-11 15:32:36 +02:00
Viktor De Pasquale
ea93013ebc Added kotlin support 2019-04-11 14:49:52 +02:00
topjohnwu
8d4c407201 Directly communicate with Activity
Since Android Q does not allow launching activities from the background
(Services/BroadcastReceivers) and our native process is root, directly
launch activities and use it for communication between native and app.

The target activity is not exported, so non-root apps cannot send an
intent to fool Magisk Manager. This is as safe as the previous
implementation, which uses protected system broadcasts.

This also workaround broadcast limitations in many ROMs (especially
in Chinese ROMs) which blocks the su request dialog if the app is
frozen/force stopped by the system.

Close #1326
2019-04-10 23:35:31 -04:00
topjohnwu
fdeede23f7 Don't build test APKs 2019-04-10 23:33:22 -04:00
topjohnwu
53c5ca59b6 Cleanup SuLogger 2019-04-10 18:09:41 -04:00
topjohnwu
679db97209 Always run su requests in new tasks 2019-04-10 18:05:19 -04:00
topjohnwu
fbdd72273e Restructure SuRequestActivity 2019-04-10 17:02:32 -04:00
topjohnwu
0165602515 More cleanups 2019-04-10 13:54:33 -04:00
topjohnwu
96127f8bd1 Lock orientation in SuRequestActivity
Fix #1302, close #1318
2019-04-10 05:36:02 -04:00
topjohnwu
0dbdf336d6 Update dependencies 2019-04-10 05:17:03 -04:00
topjohnwu
48879df2da Some cleanups 2019-04-10 05:15:20 -04:00
topjohnwu
b067a5bb13 Use root to launch su request Activity on Q 2019-04-10 05:03:26 -04:00
topjohnwu
4b54cf1288 Compile with Android Q SDK
We upgrade compileSdkVersion to Q, but keep targetSdkVersion as 28.
The reason is because targeting Q will no longer allow us to execute
native binaries in an app's private data, which Magisk Manager relies
a lot for performing stock boot image patches in non rooted environment.
For more information regarding this issue, check this link:
https://redd.it/b2inbu

Some workarounds has been discovered (https://github.com/termux/proot),
however for the time being there is no point to introduce these huge
hacks just for targeting Q, which we don't benefit anything.
2019-04-10 02:17:08 -04:00
topjohnwu
6128c24f96 Drastically improve module download service 2019-04-10 02:00:48 -04:00
topjohnwu
d9c58f307f Remove unused resources 2019-04-09 04:44:09 -04:00
Lukas Novotny
b521fbeeda Update Czech translation 2019-04-09 04:38:35 -04:00
Rom
d00a3b89f2 Update French translation 2019-04-09 04:38:23 -04:00
vvb2060
3d15518191 Update zh-rCN translation 2019-04-09 04:38:09 -04:00
Ingan121
9b6535fdf5 Update Korean translations 2019-04-09 04:37:58 -04:00
topjohnwu
e0424fdba3 Remove patch format options
Output format will be the same as input
2019-04-09 04:37:34 -04:00
Ian Macdonald
7481c53451 Update samsung.md 2019-04-08 21:07:36 -04:00
topjohnwu
7219947237 Update libsu
Close #1314
2019-04-08 21:05:11 -04:00
topjohnwu
b72004e9cc Move methods 2019-04-08 17:35:32 -04:00
topjohnwu
f187213568 Run update check service only in background 2019-04-08 17:35:32 -04:00
topjohnwu
fc0df84edd Keep track of foreground activity 2019-04-08 17:35:32 -04:00
topjohnwu
f24df4f43d Don't allow cloning root nodes
The root nodes are /system and /vendor. Adding new files into these
directories, although works on some devices, mostly bootloops on many
devices out there. So don't allow it, which also makes the whole magic
mounting logic much easier and extensible.
2019-04-08 12:30:57 -04:00
topjohnwu
dab32e1599 Use our own device nodes for mirrors 2019-04-08 01:40:04 -04:00
topjohnwu
bc286fd4d3 Upgrade Android Studio 2019-04-07 23:03:43 -04:00
topjohnwu
befe1a83b5 Use real system_root mirror 2019-04-07 14:22:45 -04:00
topjohnwu
82ea9db9fd Don't override arguments 2019-04-06 17:19:47 -04:00
topjohnwu
c5758b3f2d Update scripts 2019-04-06 13:04:17 -04:00
topjohnwu
ace3708c9c Update key combo for download mode 2019-04-06 04:45:51 -04:00
topjohnwu
fc5026d268 Add info regarding direct upgrades 2019-04-06 03:08:42 -04:00
topjohnwu
77fd0e54be Better wording 2019-04-06 03:05:41 -04:00
John Wu
24490e0ff5 Update samsung.md 2019-04-06 02:55:11 -04:00
topjohnwu
da3937ff4e Reboot after env_fix 2019-04-06 01:56:47 -04:00
topjohnwu
ebe1ab982e Add Samsung instructions 2019-04-06 01:25:11 -04:00
John Wu
98590cb00d Upload Samsung bootloader image 2019-04-05 23:35:00 -04:00
topjohnwu
ff95f634f0 Use release canary APK in stub 2019-04-05 21:07:59 -04:00
topjohnwu
ced9b4a8ee Default to beta channel if detected 2019-04-05 20:48:19 -04:00
topjohnwu
7af7910e78 Revert "Revert to old find boot order"
This reverts commit 5203886f0b.
2019-04-05 15:18:39 -04:00
vvb2060
a4f5d47e72 get_flags need before find_boot_image 2019-04-05 15:18:28 -04:00
topjohnwu
6953cc2411 Use separate flags for 64-bit 2019-04-05 15:17:59 -04:00
topjohnwu
6a0b2ddee9 Let stub APK respect canary builds 2019-04-05 07:15:54 -04:00
topjohnwu
24f5bc98d8 Add boot_complete trigger back
Samsung does not like running cmd before system services are started.
Instead of failing, it will enter an infinite wait on binder.
Move APK installation to boot complete to make sure pm can be run
without blocking process.
2019-04-05 07:00:30 -04:00
topjohnwu
5203886f0b Revert to old find boot order 2019-04-04 20:01:59 -04:00
topjohnwu
c10b376575 Support patching full ODIN firmware 2019-04-04 07:27:43 -04:00
topjohnwu
ceb21ced2b Small changes 2019-04-04 02:30:03 -04:00
topjohnwu
86789a8694 Add logging in magiskinit 2019-04-04 00:26:16 -04:00
topjohnwu
ca2235aee7 Update strings 2019-04-03 17:59:54 -04:00
topjohnwu
a385e5cd92 Use wrapper script on system with APEX
Thanks to moving libandroidicu.so to APEX runtime linker namespace,
we need a wrapper to link against libsqlite.so on Q
2019-04-03 17:25:47 -04:00
topjohnwu
0c7a95bdf6 Small net update 2019-04-03 01:01:18 -04:00
topjohnwu
036b5acf42 Update Markwon to 3.0.0 2019-04-02 23:58:19 -04:00
topjohnwu
056dafc59f Use R8 full mode
R8 FTW!
2019-04-02 16:32:40 -04:00
topjohnwu
a9c90718d6 Update some dependencies 2019-04-02 01:50:25 -04:00
topjohnwu
cc77a24502 Prevent accidental magiskinit execution
Close #1281
2019-04-01 17:14:18 -04:00
topjohnwu
71a91ac7a7 Boot to recovery if volume up key is held
Forseeing the future that more and more A only system-as-root devices
would have similar bootloader behavior as the latest Samsung devices
(that is, no ramdisk will be loaded into memory when booting from
the boot partition), a solution/workaround has to be made when Magisk
is installed to the recovery partition, making custom recoveries
unable to co-exist with Magisk.

This commit allows magiskinit to read input device events from the
kernel to detect when a user holds volume key up to toggle whether
system-as-root mode is enabled. When system-as-root mode is disabled,
magiskinit will boot with ramdisk instead of cloning rootfs from system,
which in this case will boot to the recovery.
2019-04-01 03:01:05 -04:00
topjohnwu
08a70f033a Add entrypoint to build test
Just for convenience, nothing special here
2019-04-01 02:46:09 -04:00
topjohnwu
1b0c36dbd5 Remove outdated comments 2019-03-31 15:40:55 -04:00
topjohnwu
91da1cf817 Make on_install happen earlier to allow more customization 2019-03-31 15:37:12 -04:00
topjohnwu
c577a9525d Remove simple mount mode
This mode is proven to have no difference than normal post-fs-data
module mounting. No reason to keep this code in the sources.
2019-03-31 15:10:01 -04:00
topjohnwu
0149b1368d Several improvements 2019-03-31 06:32:33 -04:00
topjohnwu
cd6bcb97ef Cleanup stuffs 2019-03-31 00:48:22 -04:00
topjohnwu
df4161ffcc Reboot to recovery when running as recovery 2019-03-30 06:49:29 -04:00
topjohnwu
7a133eaf03 Block vaultkeeper and flash_recovery service 2019-03-30 04:13:45 -04:00
topjohnwu
1cd45b53b1 Support recovery based Magisk
Some devices (mainly new Samsung phones we're talking here...) using
A only system-as-root refuse to load ramdisk when booted with boot
no matter what we do. With many A only system-as-root devices, even
though their boot image is kernel only, we can still be able to add
a ramdisk section into the image and force the kernel to use it as
rootfs. However the bootloader on devices like the S10 simply does
not load anything within boot image into memory other than the kernel.
This gives as the only option is to install Magisk on the recovery
partition. This commits adds proper support for these kind of scenarios.
2019-03-30 00:49:48 -04:00
topjohnwu
5b30c77403 Fix strings 2019-03-29 10:39:11 -04:00
Gozzwip
8248480d56 Translation done
Please change the name of the language to Azərbaycanca
2019-03-29 10:37:28 -04:00
Vladimír Kubala
345d992d39 Update Slovak translations 2019-03-29 10:36:47 -04:00
topjohnwu
a7f6afa4bc Add 7.1.1 changelog 2019-03-29 10:31:08 -04:00
topjohnwu
d22c7de79a Don't care minMagiskVersion
It will be sanitized by magiskbot anyways
2019-03-29 10:25:07 -04:00
topjohnwu
3eae9494ce Add 7.1.0 changelog 2019-03-28 09:53:05 -04:00
topjohnwu
be7e737253 Add a small notice for migration 2019-03-28 08:37:23 -04:00
topjohnwu
b6eb912dba Fix links in table of contents 2019-03-28 07:03:38 -04:00
topjohnwu
8049b08918 More precise new installer detection 2019-03-28 06:33:24 -04:00
Oliver Cervera
d1fa5be210 Update Italian translations
- added new strings from Welcome Activity
- misc fixes
2019-03-28 05:52:46 -04:00
Cristian Silaghi
fdbb1af02c Update Romanian language 2019-03-28 05:52:25 -04:00
topjohnwu
c85a5cae88 Update links 2019-03-28 05:45:58 -04:00
topjohnwu
649ef53409 Update many details in docs 2019-03-28 05:25:20 -04:00
topjohnwu
e784212283 Update tools docs 2019-03-28 04:54:06 -04:00
topjohnwu
66eb1078fe Update docs for module devs 2019-03-28 04:48:46 -04:00
topjohnwu
1c09b3642f Properly setup update flag in module installer 2019-03-27 22:20:39 -04:00
topjohnwu
d08b1a6639 Remove com.google.android.gms from default list
It seems that even adding this to the list doesn't 100% works on all
devices out there, and some even reported crashes on several Google
services. Disable it for now and do further investigations in the future.
2019-03-27 21:33:04 -04:00
topjohnwu
10f50e2401 Revert to old behavior on old MagiskHide versions 2019-03-27 20:43:38 -04:00
topjohnwu
8e9a7b25a1 Upgrade Android Studio 2019-03-27 18:31:50 -04:00
topjohnwu
4859ee2da9 Inject module-installer.sh if new format is detected 2019-03-24 06:20:57 -04:00
topjohnwu
b45db44ad9 Update transitions 2019-03-24 04:29:09 -04:00
topjohnwu
e25ce63872 Remove AppUtils 2019-03-24 02:16:19 -04:00
topjohnwu
162eeaa0a6 Improve repo adapter 2019-03-24 02:02:34 -04:00
topjohnwu
f36ce905aa Improve repo adapter
Fix #435
2019-03-23 23:18:26 -04:00
topjohnwu
8ac3aaf36c Rename Topic -> Event 2019-03-23 21:58:42 -04:00
topjohnwu
a199b0ace1 Use ZIPFILE instead of ZIP
The tool zip reads , we don't want it
2019-03-23 20:49:16 -04:00
topjohnwu
2f2108e4e8 Fix typo in module installer 2019-03-23 05:28:43 -04:00
topjohnwu
f5f7fd9132 Add com.android.google gms to default hide list
Close #1235
2019-03-23 04:39:34 -04:00
topjohnwu
f9ae4ab475 Add base Magisk module installer script 2019-03-23 04:27:36 -04:00
topjohnwu
8de03eef3f Allow modules to have custom uninstaller script 2019-03-23 03:50:55 -04:00
topjohnwu
8df942f96e Adjust scripting 2019-03-23 03:36:35 -04:00
topjohnwu
9bb2243b56 Switch to skip_mount instead of auto_mount
95%+ of existing modules enables auto mount (obviously).
Switching auto mount to opt-out makes more sense than opt-in as
in previous module format. The file 'auto_mount' will be ignored, and
the file 'skip_mount' will be checked to toggle the mounting behavior.

After scanning through the current Magisk Module Repo modules, no
modules are using custom bind mounting; all modules with auto mount
disabled have empty system folder, which means this change will not
affect any existing module.
2019-03-23 03:05:38 -04:00
topjohnwu
db06038548 Fix Magisk installation 2019-03-22 02:48:42 -04:00
topjohnwu
ecb33d3176 Cleanup scripts 2019-03-22 02:32:21 -04:00
topjohnwu
eae1c17738 Remove features before aborting 2019-03-22 02:01:36 -04:00
topjohnwu
ea55532e33 Copy busybox instead of bind mounting 2019-03-22 01:52:13 -04:00
topjohnwu
2a40cb60a9 Behave more sane in extreme conditions 2019-03-22 01:50:33 -04:00
topjohnwu
d371d017b7 Update dependencies 2019-03-22 00:49:55 -04:00
topjohnwu
1d9359d563 Fix additional setup 2019-03-20 03:20:02 -04:00
topjohnwu
945f88105f Support system-as-root devices with monolithic sepolicy 2019-03-18 04:54:15 -04:00
topjohnwu
957feca626 Limit sepolicy load to Android Q only
It seems both Android cancers, Samsung and Huawei devices, don't
like preloading sepolicy. For a temporary solution now is to limit
the sepolicy loading to Android Q only.
2019-03-16 17:15:48 -04:00
topjohnwu
c0447009db Allow entrypoint for rootfs construction simulation 2019-03-16 04:45:56 -04:00
topjohnwu
8893cbd64a Modularize MagiskInit 2019-03-15 14:46:30 -04:00
topjohnwu
f0240b1f06 Support Android Q new split sepolicy setup 2019-03-15 06:17:37 -04:00
topjohnwu
e476c18c99 Don't load sepolicy on Huawei devices
Of course, the cancer of Android, Huawei, has to do some f**king weird
modifications to the Linux kernel. Its kernel only accepts 1 single
policy load in its lifetime, a second load will result in ENOMEM error.
Since Huawei devices always use their own stupid ramdisk setup and not
system-as-root, not loading sepolicy is not a concern (for now).
2019-03-14 22:48:23 -04:00
topjohnwu
a1b5185ecb Make sure rootfs file selabels are correct
Android Q init assumes rootfs to always be on EXT4 images, thus
never runs restorecon on the whole root directory. This is an issue
because some folders in rootfs were set with special selabels in
the system partition, but when copying over to initramfs by magiskinit,
these labels will not be preserved.

So the solution is to relabel the files in rootfs with the original
context right? Yes, but rootfs does not allow security xattr to be set
on files before the kernel SELinux initializes with genfs_contexts.
We have to load our sepolicy to the kernel before we clone the root
directory from system partition, which we will also restore the selabel
in the meantime.

Unfortunately this means that for each reboot, the exact same policy
will be loaded to the kernel twice: once in magiskinit so we can label
rootfs properly, and once by the original init, which is part of the
boot procedure. There is no easy way to prevent init from loading
sepolicy, as init will refuse to continue if policy loading has failed.
2019-03-14 22:27:29 -04:00
topjohnwu
981e90cc32 Don't remove SafetyNet from hide list 2019-03-14 07:00:36 -04:00
topjohnwu
da0a72e8b0 Improve builtin selinux implementation 2019-03-14 06:34:22 -04:00
topjohnwu
b7e2e972c7 Support boot_img_hdr_v2 2019-03-13 16:51:22 -04:00
topjohnwu
650b2ce6b1 Fix config bugs 2019-03-13 15:25:53 -04:00
topjohnwu
ecf3d30349 Only show expansion when necessary 2019-03-13 08:15:02 -04:00
topjohnwu
15ddd0e284 More MagiskHide list UI improvements 2019-03-13 07:49:12 -04:00
topjohnwu
18ac6b270f Make Expandable more extensible 2019-03-13 06:12:02 -04:00
topjohnwu
3e35de9b39 Small UI improvements 2019-03-13 05:11:18 -04:00
topjohnwu
1e24c72c11 Use our own existing implementation 2019-03-13 01:37:35 -04:00
vvb2060
217564963d New MagiskHide UI 2019-03-12 17:20:08 -04:00
topjohnwu
f2f4649ab0 Don't crash when encounter unexpected XML input 2019-03-12 17:19:29 -04:00
Oliver Cervera
4395ffec5f Update it-it stub
Better wording!
2019-03-12 17:04:23 -04:00
topjohnwu
9a7a26407a Update build script 2019-03-12 17:01:37 -04:00
topjohnwu
5072a67807 Update AGP and R8 2019-03-12 16:53:07 -04:00
topjohnwu
dce0b6c05a Always detach all child threads before leaving 2019-03-12 16:48:01 -04:00
topjohnwu
a4a661bf34 Small code restructuring 2019-03-11 12:44:50 -04:00
topjohnwu
771e500468 Use dark theme by default 2019-03-11 07:39:01 -04:00
topjohnwu
7e3ff03109 Default to canary channel if running canary build 2019-03-11 07:38:31 -04:00
topjohnwu
a1827fd680 Make sure to read db before 2019-03-11 07:30:37 -04:00
topjohnwu
9ce334feac Update the way to deal with configs 2019-03-11 07:03:36 -04:00
topjohnwu
ed11e0bff6 Fix repackage manager settings migration 2019-03-11 05:43:48 -04:00
topjohnwu
5111086637 Don't care if child threads were unknown 2019-03-10 01:46:32 -05:00
topjohnwu
20f204810e Use RAII to detach PIDs 2019-03-10 01:14:41 -05:00
topjohnwu
4581354e7a Allow zygote to execve
Allow zygote to execute other programs (such as dex2oat).
This fixes the bug that cause ART framework boot images failed to load
and result to extremely serious performance degradation.

Fix #1195
2019-03-09 22:58:05 -05:00
topjohnwu
faf4d76388 Use large vector<bool> instead of set<pid>
vector<bool> uses bitsets, so we actually only use 12k memory to
store all 3 possible PID info tables. PID checkup will be now become
O(1) instead of O(logn).

P.S. The reason why we don't use unordered_map is because including it
will result in significant binary size increase (might be due to the
complex hash table STL implementation? I really don't know).
2019-03-09 22:28:43 -05:00
topjohnwu
a46e255709 Fix strings.xml 2019-03-09 05:47:19 -05:00
Vladimír Kubala
63e2bbb4d1 Slovak translation update 2019-03-09 05:37:50 -05:00
bubuleur
c3dabae237 Update French Language
Small correction line 108 thank you
2019-03-09 05:37:41 -05:00
topjohnwu
f1abcbb7fb Update WorkManager 2019-03-09 05:36:49 -05:00
topjohnwu
70efddb90f Only use SELinux if necessary in init 2019-03-09 05:30:42 -05:00
topjohnwu
f24a5dfd45 More efficient xml parsing 2019-03-09 04:27:04 -05:00
topjohnwu
081074ad9d Better zygote process detection 2019-03-08 23:53:53 -05:00
topjohnwu
ab0cc78d2c Update README.md 2019-03-08 10:23:42 -05:00
topjohnwu
de5c902fdb Remove app-core module
Less confusion
2019-03-08 10:19:22 -05:00
topjohnwu
cf65169c99 Separate stub Magisk Manager to a module 2019-03-08 10:16:02 -05:00
topjohnwu
745865ee53 Add canary channels
Only show if user is already on canary channels
2019-03-08 06:23:13 -05:00
topjohnwu
c134fb1939 Remove unnecessary rules 2019-03-08 04:21:23 -05:00
topjohnwu
0204d05316 Remove Zygote notifier
Temporary trigger process scan on packages.xml updates, will find better methods
2019-03-08 03:35:17 -05:00
topjohnwu
c345633d80 Fix build error
Close #1182
2019-03-08 01:01:42 -05:00
topjohnwu
a57a94040e Update some format magics 2019-03-08 00:47:15 -05:00
topjohnwu
1bde78d121 Rename patch_level -> os_patch_level 2019-03-07 21:59:03 -05:00
topjohnwu
bbd014ad1b More saftey checks and improvements 2019-03-07 21:49:47 -05:00
topjohnwu
1287372f5a Support patching header in magiskboot 2019-03-07 21:32:01 -05:00
topjohnwu
d2cb638fcd Use our own function to parse int 2019-03-07 20:31:35 -05:00
topjohnwu
bbe4b69c8d Fix LZ4FEncoder constructor 2019-03-07 19:58:59 -05:00
topjohnwu
7f08c06943 Remove unnecessary '--' from magiskboot actions 2019-03-07 18:07:23 -05:00
topjohnwu
8f4a6415cd Use ToT r8 for releases 2019-03-07 17:33:06 -05:00
topjohnwu
0442d6d509 Only compress kernel and ramdisk if input not compressed 2019-03-07 07:24:20 -05:00
lindwurm
a3fc6d2a27 l10n: Update Japanese translation
Signed-off-by: lindwurm <lindwurm.q@gmail.com>
2019-03-07 06:10:42 -05:00
linar10
7db05ac927 Update strings.xml 2019-03-07 06:10:29 -05:00
Igor Dyatlov
8bed93b3c5 Updated Russian translation 2019-03-07 06:10:14 -05:00
topjohnwu
915b49014f Build libsqlite.so only with magisk
Fix #1175
2019-03-07 05:21:27 -05:00
topjohnwu
c699f30831 Fix some build issues 2019-03-07 05:05:46 -05:00
topjohnwu
3e73e3a906 Play with Java streams 2019-03-07 03:43:28 -05:00
topjohnwu
32c65d8a88 Upgrade Android Studio 2019-03-07 03:41:24 -05:00
topjohnwu
a49328edd3 Workaround Binder transaction limits 2019-03-07 02:07:34 -05:00
topjohnwu
9a15365a57 Welcome, Java 8/9 APIs
Fix #1162
2019-03-07 00:01:07 -05:00
topjohnwu
82c864d57e Make zygote notifier more reliable 2019-03-06 18:22:04 -05:00
topjohnwu
6226f875ff Make db settings constructor more readable 2019-03-06 08:21:23 -05:00
topjohnwu
370015a853 Modernize database code (again) 2019-03-06 08:16:12 -05:00
topjohnwu
6597b7adc0 Add MicroG DroidGuardHelper as target
MicroG uses a different package to handle DroidGuard service (SafetyNet),
but still uses the same com.google.android.gms.unstable process name.
Thanks to the changes in 4e53ebfe, we can target both official GMS
and MicroG SafetyNet services at the same time.
2019-03-06 05:43:52 -05:00
topjohnwu
4e53ebfe44 Use both package name and process name as key
Different packages could potentially use the same process name,
and they shouldn't conflict with each other.
2019-03-06 05:40:52 -05:00
topjohnwu
04ef1e6405 Make parse prop file a util function 2019-03-05 20:27:09 -05:00
topjohnwu
b278d07b05 Switch to Zygote ptrace-ing
No matter if we use the old, buggy, error prone am_proc_start monitoring,
or the new APK inotify method, both methods rely on MagiskHide 'reacting'
fast enough to hijack the process before any detection has been done.

However, this is not reliable and practical. There are apps that utilize
native libraries to start detects and register SIGCONT signal handlers
to mitigate all existing MagiskHide process monitoring mechanism. So
our only solution is to hijack an app BEFORE it is started.

All Android apps' process is forked from zygote, so it is easily the
target to be monitored. All forks will be notified, and subsequent
thread spawning (Android apps are heaviliy multithreaded) from children
are also closely monitored to find the earliest possible point to
identify what the process will eventually be (before am_proc_bound).

ptrace is extremely complicated and very difficult to get right. The
current code is heaviliy tested on a stock Android 9.0 Pixel system,
so in theory it should work fine on most devices, but more tests and
potentially fixes are expected to follow this commit.
2019-03-05 20:23:27 -05:00
topjohnwu
6c3896079d Add zygote server notifier 2019-03-05 20:23:27 -05:00
topjohnwu
e73fa57d54 Update Android Studio 2019-03-05 07:38:40 -05:00
topjohnwu
eaa9c7e2a0 Android Q init is not always a symlink 2019-03-03 14:56:36 -05:00
topjohnwu
14ae29d907 Support Android Q new init setup 2019-03-03 06:35:25 -05:00
linar10
e8f35b02ca Update strings.xml 2019-03-02 05:49:37 -05:00
topjohnwu
dee3c3e7ba Workaround seccomp on MagiskBoot
Close #1150
2019-03-02 05:46:15 -05:00
topjohnwu
d8cd2031c7 SIGSTOP any possible process ASAP
Shut down any UID matching process and resume if it turns out not to
be our target. Since we will record every single process we have ever
paused, this means that the same process will not be paused erroneously
for another time.

This is an optimization to hijack the app as soon as possible.
2019-03-02 04:24:41 -05:00
topjohnwu
7203e7df5c Create mapping from watch descriptor to UID 2019-03-02 03:44:24 -05:00
topjohnwu
b51feffe80 Limit process name match to cmdline only
We are only interested in Zygote forked processed
2019-03-01 18:13:41 -05:00
topjohnwu
b1afd554fc Application Component Granularity MagiskHide
Before switching to the new MagiskHide implementation (APK inotify),
logcat parsing provides us lots of information to target a process.
We were targeting components so that apps with multi-processes
can still be hidden properly.

After switching to the new implementation, our granularity is limited
to the UID of the process. This is especially dangerous since Android
allow apps signed with the same signature to share UIDs, and many system
apps utilize this for elevated permissions for some services.

This commit introduces process name matching. We could not blanketly
target an UID, so the workaround is to verify its process name before
unmounting.

The tricky thing is that any app developer is allowed to name the
process of its component to whatever they want; there is no 'one
rule to catch them all' to target a specific package. As a result,
Magisk Manager is updated to scan through all components of all apps,
and show different processes of the same app, each as a separate
hide target in the list.

The hide target database also has to be updated accordingly.
Each hide target is now a <package name, process name> pair. The
magiskhide CLI and Magisk Manager is updated to support this new
target format.
2019-03-01 17:08:08 -05:00
topjohnwu
885e3c574b Upgrade dependencies 2019-02-28 23:42:33 -05:00
topjohnwu
05dd5f3396 Only load config prop when needed
Close #922
2019-02-28 23:42:33 -05:00
SakuraSa233
ec3c43faf1 update: Japanese translation 2019-02-28 05:57:53 -05:00
topjohnwu
e72c6685ed Support A only System-as-root Devices
Most Chinese devices (and supposedly Galaxy S10) running Android Pie
is using system-as-root without A/B partition.

https://source.android.com/devices/bootloader/system-as-root#about-system-as-root

According to the docs above, these devices will have a ramdisk block
with size 0 in their boot images. Since magiskinit can run independently
on system-as-root devices, we simply just create an empty ramdisk with
magiskinit added as init.

Huge thanks to @vvb2060 for the heads up and original PR.
Close #980, close #1102
2019-02-28 05:46:36 -05:00
Cristian Silaghi
99d6bd8efc Minor changes for Romanian 2019-02-27 16:44:49 -05:00
linar10
4c8587a9f2 Update strings.xml 2019-02-27 16:44:41 -05:00
John Wu
54a8a05dae Small adjustments in connect.cpp 2019-02-27 16:44:27 -05:00
John Wu
164a99681b Make case Intent.ACTION_REBOOT fall through 2019-02-27 16:44:27 -05:00
vvb2060
0eef4eacd6 Use REBOOT foreground broadcast 2019-02-27 16:44:27 -05:00
topjohnwu
5764f0c839 Compiler flag enhancements
- Enable LTO
- Add -fomit-frame-pointer for even smaller binary size

This commit is inspired by #1075. Close #1075.
2019-02-26 03:42:44 -05:00
topjohnwu
f28e425542 Fix strings resources 2019-02-26 03:13:49 -05:00
Hugwalk
d1a4f046e9 Recreate translations for Chinese (Taiwan)
Fixed wordings to fit Taiwanese accent.
e.g. 日誌 (log) to 記錄檔

Kept proper nouns in English
e.g. Superuser instead of 超級使用者

Removed westernised Chinese as much as possible.
2019-02-26 03:08:29 -05:00
Gozzwip
2ce1dc4afe new translations 2019-02-26 03:07:45 -05:00
linar10
37ac249fd7 Update strings.xml 2019-02-26 03:07:29 -05:00
vvb2060
f152bea8d8 Trim dev name 2019-02-26 03:04:17 -05:00
Oliver Cervera
7b089b888a Update Italian Translation
Minor changes
2019-02-26 02:47:01 -05:00
Cristian Silaghi
68f0e1fe39 Update Romanian translation 2019-02-26 02:46:50 -05:00
topjohnwu
8032bd0bac Introduce /data mirror
Since we switched to imageless Magisk, module files are directly
stored in /data. However, /data is mounted with nosuid, which also
prevents SELinux typetransition to work (auto transition from one
domain to another when executing files with specific context).
This could cause serious issues when we are replacing system critical
components (e.g. app_process for Xposed), because most of them
are daemons that run in special process domains.

This commit introduced /data mirror. Using similar mirroring technique
we used for system and vendor, we mount another mirror that mounts
/data without nosuid flag. All module files are then mounted from this
mirror mountpoint instead of directly from /data.

Close #1080
2019-02-25 06:13:42 -05:00
topjohnwu
0c227f2917 Always clone attribute from existing files to module files
This makes sure no weird permission/SELinux issues shall happen
2019-02-25 05:17:08 -05:00
topjohnwu
c9fa8118d1 Some code adjustments 2019-02-24 23:09:34 -05:00
topjohnwu
63b18246d8 Add compressed ramdisk support 2019-02-24 20:39:01 -05:00
topjohnwu
16ec37a226 Fix compression without outname 2019-02-24 17:45:08 -05:00
topjohnwu
bd4e5bfc1a Some minor optmizations 2019-02-24 17:45:08 -05:00
topjohnwu
621fd0ee29 Fix SEGV_ACCERR on some 64 bit devices 2019-02-24 08:20:05 -05:00
topjohnwu
6ca8db2f0c Welcome to the 64 bit world!
Close #854
2019-02-24 08:13:27 -05:00
topjohnwu
ea129fb206 Allow cpio mv to override existing entries 2019-02-24 05:11:36 -05:00
topjohnwu
3356d7b6ff More friendly to obscure/outdated custom recoveries
Close #1049
2019-02-24 04:45:47 -05:00
topjohnwu
c84023bdc2 Fix crashes when removing verity_key 2019-02-24 04:29:15 -05:00
topjohnwu
86f778c0aa Group unsupported formats into the same code 2019-02-24 02:30:04 -05:00
topjohnwu
defbbdfe21 Update scripts 2019-02-24 02:11:11 -05:00
topjohnwu
0f46493477 Compile magiskboot as static 2019-02-23 17:01:44 -05:00
topjohnwu
340bac7e42 Add decompression command 2019-02-23 16:53:51 -05:00
topjohnwu
1d3ce9fef1 Support loading CPIO from a chunk of bytes 2019-02-23 16:16:35 -05:00
topjohnwu
4a398642b8 Set mode in constructor 2019-02-23 15:22:11 -05:00
topjohnwu
9c89e56c56 Add ramdisk compression option 2019-02-23 15:04:15 -05:00
topjohnwu
267c59b1f1 Add truncate while open 2019-02-23 13:08:54 -05:00
topjohnwu
2ab17204c6 Add stream output for CPIO 2019-02-23 05:06:07 -05:00
topjohnwu
75939047d1 Fix bugs in compression 2019-02-23 04:51:13 -05:00
topjohnwu
2d7f130d2c Introduce Java-like OutputStream 2019-02-23 04:51:13 -05:00
topjohnwu
f7ae72a36c Move CPIO to libutils 2019-02-23 02:42:26 -05:00
topjohnwu
391783e268 Introduce mmap based CPIO class 2019-02-23 02:23:24 -05:00
topjohnwu
6f12c08204 Use ordered map to store CPIO entries 2019-02-22 22:53:20 -05:00
topjohnwu
cb8fe70734 Modernize CPIO code 2019-02-22 02:56:18 -05:00
topjohnwu
69d10b747a Directly use FDT headers for detection 2019-02-21 05:24:05 -05:00
topjohnwu
da3394f34e Move image parsing out of header searching 2019-02-21 05:08:38 -05:00
topjohnwu
b4c2a9f49f More macro magic 2019-02-21 04:14:52 -05:00
topjohnwu
7cee77f57a Some C++ magic to make code cleaner 2019-02-21 02:54:37 -05:00
topjohnwu
f28bd1972f Adjust LZ4F block size 2019-02-21 00:52:47 -05:00
topjohnwu
0f92d1de1b Fix bzip2 decompression 2019-02-20 20:53:54 -05:00
topjohnwu
e59c5c8780 Modernize compress and decompress 2019-02-20 20:49:26 -05:00
kirill9617
86d8026301 Update format.h
GZIP magic is \x1f\x8b\x08 not \x1f\x8b\x08\x00
2019-02-20 03:53:41 -05:00
topjohnwu
d67b827338 Rewrite compression with OOP 2019-02-20 02:10:06 -05:00
topjohnwu
660e0dc09a Fix MagiskHide unmount daemon
Close #1101
2019-02-19 01:50:41 -05:00
John Wu
3ebc886f8a Make sure PPID exists 2019-02-18 03:45:01 -05:00
vvb2060
5b54ef840a Skip same mount namespace 2019-02-18 03:45:01 -05:00
linar10
c08b0d4974 update pl 2019-02-18 03:33:25 -05:00
dark-basic
7d652afd87 Small Changes. Very Small.
I hope it does not have to be adjusted again. Since the text does not appear completely. (Only appears when the rotation of the screen is horizontal)
2019-02-18 03:33:08 -05:00
corsicanu
0f61c627b1 Support deodexed ROM on Pie (Samsung)
- cc @abrahamgcc
2019-02-18 03:32:56 -05:00
lindwurm
7126648404 l10n: ja: Update Japanese translations
Signed-off-by: lindwurm <lindwurm.q@gmail.com>
2019-02-18 03:32:27 -05:00
lindwurm
4a5e2dc9c7 l10n: ja: Fix strings for UI
* strings "インストール", "タップしてSafetyNetチェックを開始" are too long to show in button

Signed-off-by: lindwurm <lindwurm.q@gmail.com>
2019-02-18 03:32:27 -05:00
HemanthJabalpuri
10613686ed Fix bootloop when removing system SuperSU in <5.0 2019-02-18 03:31:16 -05:00
topjohnwu
17ab55115a Add newlines before rc scripts
Based on #1090, thanks to @shakalaca. Close #1090, close #1086
2019-02-18 03:30:30 -05:00
topjohnwu
2708c74ebe Add O_CLOEXEC to opens 2019-02-18 03:25:21 -05:00
topjohnwu
50ff11405f Swap out inotify fd before adding watch targets 2019-02-18 03:18:11 -05:00
topjohnwu
31a27838f5 Fix help message for magisk 2019-02-18 03:09:01 -05:00
topjohnwu
2f1b0fe57f Remove unused scripts 2019-02-18 03:08:40 -05:00
topjohnwu
692f893e1f Monitor /data/system/packages.xml
Reinstalling system apps as data creates tons of issues.
Calling pm path <pkg> is extremely expensive and doesn't work in post-fs-data.
Parse through packages.xml to get APK path and UID at the same time.
As a bonus, we don't need to traverse /data/app for packages anymore.
2019-02-18 03:05:13 -05:00
topjohnwu
14aa6041ec Use a better function to read through files 2019-02-17 22:30:23 -05:00
topjohnwu
fb55fe184c Hide useless error message 2019-02-16 03:41:37 -05:00
topjohnwu
6412bfc7b5 Only care about the first event 2019-02-16 02:49:36 -05:00
topjohnwu
3c56f38229 Change most logs to debug logs 2019-02-16 02:30:48 -05:00
topjohnwu
f4f2274c60 Auto reinstall system apps on hide list
Since we are parsing through /data/app/ to find target APKs for
monitoring, system apps will not be covered in this case.
Automatically reinstall system apps as if they received an update
and refresh the monitor target after it's done.

As a bonus, use RAII idioms for locking pthread_mutex_t.
2019-02-16 02:24:35 -05:00
topjohnwu
19ee189468 Separate scripting code 2019-02-15 20:45:05 -05:00
topjohnwu
a19c7215d2 Better nice name 2019-02-15 04:31:39 -05:00
topjohnwu
8b84039f1f Run service scripts actually in parallel 2019-02-15 01:30:47 -05:00
topjohnwu
9430dbb96c Make sure logcat process does not become a zombie 2019-02-14 17:36:18 -05:00
topjohnwu
4872df6a46 Support old APK paths and don't crash when not match 2019-02-14 16:38:28 -05:00
topjohnwu
014105f0a0 Bring back log dumping 2019-02-14 04:27:30 -05:00
topjohnwu
b106d1c501 Fix stupid mistake 2019-02-14 04:24:30 -05:00
topjohnwu
99db0672b4 Minor MagiskHide adjustments
- Fail fast on unsupported systems
- Show proper fail message on unsupported systems
- inotify_fd shall be swapped out before closing to prevent
  the proc_monitor thread to read from incomplete inotify fd
2019-02-14 04:08:05 -05:00
topjohnwu
d584360de2 More optimized APK traversal 2019-02-14 00:52:59 -05:00
topjohnwu
4eed6794c7 More MagiskHide optimizations
- Use a general procfs traversal function with callbacks
- Much better functions for killing processes
2019-02-13 20:16:26 -05:00
topjohnwu
c66cabd80f Several MagiskHide improvements
- Directly get UID instead of traversing /data/data everytime
- Use /data/user_de/0 instead of /data/data on Android 7.0+
- Update hide_uid set incrementally when adding/initializing targets
- Guard hide_uid set with the same lock as hide_list vector
- Do not add GMS package into database; only add to in-memory list
2019-02-13 06:16:26 -05:00
Park Ju Hyung
24da3485bd Hardcode GMS unstable to MagiskHide
With the new detection method, it is impossible to check for components.

Remove additional checks for components and simply hardcode string to
proc_monitor.cpp and query cmdline to see if it's GMS unstable.

This addresses wasted resources on applying custom namespace
on all GMS processes.

Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com>
2019-02-12 23:39:57 -05:00
Park Ju Hyung
7384d2d330 Completely rework MagiskHide
Previous MagiskHide detects new app launches via listening through logcat
and filtering launch info messages.

This is extremely inefficient and prone to cause multiple issues both
theoratically and practically.

Rework this by using inotify to detect open() syscalls to target APKs.

This also solves issues related to Zygote-forked caching mechanisms such as
OnePlus OxygenOS' embryo.

Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com>
2019-02-12 23:39:57 -05:00
topjohnwu
e5940168fe Fix string resources 2019-02-12 17:03:20 -05:00
Igor Sorocean
6855baf0f8 Update romanian translation 2019-02-12 17:01:11 -05:00
Fatih Fırıncı
dfd16e8fef Update strings.xml 2019-02-12 17:01:01 -05:00
Remita Amine
98a36819bc Limit Boot Image selection dialog to File Managers 2019-02-12 17:00:48 -05:00
marciozomb13
de8bc9ca9d Update strings.xml
PT-rBR update
2019-02-12 17:00:32 -05:00
topjohnwu
c137f2de4f Remove SDK 16 support completely
Android 4.1 init miss several significant features Magisk reply on,
so the final decision is to forget about it in the future.

Pull minSdkVersion of Magisk Manager back to 17 and remove some
unnecessary adjustments done for SDK 16
2019-02-12 16:58:05 -05:00
topjohnwu
0f55fcafe8 Migrate EXT4 images instead of removing them 2019-02-12 16:13:31 -05:00
topjohnwu
ed027ec3ee Refactor build flags 2019-02-12 05:17:02 -05:00
topjohnwu
b3fd79cbb9 Add more cmdline options and specify as internal API 2019-02-12 04:05:51 -05:00
topjohnwu
ed4df87b57 Remove imgtool 2019-02-12 02:44:46 -05:00
topjohnwu
1321f097b8 Remove usage of magisk.img
Mounting ext4 images causes tons of issues, such as unmountable with broken F2FS drivers.
Resizing is also very complicated and does not work properly on all devices.
Each step in either measuring free space, resizing, and shrinking the image is a
point of failure, and either step's failure could cause the module system completely broken.

The new method is to directly store modules into /data/adb/modules, and for module installation
on boot /data/adb/modules_update. Several compatibility layers has been done: the new path is
bind mounted to the old path (/sbin/.magisk/img), and the helper functions in util_functions.sh
will now transparently make existing modules install to the new location without any changes.

MagiskHide is also updated to unmount module files stored in this new location.
2019-02-12 02:14:57 -05:00
Aidan Holland
cfa28f0c4a Empty Exceptions 2019-02-11 17:14:29 -05:00
topjohnwu
ab47b717b1 Reorganize scripts 2019-02-11 17:14:07 -05:00
Aidan Holland
65ebb0d2f8 Misc Formatting
* PEP8 and linting
* empty exceptions
2019-02-11 03:18:15 -05:00
Rom
49640ce03a Update French translation 2019-02-11 03:06:44 -05:00
vvb2060
e05cdc83f3 fix extract_bb 2019-02-11 02:35:04 -05:00
topjohnwu
992a9ea2f9 Fix EMUI 9 detection 2019-02-11 02:26:15 -05:00
topjohnwu
228351fc13 Prevent bootloop on non system-as-root devices
Close #1058
2019-02-10 13:51:41 -05:00
topjohnwu
8a5b6f2b86 Block all signals in daemon 2019-02-10 04:18:50 -05:00
topjohnwu
71ecbb3af3 Clean/refactor includes 2019-02-10 03:57:51 -05:00
topjohnwu
5746614ccf Keep track of timestamps and skip old logs 2019-02-10 03:16:52 -05:00
topjohnwu
3a422c3f15 Remove magisklogd, use threads and BlockingQueue 2019-02-10 01:05:19 -05:00
topjohnwu
b3242322fd Harden socket verification
- Do not allow connections to magiskd from binaries other than the one started the server
- Do not allow connections to magisklogd without root access
2019-02-09 15:02:46 -05:00
Licaon_Kter
9826640ae6 f-strings need Python 3.6
...this is a blocker for F-Droid since Debian Strech has only Python 3.5.x
2019-02-09 05:35:05 -05:00
topjohnwu
1f5267204b Better cmdline parsing 2019-02-09 05:23:56 -05:00
topjohnwu
ed25e1bbd6 Directly inject services into init.rc 2019-02-09 02:48:05 -05:00
topjohnwu
c8491d008f Move sbin overlay creation to magiskinit 2019-02-09 01:51:46 -05:00
Mevlüt TOPÇU
08e3405394 Update strings.xml 2019-02-07 00:45:51 -05:00
dark-basic
4ebfa07186 Some adjustments - Update Strings
I changed some words for their synonyms. In order to verify how it behaves on screens less than 5 inches.
(Some changes were made, since several devices I have, some words do not appear yet having space)
2019-02-07 00:45:43 -05:00
Erfan Abdi
6698c189fc Support non-ext4 filesystem for vendor and system
Signed-off-by: Erfan Abdi <erfangplus@gmail.com>
2019-02-07 00:45:30 -05:00
topjohnwu
f0639390aa Update dependencies 2019-02-07 00:37:40 -05:00
topjohnwu
bbdfed2d5a Fix strings 2019-02-05 00:52:52 -05:00
Madis
7f4daa2c50 Estonian update 2019-02-05 00:50:53 -05:00
Gozzwip
baf9b67b35 Creating Azerbaijani file 2019-02-05 00:50:40 -05:00
Mevlüt TOPÇU
caf73b0b36 Update Turksih language
Merge please

Thank you
2019-02-05 00:50:28 -05:00
Furkan
acf87c2794 fix one word 2019-02-05 00:50:17 -05:00
topjohnwu
7f5f6b54fb Ask for fingerprint before deleting policy
Close #1038
2019-02-04 23:08:06 -05:00
topjohnwu
a08eb8a446 Hide install button by default
Close #1037
2019-02-04 22:56:45 -05:00
915 changed files with 42438 additions and 41692 deletions

8
.gitattributes vendored
View File

@@ -11,8 +11,14 @@
*.bat text eol=crlf
# Denote all files that are truly binary and should not be modified.
chromeos/** binary
tools/** binary
*.jar binary
*.exe binary
*.apk binary
*.png binary
*.jpg binary
*.ttf binary
# Help GitHub detect languages
native/jni/external/** linguist-vendored
native/jni/systemproperties/** linguist-language=C++

5
.gitignore vendored
View File

@@ -2,8 +2,8 @@ out
*.zip
*.jks
*.apk
config.prop
update.sh
/config.prop
/update.sh
# Built binaries
native/out
@@ -15,4 +15,3 @@ native/out
/.idea
/build
/captures
.externalNativeBuild

9
.gitmodules vendored
View File

@@ -19,3 +19,12 @@
[submodule "nanopb"]
path = native/jni/external/nanopb
url = https://github.com/nanopb/nanopb.git
[submodule "mincrypt"]
path = native/jni/external/mincrypt
url = https://github.com/topjohnwu/mincrypt.git
[submodule "pcre"]
path = native/jni/external/pcre
url = https://android.googlesource.com/platform/external/pcre
[submodule "termux-elf-cleaner"]
path = tools/termux-elf-cleaner
url = https://github.com/termux/termux-elf-cleaner.git

View File

@@ -1,41 +1,60 @@
# Magisk
[Downloads](https://github.com/topjohnwu/Magisk/releases) | [Documentation](https://topjohnwu.github.io/Magisk/) | [XDA Thread](https://forum.xda-developers.com/apps/magisk/official-magisk-v7-universal-systemless-t3473445)
[Downloads](https://github.com/topjohnwu/Magisk/releases) \| [Documentation](https://topjohnwu.github.io/Magisk/) \| [XDA Thread](https://forum.xda-developers.com/apps/magisk/official-magisk-v7-universal-systemless-t3473445)
## Introduction
Magisk is a suite of open source tools for customizing Android, supporting devices higher than Android 4.2 (API 17). It covers the fundamental parts for Android customization: root, boot scripts, SELinux patches, AVB2.0 / dm-verity / forceencrypt removals etc.
Furthermore, Magisk provides a **Systemless Interface** to alter the system (or vendor) arbitrarily while the actual partitions stay completely intact. With its systemless nature along with several other hacks, Magisk can hide modifications from nearly any system integrity verifications used in banking apps, corporation monitoring apps, game cheat detections, and most importantly [Google's SafetyNet API](https://developer.android.com/training/safetynet/index.html).
Furthermore, Magisk provides a **Systemless Interface** to alter the system (or vendor) arbitrarily while the actual partitions stay completely intact. With its systemless nature along with several other hacks, Magisk can almost perfectly hide modifications within userspace. Note that since 2020.3, the CTS check of [Google's SafetyNet API](https://developer.android.com/training/safetynet/index.html) will **NOT** pass.
## Bug Reports
**Make sure to install the latest [Canary Build](https://forum.xda-developers.com/apps/magisk/dev-magisk-canary-channel-bleeding-edge-t3839337) before reporting any bugs!** **DO NOT** report bugs that is already fixed upstream. Follow the instructions in the [Canary Channel XDA Thread](https://forum.xda-developers.com/apps/magisk/dev-magisk-canary-channel-bleeding-edge-t3839337), and report a bug either by opening an issue on GitHub or directly in the thread.
**Only reports using debug canary builds will be accepted.** \
Access canary builds by upgrading to either canary Magisk Manager:
- [Canary Manager (Release)](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-release.apk)
- [Canary Manager (Debug)](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-debug.apk)
For installation issues, upload both boot image and install logs. \
For Magisk issues, upload boot logcat or dmesg. \
For Magisk Manager crashes, record and upload the logcat when the crash occurs.
## Building Environment Requirements
1. Python 3: run `build.py` script
2. Java Development Kit (JDK) 8: Compile Magisk Manager and sign zips
3. Latest Android SDK: set `ANDROID_HOME` environment variable to the path to Android SDK
4. Android NDK: Install NDK along with SDK (`$ANDROID_HOME/ndk-bundle`), or optionally specify a custom path `ANDROID_NDK_HOME`
5. (Windows Only) Python package Colorama: Install with `pip install colorama`, used for ANSI color codes
- Python 3: run `build.py` script
- Java Development Kit (JDK) 8: Compile Magisk Manager and sign zips
- Latest Android SDK: set `ANDROID_HOME` environment variable to the path to Android SDK
- Android NDK: Install NDK along with SDK (`$ANDROID_HOME/ndk-bundle`), or optionally specify a custom path `ANDROID_NDK_HOME`
- (Windows Only) Python package Colorama: Install with `pip install colorama`, used for ANSI color codes
## Building Notes and Instructions
1. Clone sources with submodules: `git clone --recurse-submodules https://github.com/topjohnwu/Magisk.git`
2. Building is supported on macOS, Linux, and Windows. Official releases are built and tested with [FrankeNDK](https://github.com/topjohnwu/FrankeNDK); point `ANDROID_NDK_HOME` to FrankeNDK if you want to use it for compiling.
3. Set configurations in `config.prop`. A sample file `config.prop.sample` is provided as an example.
4. Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h`
5. By default, `build.py` build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (via the `-r, --release` flag), you need a Java Keystore file `release-key.jks` (only `JKS` format is supported) to sign APKs and zips. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
- Clone sources with submodules: `git clone --recurse-submodules https://github.com/topjohnwu/Magisk.git`
- Building is supported on macOS, Linux, and Windows. Official releases are built and tested with [FrankeNDK](https://github.com/topjohnwu/FrankeNDK); point `ANDROID_NDK_HOME` to FrankeNDK if you want to use it for compiling.
- Set configurations in `config.prop`. A sample file `config.prop.sample` is provided as an example.
- Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h`
- By default, `build.py` build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (via the `-r, --release` flag), you need a Java Keystore file `release-key.jks` (only `JKS` format is supported) to sign APKs and zips. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
## Translations
Default string resources for Magisk Manager and its stub APK are located here:
- `app/src/main/res/values/strings.xml`
- `stub/src/main/res/values/strings.xml`
Translate each and place them in the respective locations (`[module]/src/main/res/values-[lang]/strings.xml`).
## License
```
Magisk, including all git submodules are free software:
you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
Magisk, including all git submodules are free software:
you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
```
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

2
app-core/.gitignore vendored
View File

@@ -1,2 +0,0 @@
/build
src/main/res/raw/util_functions.sh

View File

@@ -1,21 +0,0 @@
apply plugin: 'com.android.library'
android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
api project(':net')
api project(':signing')
api 'org.kamranzafar:jtar:2.3'
def libsuVersion = '2.3.0'
api "com.github.topjohnwu.libsu:core:${libsuVersion}"
api "com.github.topjohnwu.libsu:io:${libsuVersion}"
}

View File

@@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.topjohnwu.magisk.core" >
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
</manifest>

View File

@@ -1,61 +0,0 @@
package com.topjohnwu.magisk;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Build;
import android.preference.PreferenceManager;
import com.topjohnwu.magisk.core.BuildConfig;
import com.topjohnwu.magisk.database.MagiskDB;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import java.util.concurrent.ThreadPoolExecutor;
public class App extends Application {
public static App self;
public static ThreadPoolExecutor THREAD_POOL;
// Global resources
public SharedPreferences prefs;
public MagiskDB mDB;
public RepoDatabaseHelper repoDB;
static {
Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER | Shell.FLAG_USE_MAGISK_BUSYBOX);
Shell.Config.verboseLogging(BuildConfig.DEBUG);
Shell.Config.addInitializers(RootUtils.class);
Shell.Config.setTimeout(2);
THREAD_POOL = (ThreadPoolExecutor) AsyncTask.THREAD_POOL_EXECUTOR;
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
self = this;
Context de = this;
if (Build.VERSION.SDK_INT >= 24) {
de = createDeviceProtectedStorageContext();
de.moveSharedPreferencesFrom(this, PreferenceManager.getDefaultSharedPreferencesName(base));
}
prefs = PreferenceManager.getDefaultSharedPreferences(de);
mDB = new MagiskDB(this);
Networking.init(this);
LocaleManager.setLocale(this);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LocaleManager.setLocale(this);
}
}

View File

@@ -1,372 +0,0 @@
package com.topjohnwu.magisk;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Xml;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileInputStream;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.IOException;
public class Config {
// Current status
public static String magiskVersionString;
public static int magiskVersionCode = -1;
private static boolean magiskHide;
// Update Info
public static String remoteMagiskVersionString;
public static int remoteMagiskVersionCode = -1;
public static String magiskLink;
public static String magiskNoteLink;
public static String magiskMD5;
public static String remoteManagerVersionString;
public static int remoteManagerVersionCode = -1;
public static String managerLink;
public static String managerNoteLink;
public static String uninstallerLink;
// Install flags
public static boolean keepVerity = false;
public static boolean keepEnc = false;
public static boolean recovery = false;
public static int suLogTimeout = 14;
public static class Key {
// su configs
public static final String ROOT_ACCESS = "root_access";
public static final String SU_MULTIUSER_MODE = "multiuser_mode";
public static final String SU_MNT_NS = "mnt_ns";
public static final String SU_MANAGER = "requester";
public static final String SU_REQUEST_TIMEOUT = "su_request_timeout";
public static final String SU_AUTO_RESPONSE = "su_auto_response";
public static final String SU_NOTIFICATION = "su_notification";
public static final String SU_REAUTH = "su_reauth";
public static final String SU_FINGERPRINT = "su_fingerprint";
// prefs
public static final String CHECK_UPDATES = "check_update";
public static final String UPDATE_CHANNEL = "update_channel";
public static final String CUSTOM_CHANNEL = "custom_channel";
public static final String BOOT_FORMAT = "boot_format";
public static final String UPDATE_SERVICE_VER = "update_service_version";
public static final String MAGISKHIDE = "magiskhide";
public static final String COREONLY = "disable";
public static final String LOCALE = "locale";
public static final String DARK_THEME = "dark_theme";
public static final String ETAG_KEY = "ETag";
public static final String REPO_ORDER = "repo_order";
public static final String SHOW_SYSTEM_APP = "show_system";
}
public static class Value {
public static final int STABLE_CHANNEL = 0;
public static final int BETA_CHANNEL = 1;
public static final int CUSTOM_CHANNEL = 2;
public static final int ROOT_ACCESS_DISABLED = 0;
public static final int ROOT_ACCESS_APPS_ONLY = 1;
public static final int ROOT_ACCESS_ADB_ONLY = 2;
public static final int ROOT_ACCESS_APPS_AND_ADB = 3;
public static final int MULTIUSER_MODE_OWNER_ONLY = 0;
public static final int MULTIUSER_MODE_OWNER_MANAGED = 1;
public static final int MULTIUSER_MODE_USER = 2;
public static final int NAMESPACE_MODE_GLOBAL = 0;
public static final int NAMESPACE_MODE_REQUESTER = 1;
public static final int NAMESPACE_MODE_ISOLATE = 2;
public static final int NO_NOTIFICATION = 0;
public static final int NOTIFICATION_TOAST = 1;
public static final int SU_PROMPT = 0;
public static final int SU_AUTO_DENY = 1;
public static final int SU_AUTO_ALLOW = 2;
public static final int[] TIMEOUT_LIST = {0, -1, 10, 20, 30, 60};
public static final int ORDER_NAME = 0;
public static final int ORDER_DATE = 1;
}
private static Bundle defs = new Bundle();
static {
/* Set default configurations */
// prefs int
defs.putInt(Key.REPO_ORDER, Value.ORDER_DATE);
// prefs string int
defs.putInt(Key.SU_REQUEST_TIMEOUT, 10);
defs.putInt(Key.SU_AUTO_RESPONSE, Value.SU_PROMPT);
defs.putInt(Key.SU_NOTIFICATION, Value.NOTIFICATION_TOAST);
defs.putInt(Key.UPDATE_CHANNEL, Value.STABLE_CHANNEL);
// prefs bool
defs.putBoolean(Key.CHECK_UPDATES, true);
// defs.putBoolean(Key.DARK_THEME, false);
// defs.putBoolean(Key.SU_REAUTH, false);
// defs.putBoolean(Key.MAGISKHIDE, false);
// defs.putBoolean(Key.COREONLY, false);
// defs.putBoolean(Key.SHOW_SYSTEM_APP, false);
// prefs string
defs.putString(Key.CUSTOM_CHANNEL, "");
defs.putString(Key.BOOT_FORMAT, ".img");
defs.putString(Key.LOCALE, "");
// defs.putString(Key.ETAG_KEY, null);
// db int
defs.putInt(Key.ROOT_ACCESS, Value.ROOT_ACCESS_APPS_AND_ADB);
defs.putInt(Key.SU_MNT_NS, Value.NAMESPACE_MODE_REQUESTER);
defs.putInt(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY);
// db bool
// defs.putBoolean(Key.SU_FINGERPRINT, false);
// db strings
// defs.putString(Key.SU_MANAGER, null);
}
public static void loadMagiskInfo() {
try {
magiskVersionString = ShellUtils.fastCmd("magisk -v").split(":")[0];
magiskVersionCode = Integer.parseInt(ShellUtils.fastCmd("magisk -V"));
magiskHide = Shell.su("magiskhide --status").exec().isSuccess();
} catch (NumberFormatException ignored) {}
}
public static void export() {
// Flush prefs to disk
App app = App.self;
app.prefs.edit().commit();
File xml = new File(app.getFilesDir().getParent() + "/shared_prefs",
app.getPackageName() + "_preferences.xml");
Shell.su(Utils.fmt("cat %s > /data/user/0/%s", xml, Const.MANAGER_CONFIGS)).exec();
}
public static void initialize() {
SharedPreferences pref = App.self.prefs;
SharedPreferences.Editor editor = pref.edit();
SuFile config = new SuFile("/data/user/0/" + Const.MANAGER_CONFIGS);
if (config.exists()) {
try {
SuFileInputStream is = new SuFileInputStream(config);
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(is, "UTF-8");
parser.nextTag();
parser.require(XmlPullParser.START_TAG, null, "map");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG)
continue;
String key = parser.getAttributeValue(null, "name");
String value = parser.getAttributeValue(null, "value");
switch (parser.getName()) {
case "string":
parser.require(XmlPullParser.START_TAG, null, "string");
editor.putString(key, parser.nextText());
parser.require(XmlPullParser.END_TAG, null, "string");
break;
case "boolean":
parser.require(XmlPullParser.START_TAG, null, "boolean");
editor.putBoolean(key, Boolean.parseBoolean(value));
parser.nextTag();
parser.require(XmlPullParser.END_TAG, null, "boolean");
break;
case "int":
parser.require(XmlPullParser.START_TAG, null, "int");
editor.putInt(key, Integer.parseInt(value));
parser.nextTag();
parser.require(XmlPullParser.END_TAG, null, "int");
break;
case "long":
parser.require(XmlPullParser.START_TAG, null, "long");
editor.putLong(key, Long.parseLong(value));
parser.nextTag();
parser.require(XmlPullParser.END_TAG, null, "long");
break;
case "float":
parser.require(XmlPullParser.START_TAG, null, "int");
editor.putFloat(key, Float.parseFloat(value));
parser.nextTag();
parser.require(XmlPullParser.END_TAG, null, "int");
break;
default:
parser.next();
}
}
} catch (IOException | XmlPullParserException e) {
e.printStackTrace();
}
editor.remove(Key.ETAG_KEY);
editor.apply();
editor = pref.edit();
config.delete();
}
// Set to defaults if not set
setDefs(pref, editor,
Key.SU_REQUEST_TIMEOUT, Key.SU_AUTO_RESPONSE, Key.ROOT_ACCESS,
Key.SU_MNT_NS, Key.SU_NOTIFICATION, Key.DARK_THEME,
Key.CHECK_UPDATES, Key.UPDATE_CHANNEL, Key.REPO_ORDER);
// These settings are from actual device state
editor.putBoolean(Key.MAGISKHIDE, magiskHide)
.putBoolean(Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists())
.putInt(Key.UPDATE_SERVICE_VER, Const.UPDATE_SERVICE_VER)
.apply();
}
private static final int PREF_INT = 0;
private static final int PREF_STR_INT = 1;
private static final int PREF_BOOL = 2;
private static final int PREF_STR = 3;
private static final int DB_INT = 4;
private static final int DB_BOOL = 5;
private static final int DB_STR = 6;
private static int getConfigType(String key) {
switch (key) {
case Key.REPO_ORDER:
return PREF_INT;
case Key.SU_REQUEST_TIMEOUT:
case Key.SU_AUTO_RESPONSE:
case Key.SU_NOTIFICATION:
case Key.UPDATE_CHANNEL:
return PREF_STR_INT;
case Key.DARK_THEME:
case Key.SU_REAUTH:
case Key.CHECK_UPDATES:
case Key.MAGISKHIDE:
case Key.COREONLY:
case Key.SHOW_SYSTEM_APP:
return PREF_BOOL;
case Key.CUSTOM_CHANNEL:
case Key.BOOT_FORMAT:
case Key.LOCALE:
case Key.ETAG_KEY:
return PREF_STR;
case Key.ROOT_ACCESS:
case Key.SU_MNT_NS:
case Key.SU_MULTIUSER_MODE:
return DB_INT;
case Key.SU_FINGERPRINT:
return DB_BOOL;
case Key.SU_MANAGER:
return DB_STR;
default:
throw new IllegalArgumentException();
}
}
@SuppressWarnings("unchecked")
public static <T> T get(String key) {
App app = App.self;
switch (getConfigType(key)) {
case PREF_INT:
return (T) (Integer) app.prefs.getInt(key, defs.getInt(key));
case PREF_STR_INT:
return (T) (Integer) Utils.getPrefsInt(app.prefs, key, defs.getInt(key));
case PREF_BOOL:
return (T) (Boolean) app.prefs.getBoolean(key, defs.getBoolean(key));
case PREF_STR:
return (T) app.prefs.getString(key, defs.getString(key));
case DB_INT:
return (T) (Integer) app.mDB.getSettings(key, defs.getInt(key));
case DB_BOOL:
return (T) (Boolean) (app.mDB.getSettings(key, defs.getBoolean(key) ? 1 : 0) != 0);
case DB_STR:
return (T) app.mDB.getStrings(key, defs.getString(key));
}
/* Will never get here (IllegalArgumentException in getConfigType) */
return (T) new Object();
}
public static void set(String key, Object val) {
App app = App.self;
switch (getConfigType(key)) {
case PREF_INT:
app.prefs.edit().putInt(key, (int) val).apply();
break;
case PREF_STR_INT:
app.prefs.edit().putString(key, String.valueOf(val)).apply();
break;
case PREF_BOOL:
app.prefs.edit().putBoolean(key, (boolean) val).apply();
break;
case PREF_STR:
app.prefs.edit().putString(key, (String) val).apply();
break;
case DB_INT:
app.mDB.setSettings(key, (int) val);
break;
case DB_BOOL:
app.mDB.setSettings(key, (boolean) val ? 1 : 0);
break;
case DB_STR:
app.mDB.setStrings(key, (String) val);
break;
}
}
public static void remove(String key) {
App app = App.self;
int def;
switch (getConfigType(key)) {
case PREF_INT:
case PREF_STR_INT:
case PREF_BOOL:
case PREF_STR:
app.prefs.edit().remove(key).apply();
break;
case DB_INT:
def = defs.getInt(key);
app.mDB.setSettings(key, def);
break;
case DB_BOOL:
def = defs.getBoolean(key) ? 1 : 0;
app.mDB.setSettings(key, def);
break;
case DB_STR:
app.mDB.setStrings(key, null);
break;
}
}
private static void setDefs(SharedPreferences pref, SharedPreferences.Editor editor, String... keys) {
for (String key : keys) {
if (pref.contains(key))
continue;
switch (getConfigType(key)) {
case PREF_INT:
editor.putInt(key, defs.getInt(key));
break;
case DB_INT:
case PREF_STR_INT:
editor.putString(key, String.valueOf(defs.getInt(key)));
break;
case PREF_STR:
case DB_STR:
editor.putString(key, defs.getString(key));
break;
case PREF_BOOL:
case DB_BOOL:
editor.putBoolean(key, defs.getBoolean(key));
break;
}
}
}
}

View File

@@ -1,110 +0,0 @@
package com.topjohnwu.magisk;
import android.os.Environment;
import android.os.Process;
import java.io.File;
import java.util.Arrays;
import java.util.List;
public class Const {
public static final String DEBUG_TAG = "MagiskManager";
// APK content
public static final String ANDROID_MANIFEST = "AndroidManifest.xml";
public static final String SU_KEYSTORE_KEY = "su_key";
// Paths
public static final String MAGISK_PATH = "/sbin/.magisk/img";
public static final File EXTERNAL_PATH;
public static File MAGISK_DISABLE_FILE;
static {
MAGISK_DISABLE_FILE = new File("xxx");
EXTERNAL_PATH = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
EXTERNAL_PATH.mkdirs();
}
public static final String BUSYBOX_PATH = "/sbin/.magisk/busybox";
public static final String TMP_FOLDER_PATH = "/dev/tmp";
public static final String MAGISK_LOG = "/cache/magisk.log";
public static final String MANAGER_CONFIGS = ".tmp.magisk.config";
// Versions
public static final int UPDATE_SERVICE_VER = 1;
public static final int MIN_MODULE_VER = 1500;
public static final int SNET_EXT_VER = 12;
/* A list of apps that should not be shown as hide-able */
public static final List<String> HIDE_BLACKLIST = Arrays.asList(
App.self.getPackageName(),
"com.google.android.gms"
);
public static final int USER_ID = Process.myUid() / 100000;
public static final class MAGISK_VER {
public static final int MIN_SUPPORT = 18000;
}
public static class ID {
public static final int UPDATE_SERVICE_ID = 1;
public static final int FETCH_ZIP = 2;
public static final int SELECT_BOOT = 3;
public static final int ONBOOT_SERVICE_ID = 6;
// notifications
public static final int MAGISK_UPDATE_NOTIFICATION_ID = 4;
public static final int APK_UPDATE_NOTIFICATION_ID = 5;
public static final int DTBO_NOTIFICATION_ID = 7;
public static final int HIDE_MANAGER_NOTIFICATION_ID = 8;
public static final String UPDATE_NOTIFICATION_CHANNEL = "update";
public static final String PROGRESS_NOTIFICATION_CHANNEL = "progress";
public static final String CHECK_MAGISK_UPDATE_WORKER_ID = "magisk_update";
}
public static class Url {
private static String getRaw(String where, String name) {
return String.format("https://raw.githubusercontent.com/topjohnwu/magisk_files/%s/%s", where, name);
}
public static final String STABLE_URL = getRaw("master", "stable.json");
public static final String BETA_URL = getRaw("master", "beta.json");
public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed&page=%d";
public static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s";
public static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip";
public static final String PAYPAL_URL = "https://www.paypal.me/topjohnwu";
public static final String PATREON_URL = "https://www.patreon.com/topjohnwu";
public static final String TWITTER_URL = "https://twitter.com/topjohnwu";
public static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
public static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk";
public static final String SNET_URL = getRaw("b66b1a914978e5f4c4bbfd74a59f4ad371bac107", "snet.apk");
public static final String BOOTCTL_URL = getRaw("9c5dfc1b8245c0b5b524901ef0ff0f8335757b77", "bootctl");
}
public static class Key {
// others
public static final String LINK_KEY = "Link";
public static final String IF_NONE_MATCH = "If-None-Match";
// intents
public static final String FROM_SPLASH = "splash";
public static final String OPEN_SECTION = "section";
public static final String INTENT_SET_NAME = "filename";
public static final String INTENT_SET_LINK = "link";
public static final String FLASH_ACTION = "action";
public static final String FLASH_SET_BOOT = "boot";
public static final String BROADCAST_MANAGER_UPDATE = "manager_update";
public static final String BROADCAST_REBOOT = "reboot";
}
public static class Value {
public static final String FLASH_ZIP = "flash";
public static final String PATCH_BOOT = "patch";
public static final String FLASH_MAGISK = "magisk";
public static final String FLASH_INACTIVE_SLOT = "slot";
public static final String UNINSTALL = "uninstall";
}
}

View File

@@ -1,155 +0,0 @@
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.List;
import androidx.annotation.NonNull;
public abstract class BaseModule implements Comparable<BaseModule>, Parcelable {
private String mId, mName, mVersion, mAuthor, mDescription;
private int mVersionCode = -1, minMagiskVersion = -1;
protected BaseModule() {
mId = mName = mVersion = mAuthor = mDescription = "";
}
protected BaseModule(Cursor c) {
mId = nonNull(c.getString(c.getColumnIndex("id")));
mName = nonNull(c.getString(c.getColumnIndex("name")));
mVersion = nonNull(c.getString(c.getColumnIndex("version")));
mVersionCode = c.getInt(c.getColumnIndex("versionCode"));
mAuthor = nonNull(c.getString(c.getColumnIndex("author")));
mDescription = nonNull(c.getString(c.getColumnIndex("description")));
minMagiskVersion = c.getInt(c.getColumnIndex("minMagisk"));
}
protected BaseModule(Parcel p) {
mId = p.readString();
mName = p.readString();
mVersion = p.readString();
mAuthor = p.readString();
mDescription = p.readString();
mVersionCode = p.readInt();
minMagiskVersion = p.readInt();
}
@Override
public int compareTo(@NonNull BaseModule module) {
return this.getName().toLowerCase().compareTo(module.getName().toLowerCase());
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mId);
dest.writeString(mName);
dest.writeString(mVersion);
dest.writeString(mAuthor);
dest.writeString(mDescription);
dest.writeInt(mVersionCode);
dest.writeInt(minMagiskVersion);
}
private String nonNull(String s) {
return s == null ? "" : s;
}
public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("id", mId);
values.put("name", mName);
values.put("version", mVersion);
values.put("versionCode", mVersionCode);
values.put("author", mAuthor);
values.put("description", mDescription);
values.put("minMagisk", minMagiskVersion);
return values;
}
protected void parseProps(List<String> props) { parseProps(props.toArray(new String[0])); }
protected void parseProps(String[] props) throws NumberFormatException {
for (String line : props) {
String[] prop = line.split("=", 2);
if (prop.length != 2)
continue;
String key = prop[0].trim();
String value = prop[1].trim();
if (key.isEmpty() || key.charAt(0) == '#')
continue;
switch (key) {
case "id":
mId = value;
break;
case "name":
mName = value;
break;
case "version":
mVersion = value;
break;
case "versionCode":
mVersionCode = Integer.parseInt(value);
break;
case "author":
mAuthor = value;
break;
case "description":
mDescription = value;
break;
case "minMagisk":
case "template":
minMagiskVersion = Integer.parseInt(value);
break;
default:
break;
}
}
}
public String getName() {
return mName;
}
public void setName(String name) {
mName = name;
}
public String getVersion() {
return mVersion;
}
public String getAuthor() {
return mAuthor;
}
public String getId() {
return mId;
}
public void setId(String id) {
mId = id;
}
public String getDescription() {
return mDescription;
}
public int getVersionCode() {
return mVersionCode;
}
public int getMinMagiskVersion() {
return minMagiskVersion;
}
}

View File

@@ -1,79 +0,0 @@
package com.topjohnwu.magisk.container;
import android.os.Parcel;
import android.os.Parcelable;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.io.SuFile;
public class Module extends BaseModule {
private SuFile mRemoveFile, mDisableFile, mUpdateFile;
private boolean mEnable, mRemove, mUpdated;
public Module(String path) {
try {
parseProps(Shell.su("dos2unix < " + path + "/module.prop").exec().getOut());
} catch (NumberFormatException ignored) {}
mRemoveFile = new SuFile(path, "remove");
mDisableFile = new SuFile(path, "disable");
mUpdateFile = new SuFile(path, "update");
if (getId().isEmpty()) {
int sep = path.lastIndexOf('/');
setId(path.substring(sep + 1));
}
if (getName().isEmpty()) {
setName(getId());
}
mEnable = !mDisableFile.exists();
mRemove = mRemoveFile.exists();
mUpdated = mUpdateFile.exists();
}
public static final Parcelable.Creator<Module> CREATOR = new Creator<Module>() {
/* It won't be used at any place */
@Override
public Module createFromParcel(Parcel source) {
return null;
}
@Override
public Module[] newArray(int size) {
return null;
}
};
public void createDisableFile() {
mEnable = !mDisableFile.createNewFile();
}
public void removeDisableFile() {
mEnable = mDisableFile.delete();
}
public boolean isEnabled() {
return mEnable;
}
public void createRemoveFile() {
mRemove = mRemoveFile.createNewFile();
}
public void deleteRemoveFile() {
mRemove = !mRemoveFile.delete();
}
public boolean willBeRemoved() {
return mRemove;
}
public boolean isUpdated() {
return mUpdated;
}
}

View File

@@ -1,61 +0,0 @@
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import com.topjohnwu.magisk.utils.Utils;
import androidx.annotation.NonNull;
public class Policy implements Comparable<Policy>{
public static final int INTERACTIVE = 0;
public static final int DENY = 1;
public static final int ALLOW = 2;
public int uid, policy = INTERACTIVE;
public long until;
public boolean logging = true, notification = true;
public String packageName, appName;
public ApplicationInfo info;
public Policy(int uid, PackageManager pm) throws PackageManager.NameNotFoundException {
String[] pkgs = pm.getPackagesForUid(uid);
if (pkgs == null || pkgs.length == 0)
throw new PackageManager.NameNotFoundException();
this.uid = uid;
packageName = pkgs[0];
info = pm.getApplicationInfo(packageName, 0);
appName = Utils.getAppLabel(info, pm);
}
public Policy(ContentValues values, PackageManager pm) throws PackageManager.NameNotFoundException {
uid = values.getAsInteger("uid");
packageName = values.getAsString("package_name");
policy = values.getAsInteger("policy");
until = values.getAsInteger("until");
logging = values.getAsInteger("logging") != 0;
notification = values.getAsInteger("notification") != 0;
info = pm.getApplicationInfo(packageName, 0);
if (info.uid != uid)
throw new PackageManager.NameNotFoundException();
appName = info.loadLabel(pm).toString();
}
public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("uid", uid);
values.put("package_name", packageName);
values.put("policy", policy);
values.put("until", until);
values.put("logging", logging ? 1 : 0);
values.put("notification", notification ? 1 : 0);
return values;
}
@Override
public int compareTo(@NonNull Policy policy) {
return appName.toLowerCase().compareTo(policy.appName.toLowerCase());
}
}

View File

@@ -1,109 +0,0 @@
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Parcel;
import android.os.Parcelable;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Utils;
import java.text.DateFormat;
import java.util.Date;
public class Repo extends BaseModule {
private Date mLastUpdate;
public Repo(String id) {
setId(id);
}
public Repo(Cursor c) {
super(c);
mLastUpdate = new Date(c.getLong(c.getColumnIndex("last_update")));
}
public Repo(Parcel p) {
super(p);
mLastUpdate = new Date(p.readLong());
}
public static final Parcelable.Creator<Repo> CREATOR = new Parcelable.Creator<Repo>() {
@Override
public Repo createFromParcel(Parcel source) {
return new Repo(source);
}
@Override
public Repo[] newArray(int size) {
return new Repo[size];
}
};
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeLong(mLastUpdate.getTime());
}
public void update() throws IllegalRepoException {
String props[] = Utils.dlString(getPropUrl()).split("\\n");
try {
parseProps(props);
} catch (NumberFormatException e) {
throw new IllegalRepoException("Repo [" + getId() + "] parse error: " + e.getMessage());
}
if (getVersionCode() < 0) {
throw new IllegalRepoException("Repo [" + getId() + "] does not contain versionCode");
}
if (getMinMagiskVersion() < Const.MIN_MODULE_VER) {
Logger.debug("Repo [" + getId() + "] is outdated");
}
}
public void update(Date lastUpdate) throws IllegalRepoException {
mLastUpdate = lastUpdate;
update();
}
@Override
public ContentValues getContentValues() {
ContentValues values = super.getContentValues();
values.put("last_update", mLastUpdate.getTime());
return values;
}
public String getZipUrl() {
return String.format(Const.Url.ZIP_URL, getId());
}
public String getPropUrl() {
return String.format(Const.Url.FILE_URL, getId(), "module.prop");
}
public String getDetailUrl() {
return String.format(Const.Url.FILE_URL, getId(), "README.md");
}
public String getLastUpdateString() {
return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(mLastUpdate);
}
public Date getLastUpdate() {
return mLastUpdate;
}
public String getDownloadFilename() {
return Utils.getLegalFilename(getName() + "-" + getVersion() + ".zip");
}
public class IllegalRepoException extends Exception {
IllegalRepoException(String message) {
super(message);
}
}
}

View File

@@ -1,56 +0,0 @@
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import com.topjohnwu.magisk.utils.LocaleManager;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SuLogEntry {
public int fromUid, toUid, fromPid;
public String packageName, appName, command;
public boolean action;
public Date date;
public SuLogEntry(Policy policy) {
fromUid = policy.uid;
packageName = policy.packageName;
appName = policy.appName;
action = policy.policy == Policy.ALLOW;
}
public SuLogEntry(ContentValues values) {
fromUid = values.getAsInteger("from_uid");
packageName = values.getAsString("package_name");
appName = values.getAsString("app_name");
fromPid = values.getAsInteger("from_pid");
command = values.getAsString("command");
toUid = values.getAsInteger("to_uid");
action = values.getAsInteger("action") != 0;
date = new Date(values.getAsLong("time"));
}
public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("from_uid", fromUid);
values.put("package_name", packageName);
values.put("app_name", appName);
values.put("from_pid", fromPid);
values.put("command", command);
values.put("to_uid", toUid);
values.put("action", action ? 1 : 0);
values.put("time", date.getTime());
return values;
}
public String getDateString() {
return DateFormat.getDateInstance(DateFormat.MEDIUM, LocaleManager.locale).format(date);
}
public String getTimeString() {
return new SimpleDateFormat("h:mm a", LocaleManager.locale).format(date);
}
}

View File

@@ -1,64 +0,0 @@
package com.topjohnwu.magisk.container;
import org.kamranzafar.jtar.TarHeader;
import java.io.File;
import java.util.Arrays;
public class TarEntry extends org.kamranzafar.jtar.TarEntry {
public TarEntry(File file, String entryName) {
super(file, entryName);
}
/*
* Workaround missing java.nio.file.attribute.PosixFilePermission
* Simply just assign a default permission to the file
* */
@Override
public void extractTarHeader(String entryName) {
int permissions = file.isDirectory() ? 000755 : 000644;
header = TarHeader.createHeader(entryName, file.length(), file.lastModified() / 1000, file.isDirectory(), permissions);
header.userName = new StringBuffer("");
header.groupName = header.userName;
}
/*
* Rewrite the header to GNU format
* */
@Override
public void writeEntryHeader(byte[] outbuf) {
super.writeEntryHeader(outbuf);
System.arraycopy("ustar \0".getBytes(), 0, outbuf, 257, TarHeader.USTAR_MAGICLEN);
getOctalBytes(header.mode, outbuf, 100, TarHeader.MODELEN);
getOctalBytes(header.userId, outbuf, 108, TarHeader.UIDLEN);
getOctalBytes(header.groupId, outbuf, 116, TarHeader.GIDLEN);
getOctalBytes(header.size, outbuf, 124, TarHeader.SIZELEN);
getOctalBytes(header.modTime, outbuf, 136, TarHeader.MODTIMELEN);
Arrays.fill(outbuf, 148, 148 + TarHeader.CHKSUMLEN, (byte) ' ');
Arrays.fill(outbuf, 329, 329 + TarHeader.USTAR_DEVLEN, (byte) '\0');
Arrays.fill(outbuf, 337, 337 + TarHeader.USTAR_DEVLEN, (byte) '\0');
// Recalculate checksum
getOctalBytes(computeCheckSum(outbuf), outbuf, 148, TarHeader.CHKSUMLEN);
}
/*
* Proper octal to ASCII conversion
* */
private void getOctalBytes(long value, byte[] buf, int offset, int length) {
int idx = length - 1;
buf[offset + idx] = 0;
--idx;
for (long val = value; idx >= 0; --idx) {
buf[offset + idx] = (byte) ((byte) '0' + (byte) (val & 7));
val = val >> 3;
}
}
}

View File

@@ -1,43 +0,0 @@
package com.topjohnwu.magisk.container;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import androidx.annotation.NonNull;
public class ValueSortedMap<K, V extends Comparable<? super V>> extends HashMap<K, V> {
private List<V> sorted = new ArrayList<>();
@NonNull
@Override
public Collection<V> values() {
if (sorted.isEmpty()) {
sorted.addAll(super.values());
Collections.sort(sorted);
}
return sorted;
}
@Override
public V put(K key, V value) {
sorted.clear();
return super.put(key, value);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
sorted.clear();
super.putAll(m);
}
@Override
public V remove(Object key) {
sorted.clear();
return super.remove(key);
}
}

View File

@@ -1,186 +0,0 @@
package com.topjohnwu.magisk.database;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.text.TextUtils;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.container.SuLogEntry;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class MagiskDB {
private static final String POLICY_TABLE = "policies";
private static final String LOG_TABLE = "logs";
private static final String SETTINGS_TABLE = "settings";
private static final String STRINGS_TABLE = "strings";
private PackageManager pm;
public MagiskDB(Context context) {
pm = context.getPackageManager();
}
public void deletePolicy(Policy policy) {
deletePolicy(policy.uid);
}
private List<String> rawSQL(String fmt, Object... args) {
return Shell.su("magisk --sqlite '" + Utils.fmt(fmt, args) + "'").exec().getOut();
}
private List<ContentValues> SQL(String fmt, Object... args) {
List<ContentValues> list = new ArrayList<>();
for (String raw : rawSQL(fmt, args)) {
ContentValues values = new ContentValues();
String[] cols = raw.split("\\|");
for (String col : cols) {
String[] pair = col.split("=", 2);
if (pair.length != 2)
continue;
values.put(pair[0], pair[1]);
}
list.add(values);
}
return list;
}
private String toSQL(ContentValues values) {
StringBuilder keys = new StringBuilder(), vals = new StringBuilder();
keys.append('(');
vals.append("VALUES(");
boolean first = true;
for (Map.Entry<String, Object> entry : values.valueSet()) {
if (!first) {
keys.append(',');
vals.append(',');
} else {
first = false;
}
keys.append(entry.getKey());
vals.append('"');
vals.append(entry.getValue());
vals.append('"');
}
keys.append(')');
vals.append(')');
keys.append(vals);
return keys.toString();
}
public void clearOutdated() {
rawSQL(
"DELETE FROM %s WHERE until > 0 AND until < %d;" +
"DELETE FROM %s WHERE time < %d",
POLICY_TABLE, System.currentTimeMillis() / 1000,
LOG_TABLE, System.currentTimeMillis() - Config.suLogTimeout * 86400000
);
}
public void deletePolicy(String pkg) {
rawSQL("DELETE FROM %s WHERE package_name=\"%s\"", POLICY_TABLE, pkg);
}
public void deletePolicy(int uid) {
rawSQL("DELETE FROM %s WHERE uid=%d", POLICY_TABLE, uid);
}
public Policy getPolicy(int uid) {
List<ContentValues> res =
SQL("SELECT * FROM %s WHERE uid=%d", POLICY_TABLE, uid);
if (!res.isEmpty()) {
try {
return new Policy(res.get(0), pm);
} catch (PackageManager.NameNotFoundException e) {
deletePolicy(uid);
}
}
return null;
}
public void updatePolicy(Policy policy) {
rawSQL("REPLACE INTO %s %s", POLICY_TABLE, toSQL(policy.getContentValues()));
}
public List<Policy> getPolicyList() {
List<Policy> list = new ArrayList<>();
for (ContentValues values : SQL("SELECT * FROM %s WHERE uid/100000=%d", POLICY_TABLE, Const.USER_ID)) {
try {
list.add(new Policy(values, pm));
} catch (PackageManager.NameNotFoundException e) {
deletePolicy(values.getAsInteger("uid"));
}
}
Collections.sort(list);
return list;
}
public List<List<SuLogEntry>> getLogs() {
List<List<SuLogEntry>> ret = new ArrayList<>();
List<SuLogEntry> list = null;
String dateString = null, newString;
for (ContentValues values : SQL("SELECT * FROM %s ORDER BY time DESC", LOG_TABLE)) {
Date date = new Date(values.getAsLong("time"));
newString = DateFormat.getDateInstance(DateFormat.MEDIUM, LocaleManager.locale).format(date);
if (!TextUtils.equals(dateString, newString)) {
dateString = newString;
list = new ArrayList<>();
ret.add(list);
}
list.add(new SuLogEntry(values));
}
return ret;
}
public void addLog(SuLogEntry log) {
rawSQL("INSERT INTO %s %s", LOG_TABLE, toSQL(log.getContentValues()));
}
public void clearLogs() {
rawSQL("DELETE FROM %s", LOG_TABLE);
}
public void setSettings(String key, int value) {
ContentValues data = new ContentValues();
data.put("key", key);
data.put("value", value);
rawSQL("REPLACE INTO %s %s", SETTINGS_TABLE, toSQL(data));
}
public int getSettings(String key, int defaultValue) {
List<ContentValues> res = SQL("SELECT value FROM %s WHERE key=\"%s\"", SETTINGS_TABLE, key);
if (res.isEmpty())
return defaultValue;
return res.get(0).getAsInteger("value");
}
public void setStrings(String key, String value) {
if (value == null) {
rawSQL("DELETE FROM %s WHERE key=\"%s\"", STRINGS_TABLE, key);
return;
}
ContentValues data = new ContentValues();
data.put("key", key);
data.put("value", value);
rawSQL("REPLACE INTO %s %s", STRINGS_TABLE, toSQL(data));
}
public String getStrings(String key, String defaultValue) {
List<ContentValues> res = SQL("SELECT value FROM %s WHERE key=\"%s\"", STRINGS_TABLE, key);
if (res.isEmpty())
return defaultValue;
return res.get(0).getAsString("value");
}
}

View File

@@ -1,113 +0,0 @@
package com.topjohnwu.magisk.database;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.container.Repo;
import java.util.HashSet;
import java.util.Set;
public class RepoDatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VER = 4;
private static final String TABLE_NAME = "repos";
private SQLiteDatabase mDb;
public RepoDatabaseHelper(Context context) {
super(context, "repo.db", null, DATABASE_VER);
mDb = getWritableDatabase();
// Remove outdated repos
mDb.delete(TABLE_NAME, "minMagisk<?", new String[] { String.valueOf(Const.MIN_MODULE_VER) });
}
@Override
public void onCreate(SQLiteDatabase db) {
onUpgrade(db, 0, DATABASE_VER);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion != newVersion) {
// Nuke old DB and create new table
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " +
"(id TEXT, name TEXT, version TEXT, versionCode INT, minMagisk INT, " +
"author TEXT, description TEXT, last_update INT, PRIMARY KEY(id))");
Config.remove(Config.Key.ETAG_KEY);
}
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, 0, DATABASE_VER);
}
public void clearRepo() {
mDb.delete(TABLE_NAME, null, null);
}
public void removeRepo(String id) {
mDb.delete(TABLE_NAME, "id=?", new String[] { id });
}
public void removeRepo(Repo repo) {
removeRepo(repo.getId());
}
public void removeRepo(Iterable<String> list) {
for (String id : list) {
if (id == null) continue;
mDb.delete(TABLE_NAME, "id=?", new String[] { id });
}
}
public void addRepo(Repo repo) {
mDb.replace(TABLE_NAME, null, repo.getContentValues());
}
public Repo getRepo(String id) {
try (Cursor c = mDb.query(TABLE_NAME, null, "id=?", new String[] { id }, null, null, null)) {
if (c.moveToNext()) {
return new Repo(c);
}
}
return null;
}
public Cursor getRawCursor() {
return mDb.query(TABLE_NAME, null, null, null, null, null, null);
}
public Cursor getRepoCursor() {
String orderBy = null;
switch ((int) Config.get(Config.Key.REPO_ORDER)) {
case Config.Value.ORDER_NAME:
orderBy = "name COLLATE NOCASE";
break;
case Config.Value.ORDER_DATE:
orderBy = "last_update DESC";
}
return mDb.query(TABLE_NAME, null, "minMagisk<=? AND minMagisk>=?",
new String[] { String.valueOf(Config.magiskVersionCode), String.valueOf(Const.MIN_MODULE_VER) },
null, null, orderBy);
}
public Set<String> getRepoIDSet() {
HashSet<String> set = new HashSet<>(300);
try (Cursor c = mDb.query(TABLE_NAME, null, null, null, null, null, null)) {
while (c.moveToNext()) {
set.add(c.getString(c.getColumnIndex("id")));
}
}
return set;
}
}

View File

@@ -1,108 +0,0 @@
package com.topjohnwu.magisk.tasks;
import android.os.SystemClock;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.net.Networking;
import com.topjohnwu.net.Request;
import com.topjohnwu.net.ResponseListener;
import com.topjohnwu.superuser.internal.UiThreadHandler;
import org.json.JSONException;
import org.json.JSONObject;
public class CheckUpdates {
private static Request getRequest() {
String url;
switch ((int) Config.get(Config.Key.UPDATE_CHANNEL)) {
case Config.Value.BETA_CHANNEL:
url = Const.Url.BETA_URL;
break;
case Config.Value.CUSTOM_CHANNEL:
url = Config.get(Config.Key.CUSTOM_CHANNEL);
break;
case Config.Value.STABLE_CHANNEL:
default:
url = Const.Url.STABLE_URL;
break;
}
return Networking.get(url);
}
public static void check() {
getRequest().getAsJSONObject(new UpdateListener(null));
}
public static void checkNow(Runnable cb) {
JSONObject json = getRequest().execForJSONObject().getResult();
if (json != null)
new UpdateListener(cb).onResponse(json);
}
private static class UpdateListener implements ResponseListener<JSONObject> {
private Runnable cb;
private long start;
UpdateListener(Runnable callback) {
cb = callback;
start = SystemClock.uptimeMillis();
}
private int getInt(JSONObject json, String name, int defValue) {
if (json == null)
return defValue;
try {
return json.getInt(name);
} catch (JSONException e) {
return defValue;
}
}
private String getString(JSONObject json, String name, String defValue) {
if (json == null)
return defValue;
try {
return json.getString(name);
} catch (JSONException e) {
return defValue;
}
}
private JSONObject getJson(JSONObject json, String name) {
try {
return json.getJSONObject(name);
} catch (JSONException e) {
return null;
}
}
@Override
public void onResponse(JSONObject json) {
JSONObject magisk = getJson(json, "magisk");
Config.remoteMagiskVersionString = getString(magisk, "version", null);
Config.remoteMagiskVersionCode = getInt(magisk, "versionCode", -1);
Config.magiskLink = getString(magisk, "link", null);
Config.magiskNoteLink = getString(magisk, "note", null);
Config.magiskMD5 = getString(magisk, "md5", null);
JSONObject manager = getJson(json, "app");
Config.remoteManagerVersionString = getString(manager, "version", null);
Config.remoteManagerVersionCode = getInt(manager, "versionCode", -1);
Config.managerLink = getString(manager, "link", null);
Config.managerNoteLink = getString(manager, "note", null);
JSONObject uninstaller = getJson(json, "uninstaller");
Config.uninstallerLink = getString(uninstaller, "link", null);
UiThreadHandler.handler.postAtTime(() -> Topic.publish(Topic.UPDATE_CHECK_DONE),
start + 1000 /* Add artificial delay to let UI behave correctly */);
if (cb != null)
cb.run();
}
}
}

View File

@@ -1,85 +0,0 @@
package com.topjohnwu.magisk.tasks;
import android.net.Uri;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import com.topjohnwu.superuser.internal.UiThreadHandler;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
public abstract class FlashZip {
private Uri mUri;
private File tmpFile;
private List<String> console, logs;
public FlashZip(Uri uri, List<String> out, List<String> err) {
mUri = uri;
console = out;
logs = err;
tmpFile = new File(App.self.getCacheDir(), "install.zip");
}
private boolean unzipAndCheck() throws IOException {
ZipUtils.unzip(tmpFile, tmpFile.getParentFile(), "META-INF/com/google/android", true);
return Shell.su("grep -q '#MAGISK' " + new File(tmpFile.getParentFile(), "updater-script"))
.exec().isSuccess();
}
private boolean flash() throws IOException {
console.add("- Copying zip to temp directory");
try (InputStream in = App.self.getContentResolver().openInputStream(mUri);
OutputStream out = new BufferedOutputStream(new FileOutputStream(tmpFile))) {
if (in == null) throw new FileNotFoundException();
InputStream buf= new BufferedInputStream(in);
ShellUtils.pump(buf, out);
} catch (FileNotFoundException e) {
console.add("! Invalid Uri");
throw e;
} catch (IOException e) {
console.add("! Cannot copy to cache");
throw e;
}
try {
if (!unzipAndCheck()) {
console.add("! This zip is not a Magisk Module!");
return false;
}
} catch (IOException e) {
console.add("! Unzip error");
throw e;
}
console.add("- Installing " + Utils.getNameFromUri(App.self, mUri));
return Shell.su("cd " + tmpFile.getParent(),
"BOOTMODE=true sh update-binary dummy 1 " + tmpFile)
.to(console, logs)
.exec().isSuccess();
}
public void exec() {
App.THREAD_POOL.execute(() -> {
boolean success = false;
try {
success = flash();
} catch (IOException ignored) {}
Shell.su("cd /", "rm -rf " + tmpFile.getParent() + " " + Const.TMP_FOLDER_PATH).submit();
boolean finalSuccess = success;
UiThreadHandler.run(() -> onResult(finalSuccess));
});
}
protected abstract void onResult(boolean success);
}

View File

@@ -1,315 +0,0 @@
package com.topjohnwu.magisk.tasks;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.container.TarEntry;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.DownloadProgressListener;
import com.topjohnwu.net.Networking;
import com.topjohnwu.signing.SignBoot;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import com.topjohnwu.superuser.internal.NOPList;
import com.topjohnwu.superuser.internal.UiThreadHandler;
import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileInputStream;
import com.topjohnwu.superuser.io.SuFileOutputStream;
import org.kamranzafar.jtar.TarInputStream;
import org.kamranzafar.jtar.TarOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import androidx.annotation.MainThread;
import androidx.annotation.WorkerThread;
public abstract class MagiskInstaller {
private List<String> console, logs;
protected String srcBoot;
protected File installDir;
private class ProgressLog implements DownloadProgressListener {
private int prev = -1;
private int location;
@Override
public void onProgress(long bytesDownloaded, long totalBytes) {
if (prev < 0) {
location = console.size();
console.add("... 0%");
}
int curr = (int) (100 * bytesDownloaded / totalBytes);
if (prev != curr) {
prev = curr;
console.set(location, "... " + prev + "%");
}
}
}
protected MagiskInstaller() {
console = NOPList.getInstance();
logs = NOPList.getInstance();
}
public MagiskInstaller(List<String> out, List<String> err) {
console = out;
logs = err;
installDir = new File(Utils.getDEContext().getFilesDir().getParent(), "install");
Shell.sh("rm -rf " + installDir).exec();
installDir.mkdirs();
}
protected boolean findImage() {
console.add("- Detecting target image");
srcBoot = ShellUtils.fastCmd("find_boot_image", "echo \"$BOOTIMAGE\"");
if (srcBoot.isEmpty()) {
console.add("! Unable to detect target image");
return false;
}
return true;
}
protected boolean findSecondaryImage() {
String slot = ShellUtils.fastCmd("echo $SLOT");
String target = (TextUtils.equals(slot, "_a") ? "_b" : "_a");
console.add("- Target slot: " + target);
console.add("- Detecting target image");
srcBoot = ShellUtils.fastCmd(
"SLOT=" + target,
"find_boot_image",
"SLOT=" + slot,
"echo \"$BOOTIMAGE\""
);
if (srcBoot.isEmpty()) {
console.add("! Unable to detect target image");
return false;
}
return true;
}
protected boolean extractZip() {
String arch;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS);
arch = abis.contains("x86") ? "x86" : "arm";
} else {
arch = TextUtils.equals(Build.CPU_ABI, "x86") ? "x86" : "arm";
}
console.add("- Device platform: " + Build.CPU_ABI);
File zip = new File(App.self.getCacheDir(), "magisk.zip");
if (!ShellUtils.checkSum("MD5", zip, Config.magiskMD5)) {
console.add("- Downloading zip");
Networking.get(Config.magiskLink)
.setDownloadProgressListener(new ProgressLog())
.execForFile(zip);
} else {
console.add("- Existing zip found");
}
try {
ZipInputStream zi = new ZipInputStream(new BufferedInputStream(
new FileInputStream(zip), (int) zip.length()));
ZipEntry ze;
while ((ze = zi.getNextEntry()) != null) {
if (ze.isDirectory())
continue;
String name = null;
String[] names = { arch + "/", "common/", "META-INF/com/google/android/update-binary" };
for (String n : names) {
if (ze.getName().startsWith(n)) {
name = ze.getName().substring(ze.getName().lastIndexOf('/') + 1);
break;
}
}
if (name == null && ze.getName().startsWith("chromeos/"))
name = ze.getName();
if (name == null)
continue;
File dest;
if (installDir instanceof SuFile) {
dest = new SuFile(installDir, name);
} else {
dest = new File(installDir, name);
}
dest.getParentFile().mkdirs();
try (OutputStream out = new SuFileOutputStream(dest)) {
ShellUtils.pump(zi, out);
}
}
} catch (IOException e) {
console.add("! Cannot unzip zip");
return false;
}
Shell.sh(Utils.fmt("chmod -R 755 %s/*; %s/magiskinit -x magisk %s/magisk",
installDir, installDir, installDir)).exec();
return true;
}
protected boolean copyBoot(Uri bootUri) {
srcBoot = new File(installDir, "boot.img").getPath();
console.add("- Copying image to cache");
// Copy boot image to local
try (InputStream in = App.self.getContentResolver().openInputStream(bootUri);
OutputStream out = new FileOutputStream(srcBoot)) {
if (in == null)
throw new FileNotFoundException();
InputStream src;
if (Utils.getNameFromUri(App.self, bootUri).endsWith(".tar")) {
// Extract boot.img from tar
TarInputStream tar = new TarInputStream(new BufferedInputStream(in));
org.kamranzafar.jtar.TarEntry entry;
while ((entry = tar.getNextEntry()) != null) {
if (entry.getName().equals("boot.img"))
break;
}
src = tar;
} else {
// Direct copy raw image
src = new BufferedInputStream(in);
}
ShellUtils.pump(src, out);
} catch (FileNotFoundException e) {
console.add("! Invalid Uri");
return false;
} catch (IOException e) {
console.add("! Copy failed");
return false;
}
return true;
}
protected boolean patchBoot() {
boolean isSigned;
try (InputStream in = new SuFileInputStream(srcBoot)) {
isSigned = SignBoot.verifySignature(in, null);
if (isSigned) {
console.add("- Boot image is signed with AVB 1.0");
}
} catch (IOException e) {
console.add("! Unable to check signature");
return false;
}
// Patch boot image
if (!Shell.sh(Utils.fmt("cd %s; KEEPFORCEENCRYPT=%b KEEPVERITY=%b " +
"sh update-binary indep boot_patch.sh %s",
installDir, Config.keepEnc, Config.keepVerity, srcBoot))
.to(console, logs).exec().isSuccess())
return false;
Shell.Job job = Shell.sh("mv bin/busybox busybox",
"rm -rf magisk.apk bin boot.img update-binary",
"cd /");
File patched = new File(installDir, "new-boot.img");
if (isSigned) {
console.add("- Signing boot image with test keys");
File signed = new File(installDir, "signed.img");
try (InputStream in = new SuFileInputStream(patched);
OutputStream out = new BufferedOutputStream(new FileOutputStream(signed))) {
SignBoot.doSignature("/boot", in, out, null, null);
} catch (IOException e) {
return false;
}
job.add("mv -f " + signed + " " + patched);
}
job.exec();
return true;
}
protected boolean flashBoot() {
if (!Shell.su(Utils.fmt("direct_install %s %s", installDir, srcBoot))
.to(console, logs).exec().isSuccess())
return false;
if (!Config.keepVerity)
Shell.su("find_dtbo_image", "patch_dtbo_image").to(console, logs).exec();
return true;
}
protected boolean storeBoot() {
File patched = new File(installDir, "new-boot.img");
String fmt = Config.get(Config.Key.BOOT_FORMAT);
File dest = new File(Const.EXTERNAL_PATH, "patched_boot" + fmt);
dest.getParentFile().mkdirs();
OutputStream os;
try {
switch (fmt) {
case ".img.tar":
os = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
((TarOutputStream) os).putNextEntry(new TarEntry(patched, "boot.img"));
break;
default:
case ".img":
os = new BufferedOutputStream(new FileOutputStream(dest));
break;
}
try (InputStream in = new SuFileInputStream(patched)) {
ShellUtils.pump(in, os);
os.close();
}
} catch (IOException e) {
console.add("! Failed to store boot to " + dest);
return false;
}
Shell.sh("rm -f " + patched).exec();
console.add("");
console.add("****************************");
console.add(" Patched image is placed in ");
console.add(" " + dest + " ");
console.add("****************************");
return true;
}
protected boolean postOTA() {
SuFile bootctl = new SuFile("/data/adb/bootctl");
try (InputStream in = Networking.get(Const.Url.BOOTCTL_URL).execForInputStream().getResult();
OutputStream out = new SuFileOutputStream(bootctl)) {
ShellUtils.pump(in, out);
} catch (IOException e) {
e.printStackTrace();
return false;
}
Shell.su("post_ota " + bootctl.getParent()).exec();
console.add("***************************************");
console.add(" Next reboot will boot to second slot!");
console.add("***************************************");
return true;
}
@WorkerThread
protected abstract boolean operations();
@MainThread
protected abstract void onResult(boolean success);
public void exec() {
App.THREAD_POOL.execute(() -> {
boolean b = operations();
UiThreadHandler.run(() -> onResult(b));
});
}
}

View File

@@ -1,176 +0,0 @@
package com.topjohnwu.magisk.tasks;
import android.database.Cursor;
import android.util.Pair;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.net.Request;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.HttpURLConnection;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.Queue;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class UpdateRepos {
private static final DateFormat DATE_FORMAT;
private App app = App.self;
private Set<String> cached;
private Queue<Pair<String, Date>> moduleQueue;
static {
DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private void runTasks(Runnable task) {
Future[] futures = new Future[App.THREAD_POOL.getMaximumPoolSize() - 1];
for (int i = 0; i < futures.length; ++i) {
futures[i] = App.THREAD_POOL.submit(task);
}
for (Future f : futures) {
while (true) {
try {
f.get();
} catch (InterruptedException e) {
continue;
} catch (ExecutionException ignored) {}
break;
}
}
}
/* We sort repos by last push, which means that we only need to check whether the
* first page is updated to determine whether the online repo database is changed
*/
private boolean parsePage(int page) {
Request req = Networking.get(Utils.fmt(Const.Url.REPO_URL, page + 1));
if (page == 0) {
String etag = Config.get(Config.Key.ETAG_KEY);
if (etag != null)
req.addHeaders(Const.Key.IF_NONE_MATCH, etag);
}
Request.Result<JSONArray> res = req.execForJSONArray();
// JSON not updated
if (res.getCode() == HttpURLConnection.HTTP_NOT_MODIFIED)
return false;
// Network error
if (res.getResult() == null) {
cached.clear();
return true;
}
// Current page is the last page
if (res.getResult().length() == 0)
return true;
try {
for (int i = 0; i < res.getResult().length(); i++) {
JSONObject rawRepo = res.getResult().getJSONObject(i);
String id = rawRepo.getString("name");
Date date = DATE_FORMAT.parse(rawRepo.getString("pushed_at"));
moduleQueue.offer(new Pair<>(id, date));
}
} catch (JSONException | ParseException e) {
// Should not happen, but if exception occurs, page load fails
return false;
}
// Update ETAG
if (page == 0) {
String etag = res.getConnection().getHeaderField(Config.Key.ETAG_KEY);
if (etag != null) {
etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1);
Config.set(Config.Key.ETAG_KEY, etag);
}
}
String links = res.getConnection().getHeaderField(Const.Key.LINK_KEY);
return links == null || !links.contains("next") || parsePage(page + 1);
}
private boolean loadPages() {
if (!parsePage(0))
return false;
runTasks(() -> {
while (true) {
Pair<String, Date> pair = moduleQueue.poll();
if (pair == null)
return;
Repo repo = app.repoDB.getRepo(pair.first);
try {
if (repo == null)
repo = new Repo(pair.first);
else
cached.remove(pair.first);
repo.update(pair.second);
app.repoDB.addRepo(repo);
} catch (Repo.IllegalRepoException e) {
Logger.debug(e.getMessage());
app.repoDB.removeRepo(pair.first);
}
}
});
return true;
}
private void fullReload() {
Cursor c = app.repoDB.getRawCursor();
runTasks(() -> {
while (true) {
Repo repo;
synchronized (c) {
if (!c.moveToNext())
return;
repo = new Repo(c);
}
try {
repo.update();
app.repoDB.addRepo(repo);
} catch (Repo.IllegalRepoException e) {
Logger.debug(e.getMessage());
app.repoDB.removeRepo(repo);
}
}
});
}
public void exec(boolean force) {
Topic.reset(Topic.REPO_LOAD_DONE);
App.THREAD_POOL.execute(() -> {
cached = Collections.synchronizedSet(app.repoDB.getRepoIDSet());
moduleQueue = new ConcurrentLinkedQueue<>();
if (loadPages()) {
// The leftover cached means they are removed from online repo
app.repoDB.removeRepo(cached);
} else if (force) {
fullReload();
}
Topic.publish(Topic.REPO_LOAD_DONE);
});
}
public void exec() {
exec(false);
}
}

View File

@@ -1,123 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.CancellationSignal;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import java.security.KeyStore;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@TargetApi(Build.VERSION_CODES.M)
public abstract class FingerprintHelper {
private FingerprintManager manager;
private Cipher cipher;
private CancellationSignal cancel;
public static boolean useFingerprint() {
boolean fp = Config.get(Config.Key.SU_FINGERPRINT);
if (fp && !canUseFingerprint()) {
Config.set(Config.Key.SU_FINGERPRINT, false);
fp = false;
}
return fp;
}
public static boolean canUseFingerprint() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
return false;
KeyguardManager km = App.self.getSystemService(KeyguardManager.class);
FingerprintManager fm = App.self.getSystemService(FingerprintManager.class);
return km.isKeyguardSecure() && fm != null && fm.isHardwareDetected() && fm.hasEnrolledFingerprints();
}
protected FingerprintHelper() throws Exception {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
manager = App.self.getSystemService(FingerprintManager.class);
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey(Const.SU_KEYSTORE_KEY, null);
if (key == null) {
key = generateKey();
}
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
} catch (KeyPermanentlyInvalidatedException e) {
// Only happens on Marshmallow
key = generateKey();
cipher.init(Cipher.ENCRYPT_MODE, key);
}
}
public abstract void onAuthenticationError(int errorCode, CharSequence errString);
public abstract void onAuthenticationHelp(int helpCode, CharSequence helpString);
public abstract void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result);
public abstract void onAuthenticationFailed();
public void authenticate() {
cancel = new CancellationSignal();
FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
manager.authenticate(cryptoObject, cancel, 0, new Callback(), null);
}
public void cancel() {
if (cancel != null)
cancel.cancel();
}
private SecretKey generateKey() throws Exception {
KeyGenerator keygen = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
Const.SU_KEYSTORE_KEY,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setInvalidatedByBiometricEnrollment(false);
}
keygen.init(builder.build());
return keygen.generateKey();
}
private class Callback extends FingerprintManager.AuthenticationCallback {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
FingerprintHelper.this.onAuthenticationError(errorCode, errString);
}
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
FingerprintHelper.this.onAuthenticationHelp(helpCode, helpString);
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
FingerprintHelper.this.onAuthenticationSucceeded(result);
}
@Override
public void onAuthenticationFailed() {
FingerprintHelper.this.onAuthenticationFailed();
}
}
}

View File

@@ -1,18 +0,0 @@
package com.topjohnwu.magisk.utils;
public interface ISafetyNetHelper {
int RESPONSE_ERR = 0x01;
int CONNECTION_FAIL = 0x02;
int BASIC_PASS = 0x10;
int CTS_PASS = 0x20;
void attest();
int getVersion();
interface Callback {
void onResponse(int responseCode);
}
}

View File

@@ -1,152 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.internal.InternalUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import androidx.annotation.StringRes;
public class LocaleManager {
public static Locale locale = Locale.getDefault();
public final static Locale defaultLocale = Locale.getDefault();
public static List<Locale> locales;
public static Locale forLanguageTag(String tag) {
if (Build.VERSION.SDK_INT >= 21) {
return Locale.forLanguageTag(tag);
} else {
String[] tok = tag.split("-");
if (tok.length == 0) {
return new Locale("");
}
String language;
switch (tok[0]) {
case "und":
language = ""; // Undefined
break;
case "fil":
language = "tl"; // Filipino
break;
default:
language = tok[0];
}
if ((language.length() != 2 && language.length() != 3))
return new Locale("");
if (tok.length == 1)
return new Locale(language);
String country = tok[1];
if (country.length() != 2 && country.length() != 3)
return new Locale(language);
return new Locale(language, country);
}
}
public static String toLanguageTag(Locale loc) {
if (Build.VERSION.SDK_INT >= 21) {
return loc.toLanguageTag();
} else {
String language = loc.getLanguage();
String country = loc.getCountry();
String variant = loc.getVariant();
if (language.isEmpty() || !language.matches("\\p{Alpha}{2,8}")) {
language = "und"; // Follow the Locale#toLanguageTag() implementation
} else if (language.equals("iw")) {
language = "he"; // correct deprecated "Hebrew"
} else if (language.equals("in")) {
language = "id"; // correct deprecated "Indonesian"
} else if (language.equals("ji")) {
language = "yi"; // correct deprecated "Yiddish"
}
// ensure valid country code, if not well formed, it's omitted
if (!country.matches("\\p{Alpha}{2}|\\p{Digit}{3}")) {
country = "";
}
// variant subtags that begin with a letter must be at least 5 characters long
if (!variant.matches("\\p{Alnum}{5,8}|\\p{Digit}\\p{Alnum}{3}")) {
variant = "";
}
StringBuilder tag = new StringBuilder(language);
if (!country.isEmpty())
tag.append('-').append(country);
if (!variant.isEmpty())
tag.append('-').append(variant);
return tag.toString();
}
}
public static void setLocale(ContextWrapper wrapper) {
String localeConfig = Config.get(Config.Key.LOCALE);
if (localeConfig.isEmpty()) {
locale = defaultLocale;
} else {
locale = forLanguageTag(localeConfig);
}
Locale.setDefault(locale);
InternalUtils.replaceBaseContext(wrapper, getLocaleContext(locale));
}
public static Context getLocaleContext(Context context, Locale locale) {
if (Build.VERSION.SDK_INT >= 17) {
Configuration config = new Configuration(context.getResources().getConfiguration());
config.setLocale(locale);
return context.createConfigurationContext(config);
} else {
return context;
}
}
public static Context getLocaleContext(Locale locale) {
return getLocaleContext(App.self.getBaseContext(), locale);
}
public static String getString(Locale locale, @StringRes int id) {
return getLocaleContext(locale).getString(id);
}
public static void loadAvailableLocales(@StringRes int compareId) {
if (Build.VERSION.SDK_INT < 17)
return;
Shell.EXECUTOR.execute(() -> {
locales = new ArrayList<>();
HashSet<String> set = new HashSet<>();
Resources res = App.self.getResources();
Locale locale;
// Add default locale
locales.add(Locale.ENGLISH);
set.add(getString(Locale.ENGLISH, compareId));
// Add some special locales
locales.add(Locale.TAIWAN);
set.add(getString(Locale.TAIWAN, compareId));
locale = new Locale("pt", "BR");
locales.add(locale);
set.add(getString(locale, compareId));
// Other locales
for (String s : res.getAssets().getLocales()) {
locale = forLanguageTag(s);
if (set.add(getString(locale, compareId))) {
locales.add(locale);
}
}
Collections.sort(locales, (a, b) -> a.getDisplayName(a).compareTo(b.getDisplayName(b)));
Topic.publish(Topic.LOCALE_FETCH_DONE);
});
}
}

View File

@@ -1,26 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.util.Log;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.core.BuildConfig;
public class Logger {
public static void debug(String line) {
if (BuildConfig.DEBUG)
Log.d(Const.DEBUG_TAG, "DEBUG: " + line);
}
public static void debug(String fmt, Object... args) {
debug(Utils.fmt(fmt, args));
}
public static void error(String line) {
Log.e(Const.DEBUG_TAG, "ERROR: " + line);
}
public static void error(String fmt, Object... args) {
error(Utils.fmt(fmt, args));
}
}

View File

@@ -1,42 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.content.Context;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.core.R;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import com.topjohnwu.superuser.io.SuFile;
import java.io.InputStream;
import androidx.annotation.NonNull;
public class RootUtils extends Shell.Initializer {
public static void rmAndLaunch(String rm, String launch) {
Shell.su(Utils.fmt("(rm_launch %d %s %s)&", Const.USER_ID, rm, launch)).exec();
}
@Override
public boolean onInit(Context context, @NonNull Shell shell) {
Shell.Job job = shell.newJob();
if (shell.isRoot()) {
job.add(context.getResources().openRawResource(R.raw.util_functions))
.add(context.getResources().openRawResource(R.raw.utils));
Const.MAGISK_DISABLE_FILE = new SuFile("/cache/.disable_magisk");
Config.loadMagiskInfo();
} else {
InputStream nonroot = context.getResources().openRawResource(R.raw.nonroot_utils);
job.add(nonroot);
}
job.add("mount_partitions", "get_flags", "run_migrations", "export BOOTMODE=true").exec();
Config.keepVerity = Boolean.parseBoolean(ShellUtils.fastCmd("echo $KEEPVERITY"));
Config.keepEnc = Boolean.parseBoolean(ShellUtils.fastCmd("echo $KEEPFORCEENCRYPT"));
Config.recovery = Boolean.parseBoolean(ShellUtils.fastCmd("echo $RECOVERYMODE"));
return true;
}
}

View File

@@ -1,61 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Bundle;
import android.text.TextUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public abstract class SuConnector {
private LocalSocket socket;
protected DataOutputStream out;
protected DataInputStream in;
protected SuConnector(String name) throws IOException {
socket = new LocalSocket();
socket.connect(new LocalSocketAddress(name, LocalSocketAddress.Namespace.ABSTRACT));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
}
private String readString() throws IOException {
int len = in.readInt();
byte[] buf = new byte[len];
in.readFully(buf);
return new String(buf, "UTF-8");
}
public Bundle readSocketInput() throws IOException {
Bundle bundle = new Bundle();
while (true) {
String name = readString();
if (TextUtils.equals(name, "eof"))
break;
bundle.putString(name, readString());
}
return bundle;
}
public void response() {
try {
onResponse();
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
out.close();
socket.close();
} catch (IOException ignored) { }
}
protected abstract void onResponse() throws IOException;
}

View File

@@ -1,86 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Process;
import android.widget.Toast;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.container.SuLogEntry;
import java.util.Date;
public abstract class SuLogger {
public void handleLogs(Intent intent) {
int fromUid = intent.getIntExtra("from.uid", -1);
if (fromUid < 0) return;
if (fromUid == Process.myUid()) return;
App app = App.self;
PackageManager pm = app.getPackageManager();
Policy policy;
boolean notify;
Bundle data = intent.getExtras();
if (data.containsKey("notify")) {
notify = data.getBoolean("notify");
try {
policy = new Policy(fromUid, pm);
} catch (PackageManager.NameNotFoundException e) {
return;
}
} else {
// Doesn't report whether notify or not, check database ourselves
policy = app.mDB.getPolicy(fromUid);
if (policy == null)
return;
notify = policy.notification;
}
policy.policy = data.getInt("policy", -1);
if (policy.policy < 0)
return;
if (notify)
handleNotify(policy);
SuLogEntry log = new SuLogEntry(policy);
int toUid = intent.getIntExtra("to.uid", -1);
if (toUid < 0) return;
int pid = intent.getIntExtra("pid", -1);
if (pid < 0) return;
String command = intent.getStringExtra("command");
if (command == null) return;
log.toUid = toUid;
log.fromPid = pid;
log.command = command;
log.date = new Date();
app.mDB.addLog(log);
}
private void handleNotify(Policy policy) {
if (policy.notification &&
(int) Config.get(Config.Key.SU_NOTIFICATION) == Config.Value.NOTIFICATION_TOAST)
Utils.toast(getMessage(policy), Toast.LENGTH_SHORT);
}
public void handleNotify(Intent intent) {
int fromUid = intent.getIntExtra("from.uid", -1);
if (fromUid < 0) return;
if (fromUid == Process.myUid()) return;
try {
Policy policy = new Policy(fromUid, App.self.getPackageManager());
policy.policy = intent.getIntExtra("policy", -1);
if (policy.policy >= 0)
handleNotify(policy);
} catch (PackageManager.NameNotFoundException ignored) {}
}
public abstract String getMessage(Policy policy);
}

View File

@@ -1,108 +0,0 @@
package com.topjohnwu.magisk.utils;
import com.topjohnwu.superuser.internal.UiThreadHandler;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashSet;
import java.util.Set;
import androidx.annotation.IntDef;
public class Topic {
public static final int MAGISK_HIDE_DONE = 0;
public static final int MODULE_LOAD_DONE = 1;
public static final int REPO_LOAD_DONE = 2;
public static final int UPDATE_CHECK_DONE = 3;
public static final int LOCALE_FETCH_DONE = 4;
@IntDef({MAGISK_HIDE_DONE, MODULE_LOAD_DONE, REPO_LOAD_DONE,
UPDATE_CHECK_DONE, LOCALE_FETCH_DONE})
@Retention(RetentionPolicy.SOURCE)
public @interface TopicID {}
// We will not dynamically add topics, so use arrays instead of hash tables
private static Store[] topicList = new Store[5];
public static void subscribe(Subscriber sub, @TopicID int... topics) {
for (int topic : topics) {
if (topicList[topic] == null)
topicList[topic] = new Store();
topicList[topic].subscribers.add(sub);
if (topicList[topic].published) {
sub.onPublish(topic, topicList[topic].results);
}
}
}
public static void subscribe(AutoSubscriber sub) {
subscribe(sub, sub.getSubscribedTopics());
}
public static void unsubscribe(Subscriber sub, @TopicID int... topics) {
for (int topic : topics) {
if (topicList[topic] == null)
continue;
topicList[topic].subscribers.remove(sub);
}
}
public static void unsubscribe(AutoSubscriber sub) {
unsubscribe(sub, sub.getSubscribedTopics());
}
public static void publish(@TopicID int topic, Object... results) {
publish(true, topic, results);
}
public static void publish(boolean persist, @TopicID int topic, Object... results) {
if (topicList[topic] == null)
topicList[topic] = new Store();
if (persist) {
topicList[topic].results = results;
topicList[topic].published = true;
}
for (Subscriber sub : topicList[topic].subscribers) {
UiThreadHandler.run(() -> sub.onPublish(topic, results));
}
}
public static void reset(@TopicID int... topics) {
for (int topic : topics) {
if (topicList[topic] == null)
continue;
topicList[topic].published = false;
topicList[topic].results = null;
}
}
public static boolean isPublished(@TopicID int... topics) {
for (int topic : topics) {
if (topicList[topic] == null)
return false;
if (!topicList[topic].published)
return false;
}
return true;
}
public static boolean isPublished(AutoSubscriber sub) {
return isPublished(sub.getSubscribedTopics());
}
private static class Store {
boolean published = false;
Set<Subscriber> subscribers = new HashSet<>();
Object[] results;
}
public interface Subscriber {
void onPublish(int topic, Object[] result);
}
public interface AutoSubscriber extends Subscriber {
@TopicID
int[] getSubscribedTopics();
}
}

View File

@@ -1,127 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.OpenableColumns;
import android.widget.Toast;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.container.ValueSortedMap;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.internal.UiThreadHandler;
import com.topjohnwu.superuser.io.SuFile;
import java.util.Locale;
import java.util.Map;
public class Utils {
public static void toast(CharSequence msg, int duration) {
UiThreadHandler.run(() -> Toast.makeText(App.self, msg, duration).show());
}
public static void toast(int resId, int duration) {
UiThreadHandler.run(() -> Toast.makeText(App.self, resId, duration).show());
}
public static String dlString(String url) {
String s = Networking.get(url).execForString().getResult();
return s == null ? "" : s;
}
public static int getPrefsInt(SharedPreferences prefs, String key, int def) {
return Integer.parseInt(prefs.getString(key, String.valueOf(def)));
}
public static int getPrefsInt(SharedPreferences prefs, String key) {
return getPrefsInt(prefs, key, 0);
}
public static String getNameFromUri(Context context, Uri uri) {
String name = null;
try (Cursor c = context.getContentResolver().query(uri, null, null, null, null)) {
if (c != null) {
int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (nameIndex != -1) {
c.moveToFirst();
name = c.getString(nameIndex);
}
}
}
if (name == null) {
int idx = uri.getPath().lastIndexOf('/');
name = uri.getPath().substring(idx + 1);
}
return name;
}
public static int dpInPx(int dp) {
float scale = App.self.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5);
}
public static String fmt(String fmt, Object... args) {
return String.format(Locale.US, fmt, args);
}
public static String getAppLabel(ApplicationInfo info, PackageManager pm) {
try {
if (info.labelRes > 0 && Build.VERSION.SDK_INT >= 17) {
Resources res = pm.getResourcesForApplication(info);
Configuration config = new Configuration();
config.setLocale(LocaleManager.locale);
res.updateConfiguration(config, res.getDisplayMetrics());
return res.getString(info.labelRes);
}
} catch (Exception ignored) {}
return info.loadLabel(pm).toString();
}
public static String getLegalFilename(CharSequence filename) {
return filename.toString().replace(" ", "_").replace("'", "").replace("\"", "")
.replace("$", "").replace("`", "").replace("*", "").replace("/", "_")
.replace("#", "").replace("@", "").replace("\\", "_");
}
public static void loadModules() {
Topic.reset(Topic.MODULE_LOAD_DONE);
App.THREAD_POOL.execute(() -> {
Map<String, Module> moduleMap = new ValueSortedMap<>();
SuFile path = new SuFile(Const.MAGISK_PATH);
SuFile[] modules = path.listFiles(
(file, name) -> !name.equals("lost+found") && !name.equals(".core"));
for (SuFile file : modules) {
if (file.isFile()) continue;
Module module = new Module(Const.MAGISK_PATH + "/" + file.getName());
moduleMap.put(module.getId(), module);
}
Topic.publish(Topic.MODULE_LOAD_DONE, moduleMap);
});
}
public static boolean showSuperUser() {
return Shell.rootAccess() && (Const.USER_ID == 0 ||
(int) Config.get(Config.Key.SU_MULTIUSER_MODE) !=
Config.Value.MULTIUSER_MODE_OWNER_MANAGED);
}
public static Context getDEContext() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?
App.self.createDeviceProtectedStorageContext() : App.self;
}
public static void reboot() {
Shell.su("/system/bin/reboot" + (Config.recovery ? " recovery" : "")).submit();
}
}

View File

@@ -1,65 +0,0 @@
package com.topjohnwu.magisk.utils;
import com.topjohnwu.signing.JarMap;
import com.topjohnwu.signing.SignAPK;
import com.topjohnwu.superuser.ShellUtils;
import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipUtils {
public static void unzip(File zip, File folder, String path, boolean junkPath) throws IOException {
InputStream in = new BufferedInputStream(new FileInputStream(zip));
unzip(in, folder, path, junkPath);
in.close();
}
public static void unzip(InputStream zip, File folder, String path, boolean junkPath) throws IOException {
try {
ZipInputStream zipfile = new ZipInputStream(zip);
ZipEntry entry;
while ((entry = zipfile.getNextEntry()) != null) {
if (!entry.getName().startsWith(path) || entry.isDirectory()){
// Ignore directories, only create files
continue;
}
String name;
if (junkPath) {
name = entry.getName().substring(entry.getName().lastIndexOf('/') + 1);
} else {
name = entry.getName();
}
File dest = new File(folder, name);
if (!dest.getParentFile().exists() && !dest.getParentFile().mkdirs()) {
dest = new SuFile(folder, name);
dest.getParentFile().mkdirs();
}
try (OutputStream out = new SuFileOutputStream(dest)) {
ShellUtils.pump(zipfile, out);
}
}
}
catch(IOException e) {
e.printStackTrace();
throw e;
}
}
public static void signZip(File input, File output) throws Exception {
try (JarMap map = new JarMap(input, false);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(output))) {
SignAPK.sign(map, out);
}
}
}

View File

@@ -1,13 +0,0 @@
mount_partitions() {
[ "`getprop ro.build.ab_update`" = "true" ] && SLOT=`getprop ro.boot.slot_suffix` || SLOT=
[ "`getprop ro.build.system_root_image`" = "true" ] && SYSTEM_ROOT=true || SYSTEM_ROOT=false
}
get_flags() {
$SYSTEM_ROOT && KEEPVERITY=true || KEEPVERITY=false
[ "`getprop ro.crypto.state`" = "encrypted" ] && KEEPFORCEENCRYPT=true || KEEPFORCEENCRYPT=false
}
run_migrations() {
# NOP
}

View File

@@ -1,108 +0,0 @@
env_check() {
for file in busybox magisk magiskboot magiskinit util_functions.sh boot_patch.sh; do
[ -f /data/adb/magisk/$file ] || return 1
done
return 0
}
fix_env() {
cd /data/adb/magisk
local OLDPATH="$PATH"
PATH=/sbin:/system/bin:/vendor/bin
sh update-binary extract
PATH="$OLDPATH"
./busybox rm -f /sbin/.magisk/busybox/*
/sbin/.magisk/mirror/bin/busybox --install -s /sbin/.magisk/busybox
rm -f update-binary magisk.apk
cd /
}
direct_install() {
rm -rf /data/adb/magisk/* 2>/dev/null
mkdir -p /data/adb/magisk 2>/dev/null
chmod 700 /data/adb
cp -rf $1/* /data/adb/magisk
rm -rf /data/adb/magisk/new-boot.img
echo "- Flashing new boot image"
flash_image $1/new-boot.img $2
if [ $? -ne 0 ]; then
echo "! Insufficient partition size"
return 1
fi
rm -rf $1
return 0
}
mm_patch_dtbo() {
if $KEEPVERITY; then
return 1
else
find_dtbo_image
patch_dtbo_image
fi
}
restore_imgs() {
local SHA1=`grep_prop SHA1 /sbin/.magisk/config`
[ -z $SHA1 ] && local SHA1=`cat /.backup/.sha1`
[ -z $SHA1 ] && return 1
local STOCKBOOT=/data/stock_boot_${SHA1}.img.gz
local STOCKDTBO=/data/stock_dtbo.img.gz
[ -f $STOCKBOOT ] || return 1
find_boot_image
find_dtbo_image
if [ -f $STOCKDTBO -a -b "$DTBOIMAGE" ]; then
flash_image $STOCKDTBO $DTBOIMAGE
fi
if [ -f $STOCKBOOT -a -b "$BOOTIMAGE" ]; then
flash_image $STOCKBOOT $BOOTIMAGE
return 0
fi
return 1
}
post_ota() {
cd $1
chmod 755 bootctl
./bootctl hal-info || return
[ `./bootctl get-current-slot` -eq 0 ] && SLOT_NUM=1 || SLOT_NUM=0
./bootctl set-active-boot-slot $SLOT_NUM
echo "BCTRL=${1}/bootctl;\$BCTRL mark-boot-successful;rm -f \$BCTRL \$0" > post-fs-data.d/post_ota.sh
chmod 755 post-fs-data.d/post_ota.sh
cd /
}
add_hosts_module() {
# Do not touch existing hosts module
[ -d /sbin/.magisk/img/hosts ] && return
cd /sbin/.magisk/img
mkdir -p hosts/system/etc
cat << EOF > hosts/module.prop
id=hosts
name=Systemless Hosts
version=1.0
versionCode=1
author=Magisk Manager
description=Magisk Manager built-in systemless hosts module
minMagisk=17000
EOF
if [ -f .core/hosts ]; then
# Migrate old hosts file to new module
mv -f .core/hosts hosts/system/etc/hosts
else
cp -f /system/etc/hosts hosts/system/etc/hosts
fi
magisk --clone-attr /system/etc/hosts hosts/system/etc/hosts
touch hosts/update
touch hosts/auto_mount
cd /
}
rm_launch() {
db_clean $1
pm uninstall $2
am start -n ${3}/a.c
exit
}

View File

@@ -1,7 +0,0 @@
# Magisk Manager
This repo is no longer an independent component. It is merged into the [Magisk Project](https://github.com/topjohnwu/Magisk).
# Translations
The default (English) strings are mainly in `src/full/res/values/strings.xml`; some are scattered in `src/main/res/values/strings.xml` and `src/stub/res/values/strings.xml`.
Translations are highly appreciated via pull requests here on Github.
Place translated XMLs in the corresponding locale folder.

View File

@@ -1,81 +1,135 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
def configProps = new Properties()
def configPath = project.hasProperty('configPath') ? project.configPath : rootProject.file('config.prop')
configProps.load(new FileInputStream(configPath))
kapt {
correctErrorTypes = true
useBuildCache = true
mapDiagnosticLocations = true
javacOptions {
option("-Xmaxerrs", 1000)
}
}
android {
defaultConfig {
applicationId 'com.topjohnwu.magisk'
vectorDrawables.useSupportLibrary = true
}
multiDexEnabled true
versionName props['appVersion']
versionCode props['appVersionCode'] as Integer
signingConfigs {
config {
storeFile rootProject.file('release-key.jks')
storePassword configProps['keyStorePass']
keyAlias configProps['keyAlias']
keyPassword configProps['keyPass']
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.incremental":"true"]
}
}
}
buildTypes {
debug {
// If keystore exists, sign the APK with custom signature
if (signingConfigs.config.storeFile.exists())
signingConfig signingConfigs.config
}
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
flavorDimensions 'mode'
productFlavors {
full {
versionName configProps['appVersion']
versionCode configProps['appVersionCode'] as Integer
javaCompileOptions {
annotationProcessorOptions {
argument('butterknife.debuggable', 'false')
}
}
}
stub {
versionCode 1
versionName 'stub'
}
dataBinding {
enabled = true
}
lintOptions {
disable 'MissingTranslation'
packagingOptions {
exclude '/META-INF/**'
exclude '/androidsupportmultidexversion.txt'
exclude '/org/bouncycastle/**'
exclude '/kotlin/**'
exclude '/kotlinx/**'
exclude '/okhttp3/**'
}
kotlinOptions {
jvmTarget = '1.8'
}
}
androidExtensions {
experimental = true
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation project(':net')
fullImplementation project(':app-core')
fullImplementation 'ru.noties:markwon:2.0.1'
fullImplementation 'com.caverock:androidsvg-aar:1.3'
implementation project(':shared')
implementation project(':signing')
def androidXVersion = "1.0.0"
implementation 'androidx.core:core:1.0.1'
fullImplementation 'androidx.constraintlayout:constraintlayout:1.1.3'
fullImplementation 'androidx.appcompat:appcompat:1.0.2'
fullImplementation "androidx.preference:preference:${androidXVersion}"
fullImplementation "androidx.recyclerview:recyclerview:${androidXVersion}"
fullImplementation "androidx.cardview:cardview:${androidXVersion}"
fullImplementation "com.google.android.material:material:${androidXVersion}"
fullImplementation 'android.arch.work:work-runtime:1.0.0-beta03'
fullImplementation 'androidx.room:room-runtime:2.0.0'
fullImplementation 'androidx.transition:transition:1.0.1'
implementation 'com.github.topjohnwu:jtar:1.0.0'
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'com.ncapdevi:frag-nav:3.2.0'
implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.6'
def butterKnifeVersion = '10.0.0'
fullImplementation "com.jakewharton:butterknife-runtime:${butterKnifeVersion}"
fullAnnotationProcessor "com.jakewharton:butterknife-compiler:${butterKnifeVersion}"
implementation 'io.reactivex.rxjava2:rxjava:2.2.18'
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:${vKotlin}"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${vKotlin}"
def vBAdapt = '3.1.1'
def bindingAdapter = 'me.tatarka.bindingcollectionadapter2:bindingcollectionadapter'
implementation "${bindingAdapter}:${vBAdapt}"
implementation "${bindingAdapter}-recyclerview:${vBAdapt}"
def vMarkwon = '4.2.1'
implementation "io.noties.markwon:core:${vMarkwon}"
implementation "io.noties.markwon:html:${vMarkwon}"
implementation "io.noties.markwon:image:${vMarkwon}"
implementation 'com.caverock:androidsvg:1.4'
def vLibsu = '2.5.1'
implementation "com.github.topjohnwu.libsu:core:${vLibsu}"
implementation "com.github.topjohnwu.libsu:io:${vLibsu}"
def vKoin = '2.0.1'
implementation "org.koin:koin-core:${vKoin}"
implementation "org.koin:koin-android:${vKoin}"
implementation "org.koin:koin-androidx-viewmodel:${vKoin}"
def vRetrofit = '2.7.1'
implementation "com.squareup.retrofit2:retrofit:${vRetrofit}"
implementation "com.squareup.retrofit2:converter-moshi:${vRetrofit}"
implementation "com.squareup.retrofit2:converter-scalars:${vRetrofit}"
implementation "com.squareup.retrofit2:adapter-rxjava2:${vRetrofit}"
def vOkHttp = '3.12.10'
implementation("com.squareup.okhttp3:okhttp:${vOkHttp}") {
force = true
}
implementation "com.squareup.okhttp3:logging-interceptor:${vOkHttp}"
def vMoshi = '1.10.0-SNAPSHOT'
implementation "com.squareup.moshi:moshi:${vMoshi}"
kapt "com.squareup.moshi:moshi-kotlin-codegen:${vMoshi}"
def vRoom = '2.2.4'
implementation "androidx.room:room-runtime:${vRoom}"
implementation "androidx.room:room-rxjava2:${vRoom}"
kapt "androidx.room:room-compiler:${vRoom}"
def vNav = '2.2.1'
implementation "androidx.navigation:navigation-fragment-ktx:${vNav}"
implementation "androidx.navigation:navigation-ui-ktx:${vNav}"
implementation 'androidx.biometric:biometric:1.0.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-beta01'
implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.fragment:fragment-ktx:1.2.2'
implementation 'androidx.work:work-runtime:2.3.3'
implementation 'androidx.transition:transition:1.3.1'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'com.google.android.material:material:1.2.0-alpha03'
}

View File

@@ -16,31 +16,39 @@
# public *;
#}
# BouncyCastle
-keep,allowoptimization class org.bouncycastle.jcajce.provider.asymmetric.rsa.**SHA1** { *; }
-keep,allowoptimization class org.bouncycastle.jcajce.provider.asymmetric.RSA** { *; }
-keep,allowoptimization class org.bouncycastle.jcajce.provider.digest.SHA1** { *; }
-dontwarn javax.naming.**
# Kotlin
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
public static void checkExpressionValueIsNotNull(...);
public static void checkNotNullExpressionValue(...);
public static void checkReturnedValueIsNotNull(...);
public static void checkFieldIsNotNull(...);
public static void checkParameterIsNotNull(...);
}
# Stubs
-keep class a.* { *; }
# Snet
-keepclassmembers class com.topjohnwu.magisk.utils.ISafetyNetHelper { *; }
-keep,allowobfuscation interface com.topjohnwu.magisk.utils.ISafetyNetHelper$Callback
-keepclassmembers class * implements com.topjohnwu.magisk.utils.ISafetyNetHelper$Callback {
-keepclassmembers class com.topjohnwu.magisk.core.utils.SafetyNetHelper { *; }
-keep,allowobfuscation interface com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback
-keepclassmembers class * implements com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback {
void onResponse(int);
}
# BootSigner
-keepclassmembers class com.topjohnwu.signer.BootSigner { *; }
# Fragments
-keep,allowobfuscation class * extends androidx.fragment.app.Fragment
# SVG
-dontwarn com.caverock.androidsvg.SVGAndroidRenderer
# Strip logging
-assumenosideeffects class com.topjohnwu.magisk.utils.Logger {
public *** debug(...);
# Strip Timber verbose and debug logging
-assumenosideeffects class timber.log.Timber.Tree {
public void v(**);
public void d(**);
}
# Excessive obfuscation
-repackageclasses 'a'
-repackageclasses
-allowaccessmodification
-optimizationpasses 6
# QOL
-dontnote **
-dontwarn com.caverock.androidsvg.**
-dontwarn ru.noties.markwon.**

5
app/res-ids.txt Normal file
View File

@@ -0,0 +1,5 @@
com.topjohnwu.magisk:color/xxxxxxxx = 0x7f010000
com.topjohnwu.magisk:drawable/xxxxxxxx = 0x7f020000
com.topjohnwu.magisk:string/xxxxxxxx = 0x7f030000
com.topjohnwu.magisk:style/xxxxxxxx = 0x7f040000
com.topjohnwu.magisk:xml/xxxxxxxx = 0x7f050000

View File

@@ -1,13 +0,0 @@
package a;
import com.topjohnwu.magisk.utils.PatchAPK;
import com.topjohnwu.signing.BootSigner;
import androidx.annotation.Keep;
@Keep
public class a extends BootSigner {
public static boolean patchAPK(String in, String out, String pkg) {
return PatchAPK.patch(in, out, pkg);
}
}

View File

@@ -1,7 +0,0 @@
package a;
import com.topjohnwu.magisk.MainActivity;
public class b extends MainActivity {
/* stub */
}

View File

@@ -1,7 +0,0 @@
package a;
import com.topjohnwu.magisk.SplashActivity;
public class c extends SplashActivity {
/* stub */
}

View File

@@ -1,7 +0,0 @@
package a;
import com.topjohnwu.magisk.App;
public class e extends App {
/* stub */
}

View File

@@ -1,7 +0,0 @@
package a;
import com.topjohnwu.magisk.FlashActivity;
public class f extends FlashActivity {
/* stub */
}

View File

@@ -1,15 +0,0 @@
package a;
import android.content.Context;
import com.topjohnwu.magisk.components.UpdateCheckService;
import androidx.annotation.NonNull;
import androidx.work.WorkerParameters;
public class g extends w<UpdateCheckService> {
/* Stub */
public g(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
}

View File

@@ -1,7 +0,0 @@
package a;
import com.topjohnwu.magisk.components.GeneralReceiver;
public class h extends GeneralReceiver {
/* stub */
}

View File

@@ -1,7 +0,0 @@
package a;
import com.topjohnwu.magisk.components.DownloadModuleService;
public class j extends DownloadModuleService {
/* stub */
}

View File

@@ -1,7 +0,0 @@
package a;
import com.topjohnwu.magisk.SuRequestActivity;
public class m extends SuRequestActivity {
/* stub */
}

View File

@@ -1,42 +0,0 @@
package a;
import android.content.Context;
import com.topjohnwu.magisk.components.DelegateWorker;
import java.lang.reflect.ParameterizedType;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
public abstract class w<T extends DelegateWorker> extends Worker {
/* Wrapper class to workaround Proguard -keep class * extends Worker */
private T base;
@SuppressWarnings("unchecked")
w(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
try {
base = ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0]).newInstance();
base.setActualWorker(this);
} catch (Exception ignored) {}
}
@NonNull
@Override
public Result doWork() {
if (base == null)
return Result.failure();
return base.doWork();
}
@Override
public void onStopped() {
if (base != null)
base.onStopped();
}
}

View File

@@ -1,27 +0,0 @@
package com.topjohnwu.magisk;
import com.topjohnwu.magisk.components.DownloadModuleService;
import com.topjohnwu.magisk.components.GeneralReceiver;
import com.topjohnwu.magisk.components.UpdateCheckService;
import java.util.HashMap;
import java.util.Map;
public class ClassMap {
private static Map<Class, Class> classMap = new HashMap<>();
static {
classMap.put(App.class, a.e.class);
classMap.put(MainActivity.class, a.b.class);
classMap.put(SplashActivity.class, a.c.class);
classMap.put(FlashActivity.class, a.f.class);
classMap.put(UpdateCheckService.class, a.g.class);
classMap.put(GeneralReceiver.class, a.h.class);
classMap.put(DownloadModuleService.class, a.j.class);
classMap.put(SuRequestActivity.class, a.m.class);
}
public static <T> Class<T> get(Class c) {
return classMap.get(c);
}
}

View File

@@ -1,270 +0,0 @@
package com.topjohnwu.magisk;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.topjohnwu.magisk.adapters.StringListAdapter;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.tasks.FlashZip;
import com.topjohnwu.magisk.tasks.MagiskInstaller;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.CallbackList;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.internal.UiThreadHandler;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindColor;
import butterknife.BindView;
import butterknife.OnClick;
public class FlashActivity extends BaseActivity {
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.button_panel) LinearLayout buttonPanel;
@BindView(R.id.reboot) Button reboot;
@BindView(R.id.recyclerView) RecyclerView rv;
@BindColor(android.R.color.white) int white;
private List<String> console, logs;
@OnClick(R.id.reboot)
void reboot() {
Utils.reboot();
}
@OnClick(R.id.save_logs)
void saveLogs() {
runWithExternalRW(() -> {
Calendar now = Calendar.getInstance();
String filename = String.format(Locale.US,
"magisk_install_log_%04d%02d%02d_%02d%02d%02d.log",
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
File logFile = new File(Const.EXTERNAL_PATH, filename);
try (FileWriter writer = new FileWriter(logFile)) {
for (String s : logs) {
writer.write(s);
writer.write('\n');
}
} catch (IOException e) {
e.printStackTrace();
return;
}
Utils.toast(logFile.getPath(), Toast.LENGTH_LONG);
});
}
@OnClick(R.id.close)
public void close() {
finish();
}
@Override
public void onBackPressed() {
// Prevent user accidentally press back button
}
@Override
public int getDarkTheme() {
return R.style.AppTheme_NoDrawer_Dark;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flash);
new FlashActivity_ViewBinding(this);
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setTitle(R.string.flashing);
}
setFloating();
setFinishOnTouchOutside(false);
if (!Shell.rootAccess())
reboot.setVisibility(View.GONE);
logs = Collections.synchronizedList(new ArrayList<>());
console = new ConsoleList();
rv.setAdapter(new ConsoleAdapter());
Intent intent = getIntent();
Uri uri = intent.getData();
switch (intent.getStringExtra(Const.Key.FLASH_ACTION)) {
case Const.Value.FLASH_ZIP:
new FlashModule(uri).exec();
break;
case Const.Value.UNINSTALL:
new Uninstall(uri).exec();
break;
case Const.Value.FLASH_MAGISK:
new DirectInstall().exec();
break;
case Const.Value.FLASH_INACTIVE_SLOT:
new SecondSlot().exec();
break;
case Const.Value.PATCH_BOOT:
new PatchBoot(uri).exec();
break;
}
}
private class ConsoleAdapter extends StringListAdapter<ConsoleAdapter.ViewHolder> {
ConsoleAdapter() {
super(console, true);
}
@Override
protected int itemLayoutRes() {
return R.layout.list_item_console;
}
@NonNull
@Override
public ViewHolder createViewHolder(@NonNull View v) {
return new ViewHolder(v);
}
class ViewHolder extends StringListAdapter.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
txt.setTextColor(white);
}
@Override
protected int textViewResId() {
return R.id.txt;
}
}
}
private class ConsoleList extends CallbackList<String> {
ConsoleList() {
super(new ArrayList<>());
}
private void updateUI() {
rv.getAdapter().notifyItemChanged(size() - 1);
rv.postDelayed(() -> rv.smoothScrollToPosition(size() - 1), 10);
}
@Override
public void onAddElement(String s) {
logs.add(s);
updateUI();
}
@Override
public String set(int i, String s) {
String ret = super.set(i, s);
UiThreadHandler.run(this::updateUI);
return ret;
}
}
private class FlashModule extends FlashZip {
FlashModule(Uri uri) {
super(uri, console, logs);
}
@Override
protected void onResult(boolean success) {
if (success) {
Utils.loadModules();
} else {
console.add("! Installation failed");
reboot.setVisibility(View.GONE);
}
buttonPanel.setVisibility(View.VISIBLE);
}
}
private class Uninstall extends FlashModule {
Uninstall(Uri uri) {
super(uri);
}
@Override
protected void onResult(boolean success) {
if (success)
UiThreadHandler.handler.postDelayed(Shell.su("pm uninstall " + getPackageName())::exec, 3000);
else
super.onResult(false);
}
}
private abstract class BaseInstaller extends MagiskInstaller {
BaseInstaller() {
super(console, logs);
}
@Override
protected void onResult(boolean success) {
if (success) {
console.add("- All done!");
} else {
Shell.sh("rm -rf " + installDir).submit();
console.add("! Installation failed");
reboot.setVisibility(View.GONE);
}
buttonPanel.setVisibility(View.VISIBLE);
}
}
private class DirectInstall extends BaseInstaller {
@Override
protected boolean operations() {
return findImage() && extractZip() && patchBoot() && flashBoot();
}
}
private class SecondSlot extends BaseInstaller {
@Override
protected boolean operations() {
return findSecondaryImage() && extractZip() && patchBoot() && flashBoot() && postOTA();
}
}
private class PatchBoot extends BaseInstaller {
private Uri uri;
PatchBoot(Uri u) {
uri = u;
}
@Override
protected boolean operations() {
return copyBoot(uri) && extractZip() && patchBoot() && storeBoot();
}
}
}

View File

@@ -1,201 +0,0 @@
package com.topjohnwu.magisk;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.google.android.material.navigation.NavigationView;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.fragments.LogFragment;
import com.topjohnwu.magisk.fragments.MagiskFragment;
import com.topjohnwu.magisk.fragments.MagiskHideFragment;
import com.topjohnwu.magisk.fragments.ModulesFragment;
import com.topjohnwu.magisk.fragments.ReposFragment;
import com.topjohnwu.magisk.fragments.SettingsFragment;
import com.topjohnwu.magisk.fragments.SuperuserFragment;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.widget.Toolbar;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import butterknife.BindView;
public class MainActivity extends BaseActivity
implements NavigationView.OnNavigationItemSelectedListener, Topic.Subscriber {
private final Handler mDrawerHandler = new Handler();
private int mDrawerItem;
private static boolean fromShortcut = false;
@BindView(R.id.toolbar) public Toolbar toolbar;
@BindView(R.id.drawer_layout) DrawerLayout drawer;
@BindView(R.id.nav_view) NavigationView navigationView;
private float toolbarElevation;
@Override
public int getDarkTheme() {
return R.style.AppTheme_Dark;
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
if (!getIntent().getBooleanExtra(Const.Key.FROM_SPLASH, false)) {
startActivity(new Intent(this, ClassMap.get(SplashActivity.class)));
finish();
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MainActivity_ViewBinding(this);
setSupportActionBar(toolbar);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.magisk, R.string.magisk) {
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
super.onDrawerSlide(drawerView, 0); // this disables the arrow @ completed tate
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, 0); // this disables the animation
}
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
toolbarElevation = toolbar.getElevation();
}
drawer.addDrawerListener(toggle);
toggle.syncState();
if (savedInstanceState == null) {
String section = getIntent().getStringExtra(Const.Key.OPEN_SECTION);
fromShortcut = section != null;
navigate(section);
}
navigationView.setNavigationItemSelectedListener(this);
}
@Override
protected void onResume() {
super.onResume();
checkHideSection();
}
@Override
public void onBackPressed() {
if (drawer.isDrawerOpen(navigationView)) {
drawer.closeDrawer(navigationView);
} else if (mDrawerItem != R.id.magisk && !fromShortcut) {
navigate(R.id.magisk);
} else {
finish();
}
}
@Override
public boolean onNavigationItemSelected(@NonNull final MenuItem menuItem) {
mDrawerHandler.removeCallbacksAndMessages(null);
mDrawerHandler.postDelayed(() -> navigate(menuItem.getItemId()), 250);
drawer.closeDrawer(navigationView);
return true;
}
@Override
public void onPublish(int topic, Object[] result) {
recreate();
}
public void checkHideSection() {
Menu menu = navigationView.getMenu();
menu.findItem(R.id.magiskhide).setVisible(Shell.rootAccess() &&
(boolean) Config.get(Config.Key.MAGISKHIDE));
menu.findItem(R.id.modules).setVisible(Shell.rootAccess() && Config.magiskVersionCode >= 0);
menu.findItem(R.id.downloads).setVisible(Networking.checkNetworkStatus(this)
&& Shell.rootAccess() && Config.magiskVersionCode >= 0);
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
menu.findItem(R.id.superuser).setVisible(Utils.showSuperUser());
}
public void navigate(String item) {
int itemId = R.id.magisk;
if (item != null) {
switch (item) {
case "superuser":
itemId = R.id.superuser;
break;
case "modules":
itemId = R.id.modules;
break;
case "downloads":
itemId = R.id.downloads;
break;
case "magiskhide":
itemId = R.id.magiskhide;
break;
case "log":
itemId = R.id.log;
break;
case "settings":
itemId = R.id.settings;
break;
}
}
navigate(itemId);
}
public void navigate(int itemId) {
mDrawerItem = itemId;
navigationView.setCheckedItem(itemId);
switch (itemId) {
case R.id.magisk:
fromShortcut = false;
displayFragment(new MagiskFragment(), true);
break;
case R.id.superuser:
displayFragment(new SuperuserFragment(), true);
break;
case R.id.modules:
displayFragment(new ModulesFragment(), true);
break;
case R.id.downloads:
displayFragment(new ReposFragment(), true);
break;
case R.id.magiskhide:
displayFragment(new MagiskHideFragment(), true);
break;
case R.id.log:
displayFragment(new LogFragment(), false);
break;
case R.id.settings:
displayFragment(new SettingsFragment(), true);
break;
}
}
private void displayFragment(@NonNull Fragment navFragment, boolean setElevation) {
supportInvalidateOptionsMenu();
getSupportFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.content_frame, navFragment)
.commitNow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
toolbar.setElevation(setElevation ? toolbarElevation : 0);
}
}
}

View File

@@ -1,90 +0,0 @@
package com.topjohnwu.magisk;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.TextUtils;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.tasks.UpdateRepos;
import com.topjohnwu.magisk.uicomponents.Notifications;
import com.topjohnwu.magisk.uicomponents.Shortcuts;
import com.topjohnwu.magisk.utils.AppUtils;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import androidx.appcompat.app.AlertDialog;
public class SplashActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Shell.getShell(shell -> {
if (Config.magiskVersionCode > 0 &&
Config.magiskVersionCode < Const.MAGISK_VER.MIN_SUPPORT) {
new AlertDialog.Builder(this)
.setTitle(R.string.unsupport_magisk_title)
.setMessage(R.string.unsupport_magisk_message)
.setNegativeButton(R.string.ok, null)
.setOnDismissListener(dialog -> finish())
.show();
} else {
initAndStart();
}
});
}
private void initAndStart() {
String pkg = Config.get(Config.Key.SU_MANAGER);
if (pkg != null && getPackageName().equals(BuildConfig.APPLICATION_ID)) {
Config.remove(Config.Key.SU_MANAGER);
Shell.su("pm uninstall " + pkg).submit();
}
if (TextUtils.equals(pkg, getPackageName())) {
try {
// We are the manager, remove com.topjohnwu.magisk as it could be malware
getPackageManager().getApplicationInfo(BuildConfig.APPLICATION_ID, 0);
Shell.su("pm uninstall " + BuildConfig.APPLICATION_ID).submit();
} catch (PackageManager.NameNotFoundException ignored) {}
}
// Dynamic detect all locales
LocaleManager.loadAvailableLocales(R.string.app_changelog);
// Set default configs
Config.initialize();
// Create notification channel on Android O
Notifications.setup(this);
// Schedule periodic update checks
AppUtils.scheduleUpdateCheck();
// Setup shortcuts
Shortcuts.setup(this);
// Create repo database
app.repoDB = new RepoDatabaseHelper(this);
// Magisk working as expected
if (Shell.rootAccess() && Config.magiskVersionCode > 0) {
// Load modules
Utils.loadModules();
// Load repos
if (Networking.checkNetworkStatus(this))
new UpdateRepos().exec();
}
Intent intent = new Intent(this, ClassMap.get(MainActivity.class));
intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION));
intent.putExtra(Const.Key.FROM_SPLASH, true);
intent.putExtra(BaseActivity.INTENT_PERM, getIntent().getStringExtra(BaseActivity.INTENT_PERM));
startActivity(intent);
finish();
}
}

View File

@@ -1,235 +0,0 @@
package com.topjohnwu.magisk;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import com.topjohnwu.magisk.utils.SuConnector;
import com.topjohnwu.magisk.utils.Utils;
import java.io.IOException;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import butterknife.BindView;
public class SuRequestActivity extends BaseActivity {
@BindView(R.id.su_popup) LinearLayout suPopup;
@BindView(R.id.timeout) Spinner timeout;
@BindView(R.id.app_icon) ImageView appIcon;
@BindView(R.id.app_name) TextView appNameView;
@BindView(R.id.package_name) TextView packageNameView;
@BindView(R.id.grant_btn) Button grant_btn;
@BindView(R.id.deny_btn) Button deny_btn;
@BindView(R.id.fingerprint) ImageView fingerprintImg;
@BindView(R.id.warning) TextView warning;
private SuConnector connector;
private Policy policy;
private CountDownTimer timer;
private FingerprintHelper fingerprintHelper;
private SharedPreferences timeoutPrefs;
@Override
public int getDarkTheme() {
return R.style.SuRequest_Dark;
}
@Override
public void finish() {
if (timer != null)
timer.cancel();
if (fingerprintHelper != null)
fingerprintHelper.cancel();
super.finish();
}
@Override
public void onBackPressed() {
if (policy != null) {
handleAction(Policy.DENY);
} else {
finish();
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
PackageManager pm = getPackageManager();
app.mDB.clearOutdated();
timeoutPrefs = Utils.getDEContext().getSharedPreferences("su_timeout", 0);
// Get policy
Intent intent = getIntent();
try {
String socketName = intent.getStringExtra("socket");
connector = new SuConnector(socketName) {
@Override
protected void onResponse() throws IOException {
out.writeInt(policy.policy);
}
};
Bundle bundle = connector.readSocketInput();
int uid = Integer.parseInt(bundle.getString("uid"));
policy = app.mDB.getPolicy(uid);
if (policy == null) {
policy = new Policy(uid, pm);
}
} catch (IOException | PackageManager.NameNotFoundException e) {
e.printStackTrace();
finish();
return;
}
// Never allow com.topjohnwu.magisk (could be malware)
if (TextUtils.equals(policy.packageName, BuildConfig.APPLICATION_ID)) {
finish();
return;
}
switch ((int) Config.get(Config.Key.SU_AUTO_RESPONSE)) {
case Config.Value.SU_AUTO_DENY:
handleAction(Policy.DENY, 0);
return;
case Config.Value.SU_AUTO_ALLOW:
handleAction(Policy.ALLOW, 0);
return;
case Config.Value.SU_PROMPT:
default:
}
// If not interactive, response directly
if (policy.policy != Policy.INTERACTIVE) {
handleAction();
return;
}
setContentView(R.layout.activity_request);
new SuRequestActivity_ViewBinding(this);
appIcon.setImageDrawable(policy.info.loadIcon(pm));
appNameView.setText(policy.appName);
packageNameView.setText(policy.packageName);
if (Build.VERSION.SDK_INT >= 17) {
warning.setCompoundDrawablesRelativeWithIntrinsicBounds(
AppCompatResources.getDrawable(this, R.drawable.ic_warning), null, null, null);
} else {
warning.setCompoundDrawablesWithIntrinsicBounds(
AppCompatResources.getDrawable(this, R.drawable.ic_warning), null, null, null);
}
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.allow_timeout, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
timeout.setAdapter(adapter);
timeout.setSelection(timeoutPrefs.getInt(policy.packageName, 0));
timer = new CountDownTimer((int) Config.get(Config.Key.SU_REQUEST_TIMEOUT) * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
deny_btn.setText(getString(R.string.deny_with_str, "(" + millisUntilFinished / 1000 + ")"));
}
@Override
public void onFinish() {
deny_btn.setText(getString(R.string.deny_with_str, "(0)"));
handleAction(Policy.DENY);
}
};
boolean useFP = FingerprintHelper.useFingerprint();
if (useFP) {
try {
fingerprintHelper = new FingerprintHelper() {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
warning.setText(errString);
}
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
warning.setText(helpString);
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
handleAction(Policy.ALLOW);
}
@Override
public void onAuthenticationFailed() {
warning.setText(R.string.auth_fail);
}
};
fingerprintHelper.authenticate();
} catch (Exception e) {
e.printStackTrace();
useFP = false;
}
}
if (!useFP) {
grant_btn.setOnClickListener(v -> {
handleAction(Policy.ALLOW);
timer.cancel();
});
grant_btn.requestFocus();
}
grant_btn.setVisibility(useFP ? View.GONE : View.VISIBLE);
fingerprintImg.setVisibility(useFP ? View.VISIBLE : View.GONE);
deny_btn.setOnClickListener(v -> {
handleAction(Policy.DENY);
timer.cancel();
});
suPopup.setOnClickListener(v -> cancelTimeout());
timeout.setOnTouchListener((v, event) -> cancelTimeout());
timer.start();
}
private boolean cancelTimeout() {
timer.cancel();
deny_btn.setText(getString(R.string.deny));
return false;
}
private void handleAction() {
connector.response();
finish();
}
private void handleAction(int action) {
int pos = timeout.getSelectedItemPosition();
timeoutPrefs.edit().putInt(policy.packageName, pos).apply();
handleAction(action, Config.Value.TIMEOUT_LIST[pos]);
}
private void handleAction(int action, int time) {
policy.policy = action;
if (time >= 0) {
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
app.mDB.updatePolicy(policy);
}
handleAction();
}
}

View File

@@ -1,169 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.internal.UiThreadHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
private static PackageInfo PLATFORM;
private List<PackageInfo> fullList, showList;
private List<String> hideList;
private PackageManager pm;
private boolean showSystem;
public ApplicationAdapter(Context context) {
fullList = showList = Collections.emptyList();
hideList = Collections.emptyList();
pm = context.getPackageManager();
showSystem = false;
if (PLATFORM == null) {
try {
PLATFORM = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
} catch (PackageManager.NameNotFoundException ignored) {}
}
AsyncTask.SERIAL_EXECUTOR.execute(this::loadApps);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_app, parent, false);
return new ViewHolder(v);
}
@WorkerThread
private void loadApps() {
fullList = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
hideList = Shell.su("magiskhide --ls").exec().getOut();
for (Iterator<PackageInfo> i = fullList.iterator(); i.hasNext(); ) {
PackageInfo info = i.next();
if (Const.HIDE_BLACKLIST.contains(info.packageName) ||
/* Do not show disabled apps */
!info.applicationInfo.enabled ||
/* Never show platform apps */
PLATFORM.signatures[0].equals(info.signatures[0])) {
i.remove();
}
}
Collections.sort(fullList, (a, b) -> {
boolean ah = hideList.contains(a.packageName);
boolean bh = hideList.contains(b.packageName);
if (ah == bh) {
return Utils.getAppLabel(a.applicationInfo, pm)
.compareToIgnoreCase(Utils.getAppLabel(b.applicationInfo, pm));
} else if (ah) {
return -1;
} else {
return 1;
}
});
Topic.publish(false, Topic.MAGISK_HIDE_DONE);
}
public void setShowSystem(boolean b) {
showSystem = b;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
ApplicationInfo info = showList.get(position).applicationInfo;
holder.appIcon.setImageDrawable(info.loadIcon(pm));
holder.appName.setText(Utils.getAppLabel(info, pm));
holder.appPackage.setText(info.packageName);
holder.checkBox.setOnCheckedChangeListener(null);
holder.checkBox.setChecked(hideList.contains(info.packageName));
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
if (isChecked) {
Shell.su("magiskhide --add " + info.packageName).submit();
hideList.add(info.packageName);
} else {
Shell.su("magiskhide --rm " + info.packageName).submit();
hideList.remove(info.packageName);
}
});
}
@Override
public int getItemCount() {
return showList.size();
}
private boolean contains(String s, String filter) {
return s.toLowerCase().contains(filter);
}
// Show if have launch intent or not system app
private boolean systemFilter(PackageInfo info) {
if (showSystem)
return true;
return (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
pm.getLaunchIntentForPackage(info.packageName) != null;
}
public void filter(String constraint) {
AsyncTask.SERIAL_EXECUTOR.execute(() -> {
showList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
for (PackageInfo info : fullList) {
if (systemFilter(info))
showList.add(info);
}
} else {
String filter = constraint.toLowerCase();
for (PackageInfo info : fullList) {
if ((contains(Utils.getAppLabel(info.applicationInfo, pm), filter) ||
contains(info.packageName, filter)) && systemFilter(info)) {
showList.add(info);
}
}
}
UiThreadHandler.run(this::notifyDataSetChanged);
});
}
public void refresh() {
AsyncTask.SERIAL_EXECUTOR.execute(this::loadApps);
}
static class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.app_icon) ImageView appIcon;
@BindView(R.id.app_name) TextView appName;
@BindView(R.id.package_name) TextView appPackage;
@BindView(R.id.checkbox) CheckBox checkBox;
ViewHolder(View itemView) {
super(itemView);
new ApplicationAdapter$ViewHolder_ViewBinding(this, itemView);
}
}
}

View File

@@ -1,126 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.material.snackbar.Snackbar;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.uicomponents.SnackbarMaker;
import com.topjohnwu.superuser.Shell;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHolder> {
private final List<Module> mList;
public ModulesAdapter(List<Module> list) {
mList = list;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_module, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Context context = holder.itemView.getContext();
final Module module = mList.get(position);
String version = module.getVersion();
String author = module.getAuthor();
String description = module.getDescription();
String noInfo = context.getString(R.string.no_info_provided);
holder.title.setText(module.getName());
holder.versionName.setText(TextUtils.isEmpty(version) ? noInfo : version);
holder.author.setText(TextUtils.isEmpty(author) ? noInfo : context.getString(R.string.author, author));
holder.description.setText(TextUtils.isEmpty(description) ? noInfo : description);
holder.checkBox.setOnCheckedChangeListener(null);
holder.checkBox.setChecked(module.isEnabled());
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
int snack;
if (isChecked) {
module.removeDisableFile();
snack = R.string.disable_file_removed;
} else {
module.createDisableFile();
snack = R.string.disable_file_created;
}
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
});
holder.delete.setOnClickListener(v -> {
boolean removed = module.willBeRemoved();
int snack;
if (removed) {
module.deleteRemoveFile();
snack = R.string.remove_file_deleted;
} else {
module.createRemoveFile();
snack = R.string.remove_file_created;
}
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
updateDeleteButton(holder, module);
});
if (module.isUpdated()) {
holder.notice.setVisibility(View.VISIBLE);
holder.notice.setText(R.string.update_file_created);
holder.delete.setEnabled(false);
} else {
updateDeleteButton(holder, module);
}
}
private void updateDeleteButton(ViewHolder holder, Module module) {
holder.notice.setVisibility(module.willBeRemoved() ? View.VISIBLE : View.GONE);
if (module.willBeRemoved()) {
holder.delete.setImageResource(R.drawable.ic_undelete);
} else {
holder.delete.setImageResource(R.drawable.ic_delete);
}
}
@Override
public int getItemCount() {
return mList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.title) TextView title;
@BindView(R.id.version_name) TextView versionName;
@BindView(R.id.description) TextView description;
@BindView(R.id.notice) TextView notice;
@BindView(R.id.checkbox) CheckBox checkBox;
@BindView(R.id.author) TextView author;
@BindView(R.id.delete) ImageView delete;
ViewHolder(View itemView) {
super(itemView);
new ModulesAdapter$ViewHolder_ViewBinding(this, itemView);
if (!Shell.rootAccess()) {
checkBox.setEnabled(false);
delete.setEnabled(false);
}
}
}
}

View File

@@ -1,161 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.material.snackbar.Snackbar;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.database.MagiskDB;
import com.topjohnwu.magisk.dialogs.CustomAlertDialog;
import com.topjohnwu.magisk.dialogs.FingerprintAuthDialog;
import com.topjohnwu.magisk.uicomponents.ArrowExpandedViewHolder;
import com.topjohnwu.magisk.uicomponents.ExpandableViewHolder;
import com.topjohnwu.magisk.uicomponents.SnackbarMaker;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.SwitchCompat;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder> {
private List<Policy> policyList;
private MagiskDB dbHelper;
private PackageManager pm;
private boolean[] expandList;
public PolicyAdapter(List<Policy> list, MagiskDB db, PackageManager pm) {
policyList = list;
expandList = new boolean[policyList.size()];
dbHelper = db;
this.pm = pm;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_policy, parent, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Policy policy = policyList.get(position);
holder.settings.setExpanded(expandList[position]);
holder.trigger.setOnClickListener(view -> {
if (holder.settings.isExpanded()) {
holder.settings.collapse();
expandList[position] = false;
} else {
holder.settings.expand();
expandList[position] = true;
}
});
holder.appName.setText(policy.appName);
holder.packageName.setText(policy.packageName);
holder.appIcon.setImageDrawable(policy.info.loadIcon(pm));
holder.notificationSwitch.setOnCheckedChangeListener(null);
holder.loggingSwitch.setOnCheckedChangeListener(null);
holder.masterSwitch.setChecked(policy.policy == Policy.ALLOW);
holder.notificationSwitch.setChecked(policy.notification);
holder.loggingSwitch.setChecked(policy.logging);
holder.masterSwitch.setOnClickListener(v -> {
boolean isChecked = holder.masterSwitch.isChecked();
Runnable r = () -> {
if ((isChecked && policy.policy == Policy.DENY) ||
(!isChecked && policy.policy == Policy.ALLOW)) {
policy.policy = isChecked ? Policy.ALLOW : Policy.DENY;
String message = v.getContext().getString(
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
dbHelper.updatePolicy(policy);
}
};
if (FingerprintHelper.useFingerprint()) {
holder.masterSwitch.setChecked(!isChecked);
new FingerprintAuthDialog((Activity) v.getContext(), () -> {
holder.masterSwitch.setChecked(isChecked);
r.run();
}).show();
} else {
r.run();
}
});
holder.notificationSwitch.setOnCheckedChangeListener((v, isChecked) -> {
if ((isChecked && !policy.notification) ||
(!isChecked && policy.notification)) {
policy.notification = isChecked;
String message = v.getContext().getString(
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
dbHelper.updatePolicy(policy);
}
});
holder.loggingSwitch.setOnCheckedChangeListener((v, isChecked) -> {
if ((isChecked && !policy.logging) ||
(!isChecked && policy.logging)) {
policy.logging = isChecked;
String message = v.getContext().getString(
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
dbHelper.updatePolicy(policy);
}
});
holder.delete.setOnClickListener(v -> new CustomAlertDialog((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) -> {
policyList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, policyList.size());
SnackbarMaker.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
Snackbar.LENGTH_SHORT).show();
dbHelper.deletePolicy(policy);
})
.setNegativeButton(R.string.no_thanks, null)
.setCancelable(true)
.show());
}
@Override
public int getItemCount() {
return policyList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.app_name) TextView appName;
@BindView(R.id.package_name) TextView packageName;
@BindView(R.id.app_icon) ImageView appIcon;
@BindView(R.id.master_switch) SwitchCompat masterSwitch;
@BindView(R.id.notification_switch) SwitchCompat notificationSwitch;
@BindView(R.id.logging_switch) SwitchCompat loggingSwitch;
@BindView(R.id.expand_layout) ViewGroup expandLayout;
@BindView(R.id.arrow) ImageView arrow;
@BindView(R.id.trigger) View trigger;
@BindView(R.id.delete) ImageView delete;
@BindView(R.id.more_info) ImageView moreInfo;
ExpandableViewHolder settings;
public ViewHolder(View itemView) {
super(itemView);
new PolicyAdapter$ViewHolder_ViewBinding(this, itemView);
settings = new ArrowExpandedViewHolder(expandLayout, arrow);
}
}
}

View File

@@ -1,205 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Build;
import android.text.TextUtils;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.components.DownloadModuleService;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.dialogs.CustomAlertDialog;
import com.topjohnwu.magisk.uicomponents.MarkDownWindow;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, ReposAdapter.RepoHolder> {
private static final int UPDATES = 0;
private static final int INSTALLED = 1;
private static final int OTHERS = 2;
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 int getItemCount(int section) {
return repoPairs.get(section).second.size();
}
@Override
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();
String name = repo.getName();
String version = repo.getVersion();
String author = repo.getAuthor();
String description = repo.getDescription();
String noInfo = context.getString(R.string.no_info_provided);
holder.title.setText(TextUtils.isEmpty(name) ? noInfo : name);
holder.versionName.setText(TextUtils.isEmpty(version) ? noInfo : version);
holder.author.setText(TextUtils.isEmpty(author) ? noInfo : context.getString(R.string.author, author));
holder.description.setText(TextUtils.isEmpty(description) ? noInfo : description);
holder.updateTime.setText(context.getString(R.string.updated_on, repo.getLastUpdateString()));
holder.infoLayout.setOnClickListener(v ->
MarkDownWindow.show((BaseActivity) context, null, repo.getDetailUrl()));
holder.downloadImage.setOnClickListener(v -> {
new CustomAlertDialog((BaseActivity) context)
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
.setMessage(context.getString(R.string.repo_install_msg, repo.getDownloadFilename()))
.setCancelable(true)
.setPositiveButton(R.string.install, (d, i) ->
startDownload((BaseActivity) context, repo, true))
.setNeutralButton(R.string.download, (d, i) ->
startDownload((BaseActivity) context, repo, false))
.setNegativeButton(R.string.no_thanks, null)
.show();
});
}
private void startDownload(BaseActivity activity, Repo repo, Boolean install) {
activity.runWithExternalRW(() -> {
Intent intent = new Intent(activity, ClassMap.get(DownloadModuleService.class))
.putExtra("repo", repo).putExtra("install", install);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
activity.startForegroundService(intent);
} else {
activity.startService(intent);
}
});
}
public void notifyDBChanged() {
if (repoCursor != null)
repoCursor.close();
repoCursor = repoDB.getRepoCursor();
filter("");
}
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);
}
}
}
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);
new ReposAdapter$SectionHolder_ViewBinding(this, itemView);
}
}
static class RepoHolder extends RecyclerView.ViewHolder {
@BindView(R.id.title) TextView title;
@BindView(R.id.version_name) TextView versionName;
@BindView(R.id.description) TextView description;
@BindView(R.id.author) TextView author;
@BindView(R.id.info_layout) View infoLayout;
@BindView(R.id.download) ImageView downloadImage;
@BindView(R.id.update_time) TextView updateTime;
RepoHolder(View itemView) {
super(itemView);
new ReposAdapter$RepoHolder_ViewBinding(this, itemView);
}
}
}

View File

@@ -1,96 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
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;
@NonNull
@Override
final public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == SECTION_TYPE)
return onCreateSectionViewHolder(parent);
return onCreateItemViewHolder(parent, viewType);
}
@Override
@SuppressWarnings("unchecked")
final public void onBindViewHolder(@NonNull 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,103 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.app.Activity;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public abstract class StringListAdapter<VH extends StringListAdapter.ViewHolder>
extends RecyclerView.Adapter<VH> {
private RecyclerView rv;
private boolean dynamic;
private int screenWidth;
private int txtWidth = -1;
private int padding;
protected List<String> mList;
public StringListAdapter(List<String> list) {
this(list, false);
}
public StringListAdapter(List<String> list, boolean isDynamic) {
mList = list;
dynamic = isDynamic;
}
@NonNull
@Override
public final VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(itemLayoutRes(), parent, false);
VH vh = createViewHolder(v);
if (txtWidth < 0)
onUpdateTextWidth(vh);
return vh;
}
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
holder.txt.setText(mList.get(position));
holder.txt.getLayoutParams().width = txtWidth;
if (dynamic)
onUpdateTextWidth(holder);
}
protected void onUpdateTextWidth(VH vh) {
if (txtWidth < 0) {
txtWidth = screenWidth - padding;
} else {
vh.txt.measure(0, 0);
int width = vh.txt.getMeasuredWidth();
if (width > txtWidth) {
txtWidth = width;
vh.txt.getLayoutParams().width = txtWidth;
}
}
if (rv.getWidth() != txtWidth + padding)
rv.requestLayout();
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView rv) {
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) rv.getContext()).getWindowManager()
.getDefaultDisplay().getMetrics(displayMetrics);
screenWidth = displayMetrics.widthPixels;
padding = rv.getPaddingLeft() + rv.getPaddingRight();
this.rv = rv;
}
@Override
public final int getItemCount() {
return mList.size();
}
@LayoutRes
protected abstract int itemLayoutRes();
@NonNull
public abstract VH createViewHolder(@NonNull View v);
public static abstract class ViewHolder extends RecyclerView.ViewHolder {
public TextView txt;
public ViewHolder(@NonNull View itemView) {
super(itemView);
txt = itemView.findViewById(textViewResId());
}
@IdRes
protected abstract int textViewResId();
}
}

View File

@@ -1,143 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.SuLogEntry;
import com.topjohnwu.magisk.database.MagiskDB;
import com.topjohnwu.magisk.uicomponents.ExpandableViewHolder;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, SuLogAdapter.LogViewHolder> {
private List<List<SuLogEntry>> logEntries;
private Set<Integer> itemExpanded, sectionExpanded;
private MagiskDB suDB;
public SuLogAdapter(MagiskDB db) {
suDB = db;
logEntries = Collections.emptyList();
sectionExpanded = new HashSet<>();
itemExpanded = new HashSet<>();
}
@Override
public int getSectionCount() {
return logEntries.size();
}
@Override
public int getItemCount(int section) {
return sectionExpanded.contains(section) ? logEntries.get(section).size() : 0;
}
@Override
public SectionHolder onCreateSectionViewHolder(ViewGroup parent) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_sulog_group, parent, false);
return new SectionHolder(v);
}
@Override
public LogViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_sulog, parent, false);
return new LogViewHolder(v);
}
@Override
public void onBindSectionViewHolder(SectionHolder holder, int section) {
SuLogEntry entry = logEntries.get(section).get(0);
holder.arrow.setRotation(sectionExpanded.contains(section) ? 180 : 0);
holder.itemView.setOnClickListener(v -> {
RotateAnimation rotate;
if (sectionExpanded.contains(section)) {
holder.arrow.setRotation(0);
rotate = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
sectionExpanded.remove(section);
notifyItemRangeRemoved(getItemPosition(section, 0), logEntries.get(section).size());
} else {
rotate = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
sectionExpanded.add(section);
notifyItemRangeInserted(getItemPosition(section, 0), logEntries.get(section).size());
}
rotate.setDuration(300);
rotate.setFillAfter(true);
holder.arrow.setAnimation(rotate);
});
holder.date.setText(entry.getDateString());
}
@Override
public void onBindItemViewHolder(LogViewHolder holder, int section, int position) {
SuLogEntry entry = logEntries.get(section).get(position);
int realIdx = getItemPosition(section, position);
holder.expandable.setExpanded(itemExpanded.contains(realIdx));
holder.itemView.setOnClickListener(view -> {
if (holder.expandable.isExpanded()) {
holder.expandable.collapse();
itemExpanded.remove(realIdx);
} else {
holder.expandable.expand();
itemExpanded.add(realIdx);
}
});
Context context = holder.itemView.getContext();
holder.appName.setText(entry.appName);
holder.action.setText(entry.action ? R.string.grant : R.string.deny);
holder.pid.setText(context.getString(R.string.pid, entry.fromPid));
holder.uid.setText(context.getString(R.string.target_uid, entry.toUid));
holder.command.setText(context.getString(R.string.command, entry.command));
holder.time.setText(entry.getTimeString());
}
public void notifyDBChanged() {
logEntries = suDB.getLogs();
itemExpanded.clear();
sectionExpanded.clear();
sectionExpanded.add(0);
notifyDataSetChanged();
}
static class SectionHolder extends RecyclerView.ViewHolder {
@BindView(R.id.date) TextView date;
@BindView(R.id.arrow) ImageView arrow;
SectionHolder(View itemView) {
super(itemView);
new SuLogAdapter$SectionHolder_ViewBinding(this, itemView);
}
}
static class LogViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.app_name) TextView appName;
@BindView(R.id.action) TextView action;
@BindView(R.id.time) TextView time;
@BindView(R.id.pid) TextView pid;
@BindView(R.id.uid) TextView uid;
@BindView(R.id.cmd) TextView command;
@BindView(R.id.expand_layout) ViewGroup expandLayout;
ExpandableViewHolder expandable;
LogViewHolder(View itemView) {
super(itemView);
new SuLogAdapter$LogViewHolder_ViewBinding(this, itemView);
expandable = new ExpandableViewHolder(expandLayout);
}
}
}

View File

@@ -1,41 +0,0 @@
package com.topjohnwu.magisk.adapters;
import java.util.ArrayList;
import java.util.List;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
public class TabFragmentAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList;
private List<String> titleList;
public TabFragmentAdapter(FragmentManager fm) {
super(fm);
fragmentList = new ArrayList<>();
titleList = new ArrayList<>();
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
@Override
public CharSequence getPageTitle(int position) {
return titleList.get(position);
}
public void addTab(Fragment fragment, String title) {
fragmentList.add(fragment);
titleList.add(title);
}
}

View File

@@ -1,157 +0,0 @@
package com.topjohnwu.magisk.components;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.WindowManager;
import android.widget.Toast;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.Topic;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public abstract class BaseActivity extends AppCompatActivity implements Topic.AutoSubscriber {
public static final String INTENT_PERM = "perm_dialog";
private static Runnable grantCallback;
static int[] EMPTY_INT_ARRAY = new int[0];
private ActivityResultListener activityResultListener;
public App app = App.self;
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
@Override
public int[] getSubscribedTopics() {
return EMPTY_INT_ARRAY;
}
@Override
public void onPublish(int topic, Object[] result) {}
@StyleRes
public int getDarkTheme() {
return -1;
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocaleManager.getLocaleContext(base, LocaleManager.locale));
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
Topic.subscribe(this);
if (getDarkTheme() != -1 && (boolean) Config.get(Config.Key.DARK_THEME)) {
setTheme(getDarkTheme());
}
super.onCreate(savedInstanceState);
String[] perms = getIntent().getStringArrayExtra(INTENT_PERM);
if (perms != null)
ActivityCompat.requestPermissions(this, perms, 0);
}
@Override
protected void onDestroy() {
Topic.unsubscribe(this);
super.onDestroy();
}
protected void setFloating() {
boolean isTablet = getResources().getBoolean(R.bool.isTablet);
if (isTablet) {
WindowManager.LayoutParams params = getWindow().getAttributes();
params.height = getResources().getDimensionPixelSize(R.dimen.floating_height);
params.width = getResources().getDimensionPixelSize(R.dimen.floating_width);
params.alpha = 1.0f;
params.dimAmount = 0.6f;
params.flags |= 2;
getWindow().setAttributes(params);
setFinishOnTouchOutside(true);
}
}
public void runWithExternalRW(Runnable callback) {
runWithPermission(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, callback);
}
public void runWithPermission(String[] permissions, Runnable callback) {
runWithPermission(this, permissions, callback);
}
public static void runWithPermission(Context context, String[] permissions, Runnable callback) {
boolean granted = true;
for (String perm : permissions) {
if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED)
granted = false;
}
if (granted) {
Const.EXTERNAL_PATH.mkdirs();
callback.run();
} else {
// Passed in context should be an activity if not granted, need to show dialog!
if (context instanceof BaseActivity) {
grantCallback = callback;
ActivityCompat.requestPermissions((BaseActivity) context, permissions, 0);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (activityResultListener != null)
activityResultListener.onActivityResult(requestCode, resultCode, data);
activityResultListener = null;
}
public void startActivityForResult(Intent intent, int requestCode, ActivityResultListener listener) {
activityResultListener = listener;
super.startActivityForResult(intent, requestCode);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
boolean grant = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED)
grant = false;
}
if (grant) {
if (grantCallback != null) {
grantCallback.run();
}
} else {
Toast.makeText(this, R.string.no_rw_storage, Toast.LENGTH_LONG).show();
}
grantCallback = null;
}
public interface ActivityResultListener {
void onActivityResult(int requestCode, int resultCode, Intent data);
}
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
if (TextUtils.equals(name, getPackageName() + "_preferences"))
return app.prefs;
return super.getSharedPreferences(name, mode);
}
}

View File

@@ -1,55 +0,0 @@
package com.topjohnwu.magisk.components;
import android.content.Intent;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.utils.Topic;
import androidx.fragment.app.Fragment;
import butterknife.Unbinder;
public abstract class BaseFragment extends Fragment implements Topic.AutoSubscriber {
public App app = App.self;
protected Unbinder unbinder = null;
@Override
public void onResume() {
super.onResume();
Topic.subscribe(this);
}
@Override
public void onPause() {
Topic.unsubscribe(this);
super.onPause();
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (unbinder != null)
unbinder.unbind();
}
@Override
public void startActivityForResult(Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, this::onActivityResult);
}
public void startActivityForResult(Intent intent, int requestCode, BaseActivity.ActivityResultListener listener) {
((BaseActivity) requireActivity()).startActivityForResult(intent, requestCode, listener);
}
public void runWithPermission(String[] permissions, Runnable callback) {
((BaseActivity) requireActivity()).runWithPermission(permissions,callback);
}
@Override
public int[] getSubscribedTopics() {
return BaseActivity.EMPTY_INT_ARRAY;
}
@Override
public void onPublish(int topic, Object[] result) {}
}

View File

@@ -1,81 +0,0 @@
package com.topjohnwu.magisk.components;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Topic;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroupAdapter;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder;
import androidx.recyclerview.widget.RecyclerView;
public abstract class BasePreferenceFragment extends PreferenceFragmentCompat
implements SharedPreferences.OnSharedPreferenceChangeListener, Topic.AutoSubscriber {
public App app = App.self;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = super.onCreateView(inflater, container, savedInstanceState);
app.prefs.registerOnSharedPreferenceChangeListener(this);
Topic.subscribe(this);
return v;
}
@Override
public void onDestroyView() {
app.prefs.unregisterOnSharedPreferenceChangeListener(this);
Topic.unsubscribe(this);
super.onDestroyView();
}
@Override
public int[] getSubscribedTopics() {
return BaseActivity.EMPTY_INT_ARRAY;
}
@Override
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
return new PreferenceGroupAdapter(preferenceScreen) {
@SuppressLint("RestrictedApi")
@Override
public void onBindViewHolder(PreferenceViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
Preference preference = getItem(position);
if (preference instanceof PreferenceCategory)
setZeroPaddingToLayoutChildren(holder.itemView);
else {
View iconFrame = holder.itemView.findViewById(R.id.icon_frame);
if (iconFrame != null) {
iconFrame.setVisibility(preference.getIcon() == null ? View.GONE : View.VISIBLE);
}
}
}
};
}
private void setZeroPaddingToLayoutChildren(View view) {
if (!(view instanceof ViewGroup))
return;
ViewGroup viewGroup = (ViewGroup) view;
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
setZeroPaddingToLayoutChildren(viewGroup.getChildAt(i));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
viewGroup.setPaddingRelative(0, viewGroup.getPaddingTop(), viewGroup.getPaddingEnd(), viewGroup.getPaddingBottom());
else
viewGroup.setPadding(0, viewGroup.getPaddingTop(), viewGroup.getPaddingRight(), viewGroup.getPaddingBottom());
}
}
}

View File

@@ -1,84 +0,0 @@
package com.topjohnwu.magisk.components;
import android.content.Context;
import android.net.Network;
import android.net.Uri;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.work.Data;
import androidx.work.ListenableWorker;
public abstract class DelegateWorker {
private ListenableWorker worker;
@NonNull
public abstract ListenableWorker.Result doWork();
public void onStopped() {}
public void setActualWorker(ListenableWorker w) {
worker = w;
}
@NonNull
public Context getApplicationContext() {
return worker.getApplicationContext();
}
@NonNull
public UUID getId() {
return worker.getId();
}
@NonNull
public Data getInputData() {
return worker.getInputData();
}
@NonNull
public Set<String> getTags() {
return worker.getTags();
}
@NonNull
@RequiresApi(24)
public List<Uri> getTriggeredContentUris() {
return worker.getTriggeredContentUris();
}
@NonNull
@RequiresApi(24)
public List<String> getTriggeredContentAuthorities() {
return worker.getTriggeredContentAuthorities();
}
@Nullable
@RequiresApi(28)
public Network getNetwork() {
return worker.getNetwork();
}
public int getRunAttemptCount() {
return worker.getRunAttemptCount();
}
@NonNull
@MainThread
public ListenableFuture<ListenableWorker.Result> startWork() {
return worker.startWork();
}
public boolean isStopped() {
return worker.isStopped();
}
}

View File

@@ -1,100 +0,0 @@
package com.topjohnwu.magisk.components;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.IBinder;
import android.widget.Toast;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.uicomponents.ProgressNotification;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import androidx.annotation.Nullable;
public class DownloadModuleService extends Service {
private boolean running = false;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (flags == 0 && running) {
Utils.toast(R.string.dl_one_module, Toast.LENGTH_LONG);
} else {
running = true;
Shell.EXECUTOR.execute(() -> {
Repo repo = intent.getParcelableExtra("repo");
boolean install = intent.getBooleanExtra("install", false);
dlProcessInstall(repo, install);
stopSelf();
});
}
return START_REDELIVER_INTENT;
}
private void dlProcessInstall(Repo repo, boolean install) {
File output = new File(Const.EXTERNAL_PATH, repo.getDownloadFilename());
ProgressNotification progress = new ProgressNotification(output.getName());
startForeground(progress.hashCode(), progress.getNotification());
try {
InputStream in = Networking.get(repo.getZipUrl())
.setDownloadProgressListener(progress)
.execForInputStream().getResult();
removeTopFolder(in, new BufferedOutputStream(new FileOutputStream(output)));
if (install) {
progress.dismiss();
Intent intent = new Intent(this, ClassMap.get(FlashActivity.class));
intent.setData(Uri.fromFile(output))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
startActivity(intent);
} else {
progress.dlDone();
}
} catch (Exception e) {
e.printStackTrace();
progress.dlFail();
}
}
private void removeTopFolder(InputStream in, OutputStream out) throws IOException {
try (ZipInputStream zin = new ZipInputStream(in);
ZipOutputStream zout = new ZipOutputStream(out)) {
ZipEntry entry;
int off = -1;
while ((entry = zin.getNextEntry()) != null) {
if (off < 0)
off = entry.getName().indexOf('/') + 1;
String path = entry.getName().substring(off);
if (path.isEmpty())
continue;
zout.putNextEntry(new ZipEntry(path));
if (!entry.isDirectory())
ShellUtils.pump(zin, zout);
}
}
}
}

View File

@@ -1,99 +0,0 @@
package com.topjohnwu.magisk.components;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.SuRequestActivity;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.uicomponents.Notifications;
import com.topjohnwu.magisk.uicomponents.Shortcuts;
import com.topjohnwu.magisk.utils.DownloadApp;
import com.topjohnwu.magisk.utils.SuLogger;
import com.topjohnwu.superuser.Shell;
public class GeneralReceiver extends BroadcastReceiver {
private static SuLogger SU_LOGGER = new SuLogger() {
@Override
public String getMessage(Policy policy) {
return App.self.getString(policy.policy == Policy.ALLOW ?
R.string.su_allow_toast : R.string.su_deny_toast, policy.appName);
}
};
private String getPkg(Intent i) {
return i.getData() == null ? "" : i.getData().getEncodedSchemeSpecificPart();
}
@Override
public void onReceive(Context context, Intent intent) {
App app = App.self;
if (intent == null)
return;
String action = intent.getAction();
if (action == null)
return;
switch (action) {
case Intent.ACTION_BOOT_COMPLETED:
String bootAction = intent.getStringExtra("action");
if (bootAction == null)
bootAction = "boot";
switch (bootAction) {
case "request":
Intent i = new Intent(app, ClassMap.get(SuRequestActivity.class))
.putExtra("socket", intent.getStringExtra("socket"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
app.startActivity(i);
break;
case "log":
SU_LOGGER.handleLogs(intent);
break;
case "notify":
SU_LOGGER.handleNotify(intent);
break;
case "boot":
default:
/* Devices with DTBO might want to patch dtbo.img.
* However, that is not possible if Magisk is installed by
* patching boot image with Magisk Manager and flashed via
* fastboot, since at that time we do not have root.
* Check for dtbo status every boot time, and prompt user
* to reboot if dtbo wasn't patched and patched by Magisk Manager.
* */
Shell.su("mm_patch_dtbo").submit(result -> {
if (result.isSuccess())
Notifications.dtboPatched();
});
break;
}
break;
case Intent.ACTION_PACKAGE_REPLACED:
// This will only work pre-O
if (Config.get(Config.Key.SU_REAUTH)) {
app.mDB.deletePolicy(getPkg(intent));
}
break;
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
String pkg = getPkg(intent);
app.mDB.deletePolicy(pkg);
Shell.su("magiskhide --rm " + pkg).submit();
break;
case Intent.ACTION_LOCALE_CHANGED:
Shortcuts.setup(context);
break;
case Const.Key.BROADCAST_MANAGER_UPDATE:
Config.managerLink = intent.getStringExtra(Const.Key.INTENT_SET_LINK);
DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME));
break;
case Const.Key.BROADCAST_REBOOT:
Shell.su("/system/bin/reboot").submit();
break;
}
}
}

View File

@@ -1,29 +0,0 @@
package com.topjohnwu.magisk.components;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.tasks.CheckUpdates;
import com.topjohnwu.magisk.uicomponents.Notifications;
import com.topjohnwu.superuser.Shell;
import androidx.annotation.NonNull;
import androidx.work.ListenableWorker;
public class UpdateCheckService extends DelegateWorker {
@NonNull
@Override
public ListenableWorker.Result doWork() {
Shell.getShell();
CheckUpdates.checkNow(this::onCheckDone);
return ListenableWorker.Result.success();
}
private void onCheckDone() {
if (BuildConfig.VERSION_CODE < Config.remoteManagerVersionCode) {
Notifications.managerUpdate();
} else if (Config.magiskVersionCode < Config.remoteMagiskVersionCode) {
Notifications.magiskUpdate();
}
}
}

View File

@@ -1,161 +0,0 @@
package com.topjohnwu.magisk.dialogs;
import android.app.Activity;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
import androidx.appcompat.app.AlertDialog;
import butterknife.BindView;
public class CustomAlertDialog extends AlertDialog.Builder {
private DialogInterface.OnClickListener positiveListener;
private DialogInterface.OnClickListener negativeListener;
private DialogInterface.OnClickListener neutralListener;
protected AlertDialog dialog;
protected ViewHolder vh;
public class ViewHolder {
@BindView(R.id.dialog_layout) public LinearLayout dialogLayout;
@BindView(R.id.button_panel) public LinearLayout buttons;
@BindView(R.id.message) public TextView messageView;
@BindView(R.id.negative) public Button negative;
@BindView(R.id.positive) public Button positive;
@BindView(R.id.neutral) public Button neutral;
ViewHolder(View v) {
new CustomAlertDialog$ViewHolder_ViewBinding(this, v);
messageView.setVisibility(View.GONE);
negative.setVisibility(View.GONE);
positive.setVisibility(View.GONE);
neutral.setVisibility(View.GONE);
buttons.setVisibility(View.GONE);
}
}
{
View v = LayoutInflater.from(getContext()).inflate(R.layout.alert_dialog, null);
vh = new ViewHolder(v);
super.setView(v);
}
public CustomAlertDialog(@NonNull Activity context) {
super(context);
}
public CustomAlertDialog(@NonNull Activity context, @StyleRes int themeResId) {
super(context, themeResId);
}
public ViewHolder getViewHolder() {
return vh;
}
@Override
public CustomAlertDialog setView(int layoutResId) { return this; }
@Override
public CustomAlertDialog setView(View view) { return this; }
@Override
public CustomAlertDialog setMessage(@Nullable CharSequence message) {
vh.messageView.setVisibility(View.VISIBLE);
vh.messageView.setText(message);
return this;
}
@Override
public CustomAlertDialog setMessage(@StringRes int messageId) {
return setMessage(getContext().getString(messageId));
}
@Override
public CustomAlertDialog setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) {
vh.buttons.setVisibility(View.VISIBLE);
vh.positive.setVisibility(View.VISIBLE);
vh.positive.setText(text);
positiveListener = listener;
vh.positive.setOnClickListener((v) -> {
if (positiveListener != null) {
positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
}
dialog.dismiss();
});
return this;
}
@Override
public CustomAlertDialog setPositiveButton(@StringRes int textId, DialogInterface.OnClickListener listener) {
return setPositiveButton(getContext().getString(textId), listener);
}
@Override
public CustomAlertDialog setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) {
vh.buttons.setVisibility(View.VISIBLE);
vh.negative.setVisibility(View.VISIBLE);
vh.negative.setText(text);
negativeListener = listener;
vh.negative.setOnClickListener((v) -> {
if (negativeListener != null) {
negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
}
dialog.dismiss();
});
return this;
}
@Override
public CustomAlertDialog setNegativeButton(@StringRes int textId, DialogInterface.OnClickListener listener) {
return setNegativeButton(getContext().getString(textId), listener);
}
@Override
public CustomAlertDialog setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) {
vh.buttons.setVisibility(View.VISIBLE);
vh.neutral.setVisibility(View.VISIBLE);
vh.neutral.setText(text);
neutralListener = listener;
vh.neutral.setOnClickListener((v) -> {
if (neutralListener != null) {
neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL);
}
dialog.dismiss();
});
return this;
}
@Override
public CustomAlertDialog setNeutralButton(@StringRes int textId, DialogInterface.OnClickListener listener) {
return setNeutralButton(getContext().getString(textId), listener);
}
@Override
public AlertDialog create() {
dialog = super.create();
return dialog;
}
@Override
public AlertDialog show() {
create();
dialog.show();
return dialog;
}
public void dismiss() {
dialog.dismiss();
}
}

View File

@@ -1,59 +0,0 @@
package com.topjohnwu.magisk.dialogs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.widget.Toast;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.SplashActivity;
import com.topjohnwu.magisk.tasks.MagiskInstaller;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.io.SuFile;
import java.io.IOException;
import androidx.annotation.NonNull;
public class EnvFixDialog extends CustomAlertDialog {
public EnvFixDialog(@NonNull Activity activity) {
super(activity);
setTitle(R.string.env_fix_title);
setMessage(R.string.env_fix_msg);
setCancelable(true);
setPositiveButton(R.string.yes, (d, i) -> {
ProgressDialog pd = ProgressDialog.show(activity,
activity.getString(R.string.setup_title),
activity.getString(R.string.setup_msg));
new MagiskInstaller() {
@Override
protected boolean operations() {
installDir = new SuFile("/data/adb/magisk");
Shell.su("rm -rf /data/adb/magisk/*").exec();
return extractZip() && Shell.su("fix_env").exec().isSuccess();
}
@Override
protected void onResult(boolean success) {
pd.dismiss();
Utils.toast(success ? R.string.setup_done : R.string.setup_fail, Toast.LENGTH_LONG);
if (success) {
// Relaunch the app
try {
Shell.getShell().close();
} catch (IOException ignored) {}
Intent intent = new Intent(activity, ClassMap.get(SplashActivity.class));
intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME | Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
activity.finish();
}
}
}.exec();
});
setNegativeButton(R.string.no_thanks, null);
}
}

View File

@@ -1,88 +0,0 @@
package com.topjohnwu.magisk.dialogs;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.view.Gravity;
import android.widget.Toast;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import com.topjohnwu.magisk.utils.Utils;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
@TargetApi(Build.VERSION_CODES.M)
public class FingerprintAuthDialog extends CustomAlertDialog {
private Runnable callback;
private DialogFingerprintHelper helper;
public FingerprintAuthDialog(@NonNull Activity activity, Runnable onSuccess) {
super(activity);
callback = onSuccess;
Drawable fingerprint = activity.getResources().getDrawable(R.drawable.ic_fingerprint);
fingerprint.setBounds(0, 0, Utils.dpInPx(50), Utils.dpInPx(50));
Resources.Theme theme = activity.getTheme();
TypedArray ta = theme.obtainStyledAttributes(new int[] {R.attr.imageColorTint});
fingerprint.setTint(ta.getColor(0, Color.GRAY));
ta.recycle();
vh.messageView.setCompoundDrawables(null, null, null, fingerprint);
vh.messageView.setCompoundDrawablePadding(Utils.dpInPx(20));
vh.messageView.setGravity(Gravity.CENTER);
setMessage(R.string.auth_fingerprint);
setNegativeButton(R.string.close, (d, w) -> helper.cancel());
setOnCancelListener(d -> helper.cancel());
try {
helper = new DialogFingerprintHelper();
} catch (Exception ignored) {}
}
@Override
public AlertDialog show() {
create();
if (helper == null) {
dialog.dismiss();
Utils.toast(R.string.auth_fail, Toast.LENGTH_SHORT);
} else {
helper.authenticate();
dialog.show();
}
return dialog;
}
class DialogFingerprintHelper extends FingerprintHelper {
DialogFingerprintHelper() throws Exception {}
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
vh.messageView.setTextColor(Color.RED);
vh.messageView.setText(errString);
}
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
vh.messageView.setTextColor(Color.RED);
vh.messageView.setText(helpString);
}
@Override
public void onAuthenticationFailed() {
vh.messageView.setTextColor(Color.RED);
vh.messageView.setText(R.string.auth_fail);
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
dismiss();
callback.run();
}
}
}

View File

@@ -1,99 +0,0 @@
package com.topjohnwu.magisk.dialogs;
import android.app.Activity;
import android.content.Intent;
import android.widget.Toast;
import com.google.android.material.snackbar.Snackbar;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.uicomponents.ProgressNotification;
import com.topjohnwu.magisk.uicomponents.SnackbarMaker;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import java.io.File;
import java.util.List;
import androidx.appcompat.app.AlertDialog;
class InstallMethodDialog extends AlertDialog.Builder {
InstallMethodDialog(BaseActivity activity, List<String> options) {
super(activity);
setTitle(R.string.select_method);
setItems(options.toArray(new String [0]), (dialog, idx) -> {
Intent intent;
switch (idx) {
case 1:
patchBoot(activity);
break;
case 0:
downloadOnly(activity);
break;
case 2:
intent = new Intent(activity, ClassMap.get(FlashActivity.class))
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_MAGISK);
activity.startActivity(intent);
break;
case 3:
installInactiveSlot(activity);
break;
default:
}
});
}
private void patchBoot(BaseActivity a) {
Utils.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG);
Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*");
a.runWithExternalRW(() ->
a.startActivityForResult(intent, Const.ID.SELECT_BOOT,
(requestCode, resultCode, data) -> {
if (requestCode == Const.ID.SELECT_BOOT &&
resultCode == Activity.RESULT_OK && data != null) {
Intent i = new Intent(a, ClassMap.get(FlashActivity.class))
.setData(data.getData())
.putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT);
a.startActivity(i);
}
})
);
}
private void downloadOnly(BaseActivity a) {
a.runWithExternalRW(() -> {
String filename = Utils.fmt("Magisk-v%s(%d).zip",
Config.remoteMagiskVersionString, Config.remoteMagiskVersionCode);
File zip = new File(Const.EXTERNAL_PATH, filename);
ProgressNotification progress = new ProgressNotification(filename);
Networking.get(Config.magiskLink)
.setDownloadProgressListener(progress)
.setErrorHandler(((conn, e) -> progress.dlFail()))
.getAsFile(zip, f -> {
progress.dlDone();
SnackbarMaker.make(a,
a.getString(R.string.internal_storage, "/Download/" + filename),
Snackbar.LENGTH_LONG).show();
});
});
}
private void installInactiveSlot(BaseActivity activity) {
new CustomAlertDialog(activity)
.setTitle(R.string.warning)
.setMessage(R.string.install_inactive_slot_msg)
.setCancelable(true)
.setPositiveButton(R.string.yes, (d, i) -> {
Intent intent = new Intent(activity, ClassMap.get(FlashActivity.class))
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_INACTIVE_SLOT);
activity.startActivity(intent);
})
.setNegativeButton(R.string.no_thanks, null)
.show();
}
}

View File

@@ -1,50 +0,0 @@
package com.topjohnwu.magisk.dialogs;
import android.net.Uri;
import android.text.TextUtils;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.uicomponents.MarkDownWindow;
import com.topjohnwu.magisk.utils.AppUtils;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import java.util.ArrayList;
import java.util.List;
public class MagiskInstallDialog extends CustomAlertDialog {
public MagiskInstallDialog(BaseActivity a) {
super(a);
String filename = Utils.fmt("Magisk-v%s(%d).zip",
Config.remoteMagiskVersionString, Config.remoteMagiskVersionCode);
setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.magisk)));
setMessage(a.getString(R.string.repo_install_msg, filename));
setCancelable(true);
setPositiveButton(R.string.install, (d, i) -> {
List<String> options = new ArrayList<>();
options.add(a.getString(R.string.download_zip_only));
options.add(a.getString(R.string.patch_boot_file));
if (Shell.rootAccess()) {
options.add(a.getString(R.string.direct_install));
String s = ShellUtils.fastCmd("grep_prop ro.build.ab_update");
if (!s.isEmpty() && Boolean.parseBoolean(s)) {
options.add(a.getString(R.string.install_inactive_slot));
}
}
new InstallMethodDialog(a, options).show();
});
if (!TextUtils.isEmpty(Config.magiskNoteLink)) {
setNeutralButton(R.string.release_notes, (d, i) -> {
if (Config.magiskNoteLink.contains("forum.xda-developers")) {
// Open forum links in browser
AppUtils.openLink(a, Uri.parse(Config.magiskNoteLink));
} else {
MarkDownWindow.show(a, null, Config.magiskNoteLink);
}
});
}
}
}

View File

@@ -1,28 +0,0 @@
package com.topjohnwu.magisk.dialogs;
import android.app.Activity;
import android.text.TextUtils;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.uicomponents.MarkDownWindow;
import com.topjohnwu.magisk.utils.DownloadApp;
import com.topjohnwu.magisk.utils.Utils;
import androidx.annotation.NonNull;
public class ManagerInstallDialog extends CustomAlertDialog {
public ManagerInstallDialog(@NonNull Activity a) {
super(a);
String name = Utils.fmt("MagiskManager v%s(%d)",
Config.remoteManagerVersionString, Config.remoteManagerVersionCode);
setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.app_name)));
setMessage(a.getString(R.string.repo_install_msg, name));
setCancelable(true);
setPositiveButton(R.string.install, (d, i) -> DownloadApp.upgrade(name));
if (!TextUtils.isEmpty(Config.managerNoteLink)) {
setNeutralButton(R.string.app_changelog, (d, i) -> MarkDownWindow.show(a, null, Config.managerNoteLink));
}
}
}

View File

@@ -1,61 +0,0 @@
package com.topjohnwu.magisk.dialogs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
import android.widget.Toast;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.uicomponents.ProgressNotification;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import java.io.File;
import androidx.annotation.NonNull;
public class UninstallDialog extends CustomAlertDialog {
public UninstallDialog(@NonNull Activity activity) {
super(activity);
setTitle(R.string.uninstall_magisk_title);
setMessage(R.string.uninstall_magisk_msg);
setNeutralButton(R.string.restore_img, (d, i) -> {
ProgressDialog dialog = ProgressDialog.show(activity,
activity.getString(R.string.restore_img),
activity.getString(R.string.restore_img_msg));
Shell.su("restore_imgs").submit(result -> {
dialog.cancel();
if (result.isSuccess()) {
Utils.toast(R.string.restore_done, Toast.LENGTH_SHORT);
} else {
Utils.toast(R.string.restore_fail, Toast.LENGTH_LONG);
}
});
});
if (!TextUtils.isEmpty(Config.uninstallerLink)) {
setPositiveButton(R.string.complete_uninstall, (d, i) -> {
File zip = new File(activity.getFilesDir(), "uninstaller.zip");
ProgressNotification progress = new ProgressNotification(zip.getName());
Networking.get(Config.uninstallerLink)
.setDownloadProgressListener(progress)
.setErrorHandler(((conn, e) -> progress.dlFail()))
.getAsFile(zip, f -> {
progress.dismiss();
Intent intent = new Intent(activity, ClassMap.get(FlashActivity.class))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(Uri.fromFile(f))
.putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL);
activity.startActivity(intent);
});
});
}
}
}

View File

@@ -1,46 +0,0 @@
package com.topjohnwu.magisk.fragments;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.material.tabs.TabLayout;
import com.topjohnwu.magisk.MainActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.adapters.TabFragmentAdapter;
import com.topjohnwu.magisk.components.BaseFragment;
import androidx.viewpager.widget.ViewPager;
import butterknife.BindView;
public class LogFragment extends BaseFragment {
@BindView(R.id.container) ViewPager viewPager;
@BindView(R.id.tab) TabLayout tab;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_log, container, false);
unbinder = new LogFragment_ViewBinding(this, v);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
((MainActivity) requireActivity()).toolbar.setElevation(0);
}
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
tab.setupWithViewPager(viewPager);
tab.setVisibility(View.VISIBLE);
viewPager.setAdapter(adapter);
return v;
}
}

View File

@@ -1,332 +0,0 @@
package com.topjohnwu.magisk.fragments;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.MainActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.components.BaseFragment;
import com.topjohnwu.magisk.dialogs.EnvFixDialog;
import com.topjohnwu.magisk.dialogs.MagiskInstallDialog;
import com.topjohnwu.magisk.dialogs.ManagerInstallDialog;
import com.topjohnwu.magisk.dialogs.UninstallDialog;
import com.topjohnwu.magisk.tasks.CheckUpdates;
import com.topjohnwu.magisk.uicomponents.ArrowExpandedViewHolder;
import com.topjohnwu.magisk.uicomponents.ExpandableViewHolder;
import com.topjohnwu.magisk.uicomponents.MarkDownWindow;
import com.topjohnwu.magisk.uicomponents.SafetyNet;
import com.topjohnwu.magisk.uicomponents.UpdateCardHolder;
import com.topjohnwu.magisk.utils.AppUtils;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.transition.ChangeBounds;
import androidx.transition.Fade;
import androidx.transition.Transition;
import androidx.transition.TransitionManager;
import androidx.transition.TransitionSet;
import butterknife.BindColor;
import butterknife.BindView;
import butterknife.OnClick;
public class MagiskFragment extends BaseFragment
implements SwipeRefreshLayout.OnRefreshListener, Topic.Subscriber {
private static boolean shownDialog = false;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.linearLayout) LinearLayout root;
@BindView(R.id.install_option_card) CardView installOptionCard;
@BindView(R.id.keep_force_enc) CheckBox keepEncChkbox;
@BindView(R.id.keep_verity) CheckBox keepVerityChkbox;
@BindView(R.id.install_option_expand) ViewGroup optionExpandLayout;
@BindView(R.id.arrow) ImageView arrow;
@BindView(R.id.uninstall_button) CardView uninstallButton;
@BindColor(R.color.red500) int colorBad;
@BindColor(R.color.green500) int colorOK;
@BindColor(R.color.yellow500) int colorWarn;
@BindColor(R.color.green500) int colorNeutral;
@BindColor(R.color.blue500) int colorInfo;
private UpdateCardHolder magisk;
private UpdateCardHolder manager;
private SafetyNet safetyNet;
private Transition transition;
private ExpandableViewHolder optionExpand;
private void magiskInstall(View v) {
// Show Manager update first
if (Config.remoteManagerVersionCode > BuildConfig.VERSION_CODE) {
new ManagerInstallDialog(requireActivity()).show();
return;
}
new MagiskInstallDialog((BaseActivity) requireActivity()).show();
}
private void managerInstall(View v) {
new ManagerInstallDialog(requireActivity()).show();
}
private void openLink(String url) {
AppUtils.openLink(requireActivity(), Uri.parse(url));
}
@OnClick(R.id.paypal)
void paypal() {
openLink(Const.Url.PAYPAL_URL);
}
@OnClick(R.id.patreon)
void patreon() {
openLink(Const.Url.PATREON_URL);
}
@OnClick(R.id.twitter)
void twitter() {
openLink(Const.Url.TWITTER_URL);
}
@OnClick(R.id.github)
void github() {
openLink(Const.Url.SOURCE_CODE_URL);
}
@OnClick(R.id.xda)
void xda() {
openLink(Const.Url.XDA_THREAD);
}
@OnClick(R.id.uninstall_button)
void uninstall() {
new UninstallDialog(requireActivity()).show();
}
@OnClick(R.id.arrow)
void expandOptions() {
if (optionExpand.isExpanded())
optionExpand.collapse();
else optionExpand.expand();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_magisk, container, false);
unbinder = new MagiskFragment_ViewBinding(this, v);
requireActivity().setTitle(R.string.magisk);
optionExpand = new ArrowExpandedViewHolder(optionExpandLayout, arrow);
safetyNet = new SafetyNet(v);
magisk = new UpdateCardHolder(inflater, root);
manager = new UpdateCardHolder(inflater, root);
manager.setClickable(vv ->
MarkDownWindow.show(requireActivity(), null,
getResources().openRawResource(R.raw.changelog)));
root.addView(magisk.itemView, 1);
root.addView(manager.itemView, 2);
keepVerityChkbox.setChecked(Config.keepVerity);
keepVerityChkbox.setOnCheckedChangeListener((view, checked) -> Config.keepVerity = checked);
keepEncChkbox.setChecked(Config.keepEnc);
keepEncChkbox.setOnCheckedChangeListener((view, checked) -> Config.keepEnc = checked);
mSwipeRefreshLayout.setOnRefreshListener(this);
magisk.install.setOnClickListener(this::magiskInstall);
manager.install.setOnClickListener(this::managerInstall);
if (Config.get(Config.Key.COREONLY)) {
magisk.additional.setText(R.string.core_only_enabled);
magisk.additional.setVisibility(View.VISIBLE);
}
if (!app.getPackageName().equals(BuildConfig.APPLICATION_ID)) {
manager.additional.setText("(" + app.getPackageName() + ")");
manager.additional.setVisibility(View.VISIBLE);
}
transition = new TransitionSet()
.setOrdering(TransitionSet.ORDERING_TOGETHER)
.addTransition(new Fade(Fade.OUT))
.addTransition(new ChangeBounds())
.addTransition(new Fade(Fade.IN));
updateUI();
return v;
}
@Override
public void onDestroyView() {
super.onDestroyView();
safetyNet.unbinder.unbind();
magisk.unbinder.unbind();
manager.unbinder.unbind();
}
@Override
public void onRefresh() {
mSwipeRefreshLayout.setRefreshing(false);
TransitionManager.beginDelayedTransition(root, transition);
safetyNet.reset();
magisk.reset();
manager.reset();
Config.loadMagiskInfo();
updateUI();
Topic.reset(getSubscribedTopics());
Config.remoteMagiskVersionString = null;
Config.remoteMagiskVersionCode = -1;
shownDialog = false;
// Trigger state check
if (Networking.checkNetworkStatus(app)) {
CheckUpdates.check();
}
}
@Override
public int[] getSubscribedTopics() {
return new int[] {Topic.UPDATE_CHECK_DONE};
}
@Override
public void onPublish(int topic, Object[] result) {
updateCheckUI();
}
private void updateUI() {
((MainActivity) requireActivity()).checkHideSection();
int image, color;
String status;
if (Config.magiskVersionCode < 0) {
color = colorBad;
image = R.drawable.ic_cancel;
status = getString(R.string.magisk_version_error);
magisk.status.setText(status);
magisk.currentVersion.setVisibility(View.GONE);
} else {
color = colorOK;
image = R.drawable.ic_check_circle;
status = getString(R.string.magisk);
magisk.currentVersion.setText(getString(R.string.current_installed,
String.format(Locale.US, "v%s (%d)",
Config.magiskVersionString, Config.magiskVersionCode)));
}
magisk.statusIcon.setColorFilter(color);
magisk.statusIcon.setImageResource(image);
manager.statusIcon.setColorFilter(colorOK);
manager.statusIcon.setImageResource(R.drawable.ic_check_circle);
manager.currentVersion.setText(getString(R.string.current_installed,
String.format(Locale.US, "v%s (%d)",
BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));
if (!Networking.checkNetworkStatus(app)) {
// No network, updateCheckUI will not be triggered
magisk.status.setText(status);
manager.status.setText(R.string.app_name);
magisk.setValid(false);
manager.setValid(false);
}
}
private void updateCheckUI() {
int image, color;
String status, button = "";
if (Config.remoteMagiskVersionCode < 0) {
color = colorNeutral;
image = R.drawable.ic_help;
status = getString(R.string.invalid_update_channel);
} else {
magisk.latestVersion.setText(getString(R.string.latest_version,
String.format(Locale.US, "v%s (%d)",
Config.remoteMagiskVersionString, Config.remoteMagiskVersionCode)));
if (Config.remoteMagiskVersionCode > Config.magiskVersionCode) {
color = colorInfo;
image = R.drawable.ic_update;
status = getString(R.string.magisk_update_title);
button = getString(R.string.update);
} else {
color = colorOK;
image = R.drawable.ic_check_circle;
status = getString(R.string.magisk_up_to_date);
button = getString(R.string.install);
}
}
if (Config.magiskVersionCode > 0) {
// Only override status if Magisk is installed
magisk.statusIcon.setImageResource(image);
magisk.statusIcon.setColorFilter(color);
magisk.status.setText(status);
magisk.install.setText(button);
}
if (Config.remoteManagerVersionCode < 0) {
color = colorNeutral;
image = R.drawable.ic_help;
status = getString(R.string.invalid_update_channel);
} else {
manager.latestVersion.setText(getString(R.string.latest_version,
String.format(Locale.US, "v%s (%d)",
Config.remoteManagerVersionString, Config.remoteManagerVersionCode)));
if (Config.remoteManagerVersionCode > BuildConfig.VERSION_CODE) {
color = colorInfo;
image = R.drawable.ic_update;
status = getString(R.string.manager_update_title);
manager.install.setText(R.string.update);
} else {
color = colorOK;
image = R.drawable.ic_check_circle;
status = getString(R.string.manager_up_to_date);
manager.install.setText(R.string.install);
}
}
manager.statusIcon.setImageResource(image);
manager.statusIcon.setColorFilter(color);
manager.status.setText(status);
magisk.setValid(Config.remoteMagiskVersionCode > 0);
manager.setValid(Config.remoteManagerVersionCode > 0);
TransitionManager.beginDelayedTransition(root, transition);
if (Config.remoteMagiskVersionCode < 0) {
// Hide install related components
installOptionCard.setVisibility(View.GONE);
uninstallButton.setVisibility(View.GONE);
} else {
// Show install related components
installOptionCard.setVisibility(View.VISIBLE);
uninstallButton.setVisibility(Shell.rootAccess() ? View.VISIBLE : View.GONE);
}
if (!shownDialog && Config.magiskVersionCode > 0 &&
!Shell.su("env_check").exec().isSuccess()) {
shownDialog = true;
new EnvFixDialog(requireActivity()).show();
}
}
}

View File

@@ -1,102 +0,0 @@
package com.topjohnwu.magisk.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SearchView;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
import com.topjohnwu.magisk.components.BaseFragment;
import com.topjohnwu.magisk.utils.Topic;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import butterknife.BindView;
public class MagiskHideFragment extends BaseFragment implements Topic.Subscriber {
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
private SearchView search;
private ApplicationAdapter adapter;
private SearchView.OnQueryTextListener searchListener;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_magisk_hide, container, false);
unbinder = new MagiskHideFragment_ViewBinding(this, view);
adapter = new ApplicationAdapter(requireActivity());
recyclerView.setAdapter(adapter);
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.setOnRefreshListener(adapter::refresh);
searchListener = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
adapter.filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.filter(newText);
return false;
}
};
requireActivity().setTitle(R.string.magiskhide);
return view;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_magiskhide, menu);
search = (SearchView) menu.findItem(R.id.app_search).getActionView();
search.setOnQueryTextListener(searchListener);
boolean showSystem = Config.get(Config.Key.SHOW_SYSTEM_APP);
menu.findItem(R.id.show_system).setChecked(showSystem);
adapter.setShowSystem(showSystem);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.show_system) {
boolean showSystem = !item.isChecked();
item.setChecked(showSystem);
Config.set(Config.Key.SHOW_SYSTEM_APP, showSystem);
adapter.setShowSystem(showSystem);
adapter.filter(search.getQuery().toString());
}
return true;
}
@Override
public int[] getSubscribedTopics() {
return new int[] {Topic.MAGISK_HIDE_DONE};
}
@Override
public void onPublish(int topic, Object[] result) {
mSwipeRefreshLayout.setRefreshing(false);
adapter.filter(search.getQuery().toString());
}
}

View File

@@ -1,157 +0,0 @@
package com.topjohnwu.magisk.fragments;
import android.Manifest;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.material.snackbar.Snackbar;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.adapters.StringListAdapter;
import com.topjohnwu.magisk.components.BaseFragment;
import com.topjohnwu.magisk.uicomponents.SnackbarMaker;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.internal.NOPList;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
public class MagiskLogFragment extends BaseFragment {
@BindView(R.id.recyclerView) RecyclerView rv;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_magisk_log, container, false);
unbinder = new MagiskLogFragment_ViewBinding(this, view);
setHasOptionsMenu(true);
return view;
}
@Override
public void onStart() {
super.onStart();
getActivity().setTitle(R.string.log);
}
@Override
public void onResume() {
super.onResume();
readLogs();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_log, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_refresh:
readLogs();
return true;
case R.id.menu_save:
runWithPermission(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, this::saveLogs);
return true;
case R.id.menu_clear:
clearLogs();
rv.setAdapter(new MagiskLogAdapter(NOPList.getInstance()));
return true;
default:
return true;
}
}
private void readLogs() {
Shell.su("tail -n 5000 " + Const.MAGISK_LOG).submit(result -> {
rv.setAdapter(new MagiskLogAdapter(result.getOut()));
});
}
private void saveLogs() {
Calendar now = Calendar.getInstance();
String filename = Utils.fmt("magisk_log_%04d%02d%02d_%02d%02d%02d.log",
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
File logFile = new File(Const.EXTERNAL_PATH, filename);
try {
logFile.createNewFile();
} catch (IOException e) {
return;
}
Shell.su("cat " + Const.MAGISK_LOG + " > " + logFile)
.submit(result ->
SnackbarMaker.make(rv, logFile.getPath(), Snackbar.LENGTH_SHORT).show());
}
private void clearLogs() {
Shell.su("echo -n > " + Const.MAGISK_LOG).submit();
SnackbarMaker.make(rv, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
}
private class MagiskLogAdapter extends StringListAdapter<MagiskLogAdapter.ViewHolder> {
MagiskLogAdapter(List<String> list) {
super(list);
if (mList.isEmpty())
mList.add(requireContext().getString(R.string.log_is_empty));
}
@Override
protected int itemLayoutRes() {
return R.layout.list_item_console;
}
@NonNull
@Override
public ViewHolder createViewHolder(@NonNull View v) {
return new ViewHolder(v);
}
@Override
protected void onUpdateTextWidth(ViewHolder holder) {
super.onUpdateTextWidth(holder);
// Find the longest string and update accordingly
int max = 0;
String maxStr = "";
for (String s : mList) {
int len = s.length();
if (len > max) {
max = len;
maxStr = s;
}
}
holder.txt.setText(maxStr);
super.onUpdateTextWidth(holder);
}
public class ViewHolder extends StringListAdapter.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
protected int textViewResId() {
return R.id.txt;
}
}
}
}

View File

@@ -1,141 +0,0 @@
package com.topjohnwu.magisk.fragments;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.adapters.ModulesAdapter;
import com.topjohnwu.magisk.components.BaseFragment;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import butterknife.BindView;
import butterknife.OnClick;
public class ModulesFragment extends BaseFragment implements Topic.Subscriber {
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
@BindView(R.id.empty_rv) TextView emptyRv;
@OnClick(R.id.fab)
void selectFile() {
runWithPermission(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, () -> {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("application/zip");
startActivityForResult(intent, Const.ID.FETCH_ZIP);
});
}
private List<Module> listModules = new ArrayList<>();
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_modules, container, false);
unbinder = new ModulesFragment_ViewBinding(this, view);
setHasOptionsMenu(true);
mSwipeRefreshLayout.setOnRefreshListener(() -> {
recyclerView.setVisibility(View.GONE);
Utils.loadModules();
});
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
mSwipeRefreshLayout.setEnabled(recyclerView.getChildAt(0).getTop() >= 0);
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
requireActivity().setTitle(R.string.modules);
return view;
}
@Override
public int[] getSubscribedTopics() {
return new int[] {Topic.MODULE_LOAD_DONE};
}
@Override
public void onPublish(int topic, Object[] result) {
updateUI((Map<String, Module>) result[0]);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) {
// Get the URI of the selected file
Intent intent = new Intent(getActivity(), ClassMap.get(FlashActivity.class));
intent.setData(data.getData()).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
startActivity(intent);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_reboot, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.reboot:
Utils.reboot();
return true;
case R.id.reboot_recovery:
Shell.su("/system/bin/reboot recovery").submit();
return true;
case R.id.reboot_bootloader:
Shell.su("/system/bin/reboot bootloader").submit();
return true;
case R.id.reboot_download:
Shell.su("/system/bin/reboot download").submit();
return true;
default:
return false;
}
}
private void updateUI(Map<String, Module> moduleMap) {
listModules.clear();
listModules.addAll(moduleMap.values());
if (listModules.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
recyclerView.setAdapter(new ModulesAdapter(listModules));
}
mSwipeRefreshLayout.setRefreshing(false);
}
}

View File

@@ -1,117 +0,0 @@
package com.topjohnwu.magisk.fragments;
import android.app.AlertDialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SearchView;
import android.widget.TextView;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.adapters.ReposAdapter;
import com.topjohnwu.magisk.components.BaseFragment;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.tasks.UpdateRepos;
import com.topjohnwu.magisk.utils.Topic;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import butterknife.BindView;
public class ReposFragment extends BaseFragment implements Topic.Subscriber {
@BindView(R.id.recyclerView) RecyclerView recyclerView;
@BindView(R.id.empty_rv) TextView emptyRv;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
private ReposAdapter adapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_repos, container, false);
unbinder = new ReposFragment_ViewBinding(this, view);
mSwipeRefreshLayout.setRefreshing(true);
recyclerView.setVisibility(View.GONE);
mSwipeRefreshLayout.setOnRefreshListener(() -> new UpdateRepos().exec(true));
requireActivity().setTitle(R.string.downloads);
return view;
}
@Override
public int[] getSubscribedTopics() {
return new int[] {Topic.MODULE_LOAD_DONE, Topic.REPO_LOAD_DONE};
}
@Override
public void onPublish(int topic, Object[] result) {
switch (topic) {
case Topic.MODULE_LOAD_DONE:
adapter = new ReposAdapter(app.repoDB, (Map<String, Module>) result[0]);
recyclerView.setAdapter(adapter);
break;
case Topic.REPO_LOAD_DONE:
if (adapter != null)
adapter.notifyDBChanged();
break;
}
if (Topic.isPublished(this)) {
mSwipeRefreshLayout.setRefreshing(false);
boolean empty = adapter.getItemCount() == 0;
recyclerView.setVisibility(empty ? View.GONE : View.VISIBLE);
emptyRv.setVisibility(empty ? View.VISIBLE : View.GONE);
}
}
@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;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.filter(newText);
return false;
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.repo_sort) {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.sorting_order)
.setSingleChoiceItems(R.array.sorting_orders,
Config.get(Config.Key.REPO_ORDER), (d, which) -> {
Config.set(Config.Key.REPO_ORDER, which);
adapter.notifyDBChanged();
d.dismiss();
}).show();
}
return true;
}
}

View File

@@ -1,293 +0,0 @@
package com.topjohnwu.magisk.fragments;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.BasePreferenceFragment;
import com.topjohnwu.magisk.dialogs.FingerprintAuthDialog;
import com.topjohnwu.magisk.tasks.CheckUpdates;
import com.topjohnwu.magisk.utils.AppUtils;
import com.topjohnwu.magisk.utils.DownloadApp;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.PatchAPK;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import java.io.IOException;
import java.util.Locale;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreferenceCompat;
public class SettingsFragment extends BasePreferenceFragment implements Topic.Subscriber {
private ListPreference updateChannel, autoRes, suNotification,
requestTimeout, rootConfig, multiuserConfig, nsConfig;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.app_settings, rootKey);
requireActivity().setTitle(R.string.settings);
boolean showSuperuser = Utils.showSuperUser();
app.prefs.edit()
.putBoolean(Config.Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint())
.apply();
PreferenceScreen prefScreen = getPreferenceScreen();
PreferenceCategory generalCatagory = (PreferenceCategory) findPreference("general");
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
Preference hideManager = findPreference("hide");
hideManager.setOnPreferenceClickListener(pref -> {
PatchAPK.hideManager();
return true;
});
Preference restoreManager = findPreference("restore");
restoreManager.setOnPreferenceClickListener(pref -> {
DownloadApp.restore();
return true;
});
findPreference("clear").setOnPreferenceClickListener(pref -> {
app.prefs.edit().remove(Config.Key.ETAG_KEY).apply();
app.repoDB.clearRepo();
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT);
return true;
});
findPreference("hosts").setOnPreferenceClickListener(pref -> {
Shell.su("add_hosts_module").exec();
Utils.loadModules();
Utils.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT);
return true;
});
updateChannel = (ListPreference) findPreference(Config.Key.UPDATE_CHANNEL);
rootConfig = (ListPreference) findPreference(Config.Key.ROOT_ACCESS);
autoRes = (ListPreference) findPreference(Config.Key.SU_AUTO_RESPONSE);
requestTimeout = (ListPreference) findPreference(Config.Key.SU_REQUEST_TIMEOUT);
suNotification = (ListPreference) findPreference(Config.Key.SU_NOTIFICATION);
multiuserConfig = (ListPreference) findPreference(Config.Key.SU_MULTIUSER_MODE);
nsConfig = (ListPreference) findPreference(Config.Key.SU_MNT_NS);
SwitchPreferenceCompat reauth = (SwitchPreferenceCompat) findPreference(Config.Key.SU_REAUTH);
SwitchPreferenceCompat fingerprint = (SwitchPreferenceCompat) findPreference(Config.Key.SU_FINGERPRINT);
updateChannel.setOnPreferenceChangeListener((p, o) -> {
int prev = Config.get(Config.Key.UPDATE_CHANNEL);
int channel = Integer.parseInt((String) o);
if (channel == Config.Value.CUSTOM_CHANNEL) {
View v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null);
EditText url = v.findViewById(R.id.custom_url);
url.setText(app.prefs.getString(Config.Key.CUSTOM_CHANNEL, ""));
new AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_update_custom)
.setView(v)
.setPositiveButton(R.string.ok, (d, i) ->
Config.set(Config.Key.CUSTOM_CHANNEL, url.getText().toString()))
.setNegativeButton(R.string.close, (d, i) ->
Config.set(Config.Key.UPDATE_CHANNEL, prev))
.setOnCancelListener(d ->
Config.set(Config.Key.UPDATE_CHANNEL, prev))
.show();
}
return true;
});
setSummary();
// Remove language setting when API < 17
if (Build.VERSION.SDK_INT < 17)
generalCatagory.removePreference(findPreference(Config.Key.LOCALE));
// Disable dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserConfig);
}
// Disable re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
reauth.setEnabled(false);
reauth.setChecked(false);
reauth.setSummary(R.string.android_o_not_support);
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.setEnabled(false);
fingerprint.setChecked(false);
fingerprint.setSummary(R.string.disable_fingerprint);
}
if (Shell.rootAccess() && Const.USER_ID == 0) {
if (app.getPackageName().equals(BuildConfig.APPLICATION_ID)) {
generalCatagory.removePreference(restoreManager);
} else {
if (!Networking.checkNetworkStatus(app))
generalCatagory.removePreference(restoreManager);
generalCatagory.removePreference(hideManager);
}
} else {
generalCatagory.removePreference(restoreManager);
generalCatagory.removePreference(hideManager);
}
if (!showSuperuser) {
prefScreen.removePreference(suCategory);
}
if (!Shell.rootAccess()) {
prefScreen.removePreference(magiskCategory);
generalCatagory.removePreference(hideManager);
}
}
private void setLocalePreference(ListPreference lp) {
CharSequence[] entries = new CharSequence[LocaleManager.locales.size() + 1];
CharSequence[] entryValues = new CharSequence[LocaleManager.locales.size() + 1];
entries[0] = LocaleManager.getString(LocaleManager.defaultLocale, R.string.system_default);
entryValues[0] = "";
int i = 1;
for (Locale locale : LocaleManager.locales) {
entries[i] = locale.getDisplayName(locale);
entryValues[i++] = LocaleManager.toLanguageTag(locale);
}
lp.setEntries(entries);
lp.setEntryValues(entryValues);
lp.setSummary(LocaleManager.locale.getDisplayName(LocaleManager.locale));
}
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
switch (key) {
case Config.Key.ROOT_ACCESS:
case Config.Key.SU_MULTIUSER_MODE:
case Config.Key.SU_MNT_NS:
app.mDB.setSettings(key, Utils.getPrefsInt(prefs, key));
break;
case Config.Key.DARK_THEME:
requireActivity().recreate();
break;
case Config.Key.COREONLY:
if (prefs.getBoolean(key, false)) {
try {
Const.MAGISK_DISABLE_FILE.createNewFile();
} catch (IOException ignored) {}
} else {
Const.MAGISK_DISABLE_FILE.delete();
}
Utils.toast(R.string.settings_reboot_toast, Toast.LENGTH_LONG);
break;
case Config.Key.MAGISKHIDE:
if (prefs.getBoolean(key, false)) {
Shell.su("magiskhide --enable").submit();
} else {
Shell.su("magiskhide --disable").submit();
}
break;
case Config.Key.LOCALE:
LocaleManager.setLocale(app);
requireActivity().recreate();
break;
case Config.Key.UPDATE_CHANNEL:
case Config.Key.CUSTOM_CHANNEL:
CheckUpdates.check();
break;
case Config.Key.CHECK_UPDATES:
AppUtils.scheduleUpdateCheck();
break;
}
setSummary(key);
}
@Override
public boolean onPreferenceTreeClick(Preference preference) {
String key = preference.getKey();
switch (key) {
case Config.Key.SU_FINGERPRINT:
boolean checked = ((SwitchPreferenceCompat) preference).isChecked();
((SwitchPreferenceCompat) preference).setChecked(!checked);
new FingerprintAuthDialog(requireActivity(), () -> {
((SwitchPreferenceCompat) preference).setChecked(checked);
Config.set(key, checked);
}).show();
break;
}
return true;
}
private void setSummary(String key) {
switch (key) {
case Config.Key.UPDATE_CHANNEL:
updateChannel.setSummary(getResources()
.getStringArray(R.array.update_channel)
[(int) Config.get(Config.Key.UPDATE_CHANNEL)]);
break;
case Config.Key.ROOT_ACCESS:
rootConfig.setSummary(getResources()
.getStringArray(R.array.su_access)
[(int) Config.get(Config.Key.ROOT_ACCESS)]);
break;
case Config.Key.SU_AUTO_RESPONSE:
autoRes.setSummary(getResources()
.getStringArray(R.array.auto_response)
[(int) Config.get(Config.Key.SU_AUTO_RESPONSE)]);
break;
case Config.Key.SU_NOTIFICATION:
suNotification.setSummary(getResources()
.getStringArray(R.array.su_notification)
[(int) Config.get(Config.Key.SU_NOTIFICATION)]);
break;
case Config.Key.SU_REQUEST_TIMEOUT:
requestTimeout.setSummary(
getString(R.string.request_timeout_summary,
(int) Config.get(Config.Key.SU_REQUEST_TIMEOUT)));
break;
case Config.Key.SU_MULTIUSER_MODE:
multiuserConfig.setSummary(getResources()
.getStringArray(R.array.multiuser_summary)
[(int) Config.get(Config.Key.SU_MULTIUSER_MODE)]);
break;
case Config.Key.SU_MNT_NS:
nsConfig.setSummary(getResources()
.getStringArray(R.array.namespace_summary)
[(int) Config.get(Config.Key.SU_MNT_NS)]);
break;
}
}
private void setSummary() {
setSummary(Config.Key.UPDATE_CHANNEL);
setSummary(Config.Key.ROOT_ACCESS);
setSummary(Config.Key.SU_AUTO_RESPONSE);
setSummary(Config.Key.SU_NOTIFICATION);
setSummary(Config.Key.SU_REQUEST_TIMEOUT);
setSummary(Config.Key.SU_MULTIUSER_MODE);
setSummary(Config.Key.SU_MNT_NS);
}
@Override
public void onPublish(int topic, Object[] result) {
setLocalePreference((ListPreference) findPreference(Config.Key.LOCALE));
}
@Override
public int[] getSubscribedTopics() {
return new int[] {Topic.LOCALE_FETCH_DONE};
}
}

View File

@@ -1,79 +0,0 @@
package com.topjohnwu.magisk.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.adapters.SuLogAdapter;
import com.topjohnwu.magisk.components.BaseFragment;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
public class SuLogFragment extends BaseFragment {
@BindView(R.id.empty_rv) TextView emptyRv;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
private SuLogAdapter adapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_log, menu);
menu.findItem(R.id.menu_save).setVisible(false);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
unbinder = new SuLogFragment_ViewBinding(this, v);
adapter = new SuLogAdapter(app.mDB);
recyclerView.setAdapter(adapter);
updateList();
return v;
}
private void updateList() {
adapter.notifyDBChanged();
if (adapter.getSectionCount() == 0) {
emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_refresh:
updateList();
return true;
case R.id.menu_clear:
app.mDB.clearLogs();
updateList();
return true;
default:
return true;
}
}
}

View File

@@ -1,63 +0,0 @@
package com.topjohnwu.magisk.fragments;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.adapters.PolicyAdapter;
import com.topjohnwu.magisk.components.BaseFragment;
import com.topjohnwu.magisk.container.Policy;
import java.util.List;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
public class SuperuserFragment extends BaseFragment {
@BindView(R.id.recyclerView) RecyclerView recyclerView;
@BindView(R.id.empty_rv) TextView emptyRv;
private PackageManager pm;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_superuser, container, false);
unbinder = new SuperuserFragment_ViewBinding(this, view);
pm = requireActivity().getPackageManager();
return view;
}
@Override
public void onStart() {
super.onStart();
requireActivity().setTitle(getString(R.string.superuser));
}
@Override
public void onResume() {
super.onResume();
displayPolicyList();
}
private void displayPolicyList() {
List<Policy> policyList = app.mDB.getPolicyList();
if (policyList.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
recyclerView.setAdapter(new PolicyAdapter(policyList, app.mDB, pm));
emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
}
}

View File

@@ -1,43 +0,0 @@
package com.topjohnwu.magisk.uicomponents;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
public class ArrowExpandedViewHolder extends ExpandableViewHolder {
private View arrow;
public ArrowExpandedViewHolder(ViewGroup viewGroup, View arrow) {
super(viewGroup);
this.arrow = arrow;
}
@Override
public void setExpanded(boolean expanded) {
super.setExpanded(expanded);
if (arrow != null)
arrow.setRotation(expanded ? 180 : 0);
}
@Override
public void expand() {
super.expand();
setRotate(new RotateAnimation(0, 180,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f));
}
@Override
public void collapse() {
super.collapse();
setRotate(new RotateAnimation(180, 0,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f));
}
private void setRotate(RotateAnimation rotate) {
rotate.setDuration(300);
rotate.setFillAfter(true);
arrow.startAnimation(rotate);
}
}

View File

@@ -1,72 +0,0 @@
package com.topjohnwu.magisk.uicomponents;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
public class ExpandableViewHolder {
private ViewGroup expandLayout;
private ValueAnimator expandAnimator, collapseAnimator;
private boolean mExpanded = false;
private int expandHeight = 0;
public ExpandableViewHolder(ViewGroup viewGroup) {
expandLayout = viewGroup;
setExpanded(false);
expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (expandHeight == 0) {
expandLayout.measure(0, 0);
expandHeight = expandLayout.getMeasuredHeight();
}
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
expandAnimator = slideAnimator(0, expandHeight);
collapseAnimator = slideAnimator(expandHeight, 0);
return true;
}
});
}
public boolean isExpanded() {
return mExpanded;
}
public void setExpanded(boolean expanded) {
mExpanded = expanded;
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = expanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
}
public void expand() {
if (mExpanded) return;
expandLayout.setVisibility(View.VISIBLE);
expandAnimator.start();
mExpanded = true;
}
public void collapse() {
if (!mExpanded) return;
collapseAnimator.start();
mExpanded = false;
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
}
}

View File

@@ -1,103 +0,0 @@
package com.topjohnwu.magisk.uicomponents;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import com.caverock.androidsvg.SVG;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.net.ResponseListener;
import com.topjohnwu.signing.ByteArrayStream;
import com.topjohnwu.superuser.ShellUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Callable;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.spans.AsyncDrawable;
public class MarkDownWindow {
private static final SpannableConfiguration config = SpannableConfiguration.builder(App.self)
.asyncDrawableLoader(new Loader()).build();
public static void show(Activity activity, String title, String url) {
Networking.get(url).getAsString(new Listener(activity, title));
}
public static void show (Activity activity, String title, InputStream is) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ShellUtils.pump(is, baos);
new Listener(activity, title).onResponse(baos.toString());
} catch (IOException ignored) {}
}
static class Listener implements ResponseListener<String> {
Activity activity;
String title;
Listener(Activity a, String t) {
activity = a;
title = t;
}
@Override
public void onResponse(String md) {
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
alert.setTitle(title);
View mv = LayoutInflater.from(activity).inflate(R.layout.markdown_window, null);
Markwon.setMarkdown(mv.findViewById(R.id.md_txt), config, md);
alert.setView(mv);
alert.setNegativeButton(R.string.close, (dialog, id) -> dialog.dismiss());
alert.show();
}
}
static class Loader implements AsyncDrawable.Loader {
@Override
public void load(@NonNull String url, @NonNull AsyncDrawable asyncDrawable) {
App.THREAD_POOL.submit((Callable<?>) () -> {
InputStream is = Networking.get(url).execForInputStream().getResult();
if (is == null)
return null;
ByteArrayStream buf = new ByteArrayStream();
buf.readFrom(is);
// First try default drawables
Drawable drawable = Drawable.createFromStream(buf.getInputStream(), "");
if (drawable == null) {
// SVG
SVG svg = SVG.getFromInputStream(buf.getInputStream());
int width = Utils.dpInPx((int) svg.getDocumentWidth());
int height = Utils.dpInPx((int) svg.getDocumentHeight());
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
final Canvas canvas = new Canvas(bitmap);
float density = App.self.getResources().getDisplayMetrics().density;
canvas.scale(density, density);
svg.renderToCanvas(canvas);
drawable = new BitmapDrawable(App.self.getResources(), bitmap);
}
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
asyncDrawable.setResult(drawable);
return null;
});
}
@Override
public void cancel(@NonNull String url) {}
}
}

View File

@@ -1,114 +0,0 @@
package com.topjohnwu.magisk.uicomponents;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.SplashActivity;
import com.topjohnwu.magisk.components.GeneralReceiver;
import com.topjohnwu.magisk.utils.Utils;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.app.TaskStackBuilder;
public class Notifications {
public static NotificationManagerCompat mgr = NotificationManagerCompat.from(App.self);
public static void setup(Context c) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager mgr = c.getSystemService(NotificationManager.class);
mgr.deleteNotificationChannel("magisk_notification");
NotificationChannel channel =
new NotificationChannel(Const.ID.UPDATE_NOTIFICATION_CHANNEL,
c.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT);
mgr.createNotificationChannel(channel);
channel = new NotificationChannel(Const.ID.PROGRESS_NOTIFICATION_CHANNEL,
c.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW);
mgr.createNotificationChannel(channel);
}
}
public static void magiskUpdate() {
App app = App.self;
Intent intent = new Intent(app, ClassMap.get(SplashActivity.class));
intent.putExtra(Const.Key.OPEN_SECTION, "magisk");
TaskStackBuilder stackBuilder = TaskStackBuilder.create(app);
stackBuilder.addParentStack(ClassMap.get(SplashActivity.class));
stackBuilder.addNextIntent(intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.UPDATE_NOTIFICATION_CHANNEL);
builder.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle(app.getString(R.string.magisk_update_title))
.setContentText(app.getString(R.string.manager_download_install))
.setVibrate(new long[]{0, 100, 100, 100})
.setAutoCancel(true)
.setContentIntent(pendingIntent);
mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build());
}
public static void managerUpdate() {
App app = App.self;
String name = Utils.fmt("MagiskManager v%s(%d)",
Config.remoteManagerVersionString, Config.remoteManagerVersionCode);
Intent intent = new Intent(app, ClassMap.get(GeneralReceiver.class));
intent.setAction(Const.Key.BROADCAST_MANAGER_UPDATE);
intent.putExtra(Const.Key.INTENT_SET_LINK, Config.managerLink);
intent.putExtra(Const.Key.INTENT_SET_NAME, name);
PendingIntent pendingIntent = PendingIntent.getBroadcast(app,
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.UPDATE_NOTIFICATION_CHANNEL);
builder.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle(app.getString(R.string.manager_update_title))
.setContentText(app.getString(R.string.manager_download_install))
.setVibrate(new long[]{0, 100, 100, 100})
.setAutoCancel(true)
.setContentIntent(pendingIntent);
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build());
}
public static void dtboPatched() {
App app = App.self;
Intent intent = new Intent(app, ClassMap.get(GeneralReceiver.class))
.setAction(Const.Key.BROADCAST_REBOOT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(app,
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.UPDATE_NOTIFICATION_CHANNEL);
builder.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle(app.getString(R.string.dtbo_patched_title))
.setContentText(app.getString(R.string.dtbo_patched_reboot))
.setVibrate(new long[]{0, 100, 100, 100})
.addAction(R.drawable.ic_refresh, app.getString(R.string.reboot), pendingIntent);
mgr.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build());
}
public static NotificationCompat.Builder progress(String title) {
App app = App.self;
NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.PROGRESS_NOTIFICATION_CHANNEL);
builder.setPriority(NotificationCompat.PRIORITY_LOW)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentTitle(title)
.setProgress(0, 0, true)
.setOngoing(true);
return builder;
}
}

View File

@@ -1,76 +0,0 @@
package com.topjohnwu.magisk.uicomponents;
import android.app.Notification;
import android.widget.Toast;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.DownloadProgressListener;
import androidx.core.app.NotificationCompat;
public class ProgressNotification implements DownloadProgressListener {
private NotificationCompat.Builder builder;
private Notification notification;
private long prevTime;
public ProgressNotification(String title) {
builder = Notifications.progress(title);
prevTime = System.currentTimeMillis();
update();
Utils.toast(App.self.getString(R.string.downloading_toast, title), Toast.LENGTH_SHORT);
}
@Override
public void onProgress(long bytesDownloaded, long totalBytes) {
long cur = System.currentTimeMillis();
if (cur - prevTime >= 1000) {
prevTime = cur;
int progress = (int) (bytesDownloaded * 100 / totalBytes);
builder.setProgress(100, progress, false);
builder.setContentText(progress + "%");
update();
}
}
public NotificationCompat.Builder getNotificationBuilder() {
return builder;
}
public Notification getNotification() {
return notification;
}
public void update() {
notification = builder.build();
Notifications.mgr.notify(hashCode(), notification);
}
private void lastUpdate() {
notification = builder.build();
Notifications.mgr.cancel(hashCode());
Notifications.mgr.notify(notification.hashCode(), notification);
}
public void dlDone() {
builder.setProgress(0, 0, false)
.setContentText(App.self.getString(R.string.download_complete))
.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setOngoing(false);
lastUpdate();
}
public void dlFail() {
builder.setProgress(0, 0, false)
.setContentText(App.self.getString(R.string.download_file_error))
.setSmallIcon(android.R.drawable.stat_notify_error)
.setOngoing(false);
lastUpdate();
}
public void dismiss() {
Notifications.mgr.cancel(hashCode());
}
}

View File

@@ -1,161 +0,0 @@
package com.topjohnwu.magisk.uicomponents;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.dialogs.CustomAlertDialog;
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import java.io.File;
import androidx.annotation.StringRes;
import androidx.cardview.widget.CardView;
import butterknife.BindColor;
import butterknife.BindView;
import butterknife.OnClick;
import butterknife.Unbinder;
import dalvik.system.DexClassLoader;
public class SafetyNet implements ISafetyNetHelper.Callback {
private static final File EXT_APK =
new File(App.self.getFilesDir().getParent() + "/snet", "snet.apk");
@BindView(R.id.safetyNet_card) CardView safetyNetCard;
@BindView(R.id.safetyNet_refresh) ImageView safetyNetRefreshIcon;
@BindView(R.id.safetyNet_status) TextView safetyNetStatusText;
@BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress;
@BindView(R.id.safetyNet_expand) ViewGroup expandLayout;
@BindView(R.id.cts_status_icon) ImageView ctsStatusIcon;
@BindView(R.id.cts_status) TextView ctsStatusText;
@BindView(R.id.basic_status_icon) ImageView basicStatusIcon;
@BindView(R.id.basic_status) TextView basicStatusText;
@BindColor(R.color.red500) int colorBad;
@BindColor(R.color.green500) int colorOK;
public Unbinder unbinder;
private ExpandableViewHolder expandable;
public SafetyNet(View v) {
unbinder = new SafetyNet_ViewBinding(this, v);
expandable = new ExpandableViewHolder(expandLayout);
Context context = v.getContext();
safetyNetCard.setVisibility(hasGms(context) && Networking.checkNetworkStatus(context) ?
View.VISIBLE : View.GONE);
}
@OnClick(R.id.safetyNet_refresh)
void safetyNet(View v) {
Runnable task = () -> {
safetyNetProgress.setVisibility(View.VISIBLE);
safetyNetRefreshIcon.setVisibility(View.INVISIBLE);
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
check((Activity) v.getContext());
expandable.collapse();
};
if (!SafetyNet.EXT_APK.exists()) {
// Show dialog
new CustomAlertDialog((Activity) v.getContext())
.setTitle(R.string.proprietary_title)
.setMessage(R.string.proprietary_notice)
.setCancelable(true)
.setPositiveButton(R.string.yes, (d, i) -> task.run())
.setNegativeButton(R.string.no_thanks, null)
.show();
} else {
task.run();
}
}
public void reset() {
safetyNetStatusText.setText(R.string.safetyNet_check_text);
expandable.setExpanded(false);
}
@Override
public void onResponse(int response) {
safetyNetProgress.setVisibility(View.GONE);
safetyNetRefreshIcon.setVisibility(View.VISIBLE);
if ((response & 0x0F) == 0) {
safetyNetStatusText.setText(R.string.safetyNet_check_success);
boolean b;
b = (response & ISafetyNetHelper.CTS_PASS) != 0;
ctsStatusText.setText("ctsProfile: " + b);
ctsStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
ctsStatusIcon.setColorFilter(b ? colorOK : colorBad);
b = (response & ISafetyNetHelper.BASIC_PASS) != 0;
basicStatusText.setText("basicIntegrity: " + b);
basicStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
basicStatusIcon.setColorFilter(b ? colorOK : colorBad);
expandable.expand();
} else {
@StringRes int resid;
switch (response) {
case ISafetyNetHelper.RESPONSE_ERR:
resid = R.string.safetyNet_res_invalid;
break;
case ISafetyNetHelper.CONNECTION_FAIL:
default:
resid = R.string.safetyNet_api_error;
break;
}
safetyNetStatusText.setText(resid);
}
}
private void dyRun(Activity activity) throws Exception {
DexClassLoader loader = new DexClassLoader(EXT_APK.getPath(), EXT_APK.getParent(),
null, ISafetyNetHelper.class.getClassLoader());
Class<?> clazz = loader.loadClass("com.topjohnwu.snet.Snet");
ISafetyNetHelper helper = (ISafetyNetHelper) clazz.getMethod("newHelper",
Class.class, String.class, Activity.class, Object.class)
.invoke(null, ISafetyNetHelper.class, EXT_APK.getPath(), activity, this);
if (helper.getVersion() < Const.SNET_EXT_VER)
throw new Exception();
helper.attest();
}
private void check(Activity activity) {
try {
dyRun(activity);
} catch (Exception ignored) {
Shell.sh("rm -rf " + EXT_APK.getParent()).exec();
EXT_APK.getParentFile().mkdir();
Networking.get(Const.Url.SNET_URL).getAsFile(EXT_APK, f -> {
try {
dyRun(activity);
} catch (Exception e) {
e.printStackTrace();
onResponse(-1);
}
});
}
}
private boolean hasGms(Context context) {
PackageManager pm = context.getPackageManager();
PackageInfo info;
try {
info = pm.getPackageInfo("com.google.android.gms", 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return info.applicationInfo.enabled;
}
}

View File

@@ -1,79 +0,0 @@
package com.topjohnwu.magisk.uicomponents;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.os.Build;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.SplashActivity;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import java.util.ArrayList;
import androidx.annotation.RequiresApi;
public class Shortcuts {
public static void setup(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
ShortcutManager manager = context.getSystemService(ShortcutManager.class);
manager.setDynamicShortcuts(getShortCuts(context));
}
}
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
private static ArrayList<ShortcutInfo> getShortCuts(Context context) {
ArrayList<ShortcutInfo> shortCuts = new ArrayList<>();
boolean root = Shell.rootAccess();
if (Utils.showSuperUser()) {
shortCuts.add(new ShortcutInfo.Builder(context, "superuser")
.setShortLabel(context.getString(R.string.superuser))
.setIntent(new Intent(context, ClassMap.get(SplashActivity.class))
.putExtra(Const.Key.OPEN_SECTION, "superuser")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_superuser))
.setRank(0)
.build());
}
if (root && (boolean) Config.get(Config.Key.MAGISKHIDE)) {
shortCuts.add(new ShortcutInfo.Builder(context, "magiskhide")
.setShortLabel(context.getString(R.string.magiskhide))
.setIntent(new Intent(context, ClassMap.get(SplashActivity.class))
.putExtra(Const.Key.OPEN_SECTION, "magiskhide")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_magiskhide))
.setRank(1)
.build());
}
if (!(boolean) Config.get(Config.Key.COREONLY) && root && Config.magiskVersionCode >= 0) {
shortCuts.add(new ShortcutInfo.Builder(context, "modules")
.setShortLabel(context.getString(R.string.modules))
.setIntent(new Intent(context, ClassMap.get(SplashActivity.class))
.putExtra(Const.Key.OPEN_SECTION, "modules")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_extension))
.setRank(3)
.build());
shortCuts.add(new ShortcutInfo.Builder(context, "downloads")
.setShortLabel(context.getString(R.string.downloads))
.setIntent(new Intent(context, ClassMap.get(SplashActivity.class))
.putExtra(Const.Key.OPEN_SECTION, "downloads")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_cloud_download))
.setRank(2)
.build());
}
return shortCuts;
}
}

View File

@@ -1,48 +0,0 @@
package com.topjohnwu.magisk.uicomponents;
import android.app.Activity;
import android.net.Uri;
import android.view.View;
import android.widget.TextView;
import com.google.android.material.snackbar.Snackbar;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Utils;
import androidx.annotation.StringRes;
public class SnackbarMaker {
public static Snackbar make(Activity activity, CharSequence text, int duration) {
View view = activity.findViewById(android.R.id.content);
return make(view, text, duration);
}
public static Snackbar make(Activity activity, @StringRes int resId, int duration) {
return make(activity, activity.getString(resId), duration);
}
public static Snackbar make(View view, CharSequence text, int duration) {
Snackbar snack = Snackbar.make(view, text, duration);
setup(snack);
return snack;
}
public static Snackbar make(View view, @StringRes int resId, int duration) {
Snackbar snack = Snackbar.make(view, resId, duration);
setup(snack);
return snack;
}
private static void setup(Snackbar snack) {
TextView text = snack.getView().findViewById(com.google.android.material.R.id.snackbar_text);
text.setMaxLines(Integer.MAX_VALUE);
}
public static void showUri(Activity activity, Uri uri) {
make(activity, activity.getString(R.string.internal_storage,
"/Download/" + Utils.getNameFromUri(activity, uri)),
Snackbar.LENGTH_LONG)
.setAction(R.string.ok, (v)->{}).show();
}
}

View File

@@ -1,59 +0,0 @@
package com.topjohnwu.magisk.uicomponents;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import butterknife.BindView;
import butterknife.Unbinder;
public class UpdateCardHolder {
@BindView(R.id.status_icon) public ImageView statusIcon;
@BindView(R.id.progress) public ProgressBar progress;
@BindView(R.id.status) public TextView status;
@BindView(R.id.current_version) public TextView currentVersion;
@BindView(R.id.latest_version) public TextView latestVersion;
@BindView(R.id.additional) public TextView additional;
@BindView(R.id.install) public Button install;
public View itemView;
public Unbinder unbinder;
public UpdateCardHolder(LayoutInflater inflater, ViewGroup root) {
itemView = inflater.inflate(R.layout.update_card, root, false);
unbinder = new UpdateCardHolder_ViewBinding(this, itemView);
}
public void setClickable(View.OnClickListener listener) {
itemView.setClickable(true);
itemView.setFocusable(true);
itemView.setOnClickListener(listener);
}
public void setValid(boolean valid) {
progress.setVisibility(View.GONE);
statusIcon.setVisibility(View.VISIBLE);
if (valid) {
install.setVisibility(View.VISIBLE);
latestVersion.setVisibility(View.VISIBLE);
} else {
install.setVisibility(View.GONE);
latestVersion.setVisibility(View.GONE);
}
}
public void reset() {
progress.setVisibility(View.VISIBLE);
statusIcon.setVisibility(View.INVISIBLE);
latestVersion.setVisibility(View.GONE);
install.setVisibility(View.GONE);
status.setText(R.string.checking_for_updates);
}
}

View File

@@ -1,53 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.UpdateCheckService;
import com.topjohnwu.magisk.tasks.CheckUpdates;
import java.util.concurrent.TimeUnit;
import androidx.work.Constraints;
import androidx.work.ExistingPeriodicWorkPolicy;
import androidx.work.NetworkType;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
public class AppUtils {
public static void scheduleUpdateCheck() {
if (Config.get(Config.Key.CHECK_UPDATES)) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
PeriodicWorkRequest request = new PeriodicWorkRequest
.Builder(ClassMap.get(UpdateCheckService.class), 12, TimeUnit.HOURS)
.setConstraints(constraints)
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork(
Const.ID.CHECK_MAGISK_UPDATE_WORKER_ID,
ExistingPeriodicWorkPolicy.REPLACE, request);
} else {
WorkManager.getInstance().cancelUniqueWork(Const.ID.CHECK_MAGISK_UPDATE_WORKER_ID);
CheckUpdates.check();
}
}
public static void openLink(Context context, Uri link) {
Intent intent = new Intent(Intent.ACTION_VIEW, link);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (intent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(intent);
} else {
Utils.toast(R.string.open_link_failed_toast, Toast.LENGTH_SHORT);
}
}
}

View File

@@ -1,92 +0,0 @@
package com.topjohnwu.magisk.utils;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.uicomponents.ProgressNotification;
import com.topjohnwu.net.Networking;
import com.topjohnwu.net.ResponseListener;
import com.topjohnwu.superuser.Shell;
import java.io.File;
import dalvik.system.DexClassLoader;
public class DownloadApp {
public static void upgrade(String name) {
dlInstall(name, new PatchPackageName());
}
public static void restore() {
String name = Utils.fmt("MagiskManager v%s(%d)",
Config.remoteManagerVersionString, Config.remoteManagerVersionCode);
dlInstall(name, new RestoreManager());
}
private static void dlInstall(String name, ManagerDownloadListener listener) {
File apk = new File(App.self.getCacheDir(), "manager.apk");
ProgressNotification progress = new ProgressNotification(name);
listener.progress = progress;
Networking.get(Config.managerLink)
.setExecutor(App.THREAD_POOL)
.setDownloadProgressListener(progress)
.setErrorHandler((conn, e) -> progress.dlFail())
.getAsFile(apk, listener);
}
private abstract static class ManagerDownloadListener implements ResponseListener<File> {
ProgressNotification progress;
}
private static class PatchPackageName extends ManagerDownloadListener {
@Override
public void onResponse(File apk) {
File patched = apk;
App app = App.self;
if (!app.getPackageName().equals(BuildConfig.APPLICATION_ID)) {
progress.getNotificationBuilder()
.setProgress(0, 0, true)
.setContentTitle(app.getString(R.string.hide_manager_title))
.setContentText("");
progress.update();
patched = new File(apk.getParent(), "patched.apk");
try {
// Try using the new APK to patch itself
ClassLoader loader = new DexClassLoader(apk.getPath(),
apk.getParent(), null, ClassLoader.getSystemClassLoader());
loader.loadClass("a.a")
.getMethod("patchAPK", String.class, String.class, String.class)
.invoke(null, apk.getPath(), patched.getPath(), app.getPackageName());
} catch (Exception e) {
e.printStackTrace();
// Fallback to use the current implementation
PatchAPK.patch(apk.getPath(), patched.getPath(), app.getPackageName());
}
}
APKInstall.install(app, patched);
progress.dismiss();
}
}
private static class RestoreManager extends ManagerDownloadListener {
@Override
public void onResponse(File apk) {
App app = App.self;
progress.getNotificationBuilder()
.setProgress(0, 0, true)
.setContentTitle(app.getString(R.string.restore_img_msg))
.setContentText("");
progress.update();
Config.export();
// Make it world readable
apk.setReadable(true, false);
if (Shell.su("pm install " + apk).exec().isSuccess())
RootUtils.rmAndLaunch(app.getPackageName(), BuildConfig.APPLICATION_ID);
progress.dismiss();
}
}
}

View File

@@ -1,148 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.widget.Toast;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.uicomponents.Notifications;
import com.topjohnwu.signing.JarMap;
import com.topjohnwu.signing.SignAPK;
import com.topjohnwu.superuser.Shell;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.IntBuffer;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import androidx.core.app.NotificationCompat;
public class PatchAPK {
public static final String LOWERALPHA = "abcdefghijklmnopqrstuvwxyz";
public static final String UPPERALPHA = LOWERALPHA.toUpperCase();
public static final String ALPHA = LOWERALPHA + UPPERALPHA;
public static final String DIGITS = "0123456789";
public static final String ALPHANUM = ALPHA + DIGITS;
public static final String ALPHANUMDOTS = ALPHANUM + "............";
private static String genPackageName(String prefix, int length) {
StringBuilder builder = new StringBuilder(length);
builder.append(prefix);
length -= prefix.length();
SecureRandom random = new SecureRandom();
char next, prev = prefix.charAt(prefix.length() - 1);
for (int i = 0; i < length; ++i) {
if (prev == '.' || i == length - 1) {
next = ALPHA.charAt(random.nextInt(ALPHA.length()));
} else {
next = ALPHANUMDOTS.charAt(random.nextInt(ALPHANUMDOTS.length()));
}
builder.append(next);
prev = next;
}
return builder.toString();
}
private static boolean findAndPatch(byte xml[], String from, String to) {
if (from.length() != to.length())
return false;
CharBuffer buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer();
List<Integer> offList = new ArrayList<>();
for (int i = 0; i < buf.length() - from.length(); ++i) {
boolean match = true;
for (int j = 0; j < from.length(); ++j) {
if (buf.get(i + j) != from.charAt(j)) {
match = false;
break;
}
}
if (match) {
offList.add(i);
i += from.length();
}
}
if (offList.isEmpty())
return false;
for (int off : offList) {
buf.position(off);
buf.put(to);
}
return true;
}
private static boolean findAndPatch(byte xml[], int a, int b) {
IntBuffer buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
int len = xml.length / 4;
for (int i = 0; i < len; ++i) {
if (buf.get(i) == a) {
buf.put(i, b);
return true;
}
}
return false;
}
private static boolean patchAndHide() {
App app = App.self;
// Generate a new app with random package name
File repack = new File(app.getFilesDir(), "patched.apk");
String pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length());
if (!patch(app.getPackageCodePath(), repack.getPath(), pkg))
return false;
// Install the application
repack.setReadable(true, false);
if (!Shell.su("pm install " + repack).exec().isSuccess())
return false;
Config.set(Config.Key.SU_MANAGER, pkg);
Config.export();
RootUtils.rmAndLaunch(BuildConfig.APPLICATION_ID, pkg);
return true;
}
public static boolean patch(String in, String out, String pkg) {
try {
JarMap jar = new JarMap(in);
JarEntry je = jar.getJarEntry(Const.ANDROID_MANIFEST);
byte xml[] = jar.getRawData(je);
if (!findAndPatch(xml, BuildConfig.APPLICATION_ID, pkg) ||
!findAndPatch(xml, R.string.app_name, R.string.re_app_name))
return false;
// Write in changes
jar.getOutputStream(je).write(xml);
SignAPK.sign(jar, new BufferedOutputStream(new FileOutputStream(out)));
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public static void hideManager() {
App.THREAD_POOL.execute(() -> {
App app = App.self;
NotificationCompat.Builder progress =
Notifications.progress(app.getString(R.string.hide_manager_title));
Notifications.mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build());
if(!patchAndHide())
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
Notifications.mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID);
});
}
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/su_request_background" />
<foreground>
<inset
android:drawable="@drawable/ic_cloud_download"
android:inset="30%" />
</foreground>
</adaptive-icon>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5zM5.12,5l0.81,-1h12l0.94,1H5.12z"/>
</vector>

Some files were not shown because too many files have changed in this diff Show More