Compare commits

..

1047 Commits
v16.7 ... v19.2

Author SHA1 Message Date
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
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
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
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
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
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
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
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
topjohnwu
b31402766e Add 7.0.0 changelog 2019-02-04 03:15:20 -05:00
topjohnwu
9ab3143bf0 Force preference screen to use our preference stored in DE 2019-02-04 03:13:01 -05:00
topjohnwu
81a0cddb9e Add DirectBoot support to receivers and SuRequestActivity
Close #1032, courtesy of @vvb2060
2019-02-04 01:58:04 -05:00
topjohnwu
f620ac769f Update newline in docs 2019-02-03 23:48:20 -05:00
topjohnwu
dc91041edd Update documentation 2019-02-03 23:37:38 -05:00
topjohnwu
6ee08b6717 Temporary remove API 16 support 2019-02-03 16:42:16 -05:00
Taras
5a2cd2ac84 Update Ukrainian translation 2019-02-03 16:13:44 -05:00
Albert I
2bd8448aaa Update Indonesian translations
Signed-off-by: Albert I <krascgq@outlook.co.id>
2019-02-03 16:13:30 -05:00
topjohnwu
2360adb592 Move bootctl binary out of Magisk Manager source
Close #1023
2019-02-03 16:11:47 -05:00
topjohnwu
c7301a5161 Better support for low API levels 2019-02-03 09:50:49 -05:00
topjohnwu
72270825c1 Prevent segmentation fault when resetprop is unsupported 2019-02-03 09:48:57 -05:00
topjohnwu
1e94f0a094 Some minor adjustments 2019-02-03 05:16:29 -05:00
topjohnwu
e39d2567ea More SDK 16 fixes 2019-02-03 04:59:04 -05:00
topjohnwu
949136c92a Small UI adjustments 2019-02-03 03:57:49 -05:00
topjohnwu
9f456a9b19 Do not show negative button for several dialogs 2019-02-03 03:57:49 -05:00
topjohnwu
4cf6ba25ca Make update cards more feasible on other languages 2019-02-03 03:57:49 -05:00
topjohnwu
093f971896 Fix small log error 2019-02-03 03:57:49 -05:00
Davy Defaud
df38a9da71 French translation fixes 2019-02-02 20:54:25 -05:00
vvb2060
813814c54a Update zh-rCN translation 2019-02-02 20:54:09 -05:00
dark-basic
68cb32f375 Update strings.xml 2019-02-02 20:52:31 -05:00
topjohnwu
93c9590b0f Add traditional Chinese translation 2019-02-02 13:35:52 -05:00
topjohnwu
619d979c39 Fix strings 2019-02-02 13:30:55 -05:00
topjohnwu
c30faad838 Allow all binder operations for root processes 2019-02-02 13:24:55 -05:00
JoanVC100
bea0de4980 Update Catalan translations 2019-02-02 13:23:44 -05:00
Rom
ef5a490415 Update French translation 2019-02-02 13:23:30 -05:00
Albert I
fa404285be Update Indonesian translations
Signed-off-by: Albert I <krascgq@outlook.co.id>
2019-02-02 13:23:15 -05:00
dark-basic
0e526258ff Update strings.xml
New lines added.
Adjustments here, and there.
---
Hey topjohnwu (o.o)/
Tip: Adjust update report text, since everything written does not appear. :D
2019-02-02 13:23:07 -05:00
topjohnwu
56d2fb9a3b Prevent Magisk Manager to run on pre-v18.0 2019-02-02 05:30:16 -05:00
topjohnwu
7c82690852 Cleanup resources 2019-02-02 05:18:29 -05:00
topjohnwu
62acc17e42 Support API 16 (Android 4.1)
Because why not
2019-02-02 05:06:13 -05:00
topjohnwu
9fbe5895b7 Use Intent rather than global variable 2019-02-02 04:22:25 -05:00
topjohnwu
6bbe0f07d4 Only load modules and repos if Magisk is installed properly 2019-02-02 04:19:14 -05:00
topjohnwu
bd3e0b9336 Optimize repo list fetching 2019-02-02 04:15:30 -05:00
topjohnwu
699debdaca Cast AsyncTask.THREAD_POOL_EXECUTOR to ThreadPoolExecutor 2019-02-02 02:50:49 -05:00
topjohnwu
70eba568af Do not check update twice 2019-02-02 02:27:15 -05:00
topjohnwu
bb7560e441 Add artificial delay to CheckUpdate 2019-02-02 01:09:53 -05:00
topjohnwu
43c0cac52f Fix splash screen on KitKat+ 2019-02-02 00:40:33 -05:00
tarasyyyk
4b4aa148a9 update Ukrainian translation 2019-02-01 15:55:56 -05:00
Oliver Cervera
c9c90c4e7f Update Italian translation
Update to reflect recent Magisk Manager changes.
2019-02-01 15:55:48 -05:00
vvb2060
99093e9a4c Update zh-rCN translation 2019-02-01 15:55:39 -05:00
vvb2060
2cf33d635d Setuid after read proc 2019-02-01 15:55:29 -05:00
topjohnwu
d6abaf846e Fix icon colors in light theme 2019-02-01 15:53:48 -05:00
topjohnwu
4b88131977 Fix snet on release builds 2019-02-01 06:21:55 -05:00
Rom
4520f46a57 Update for French translation 2019-02-01 04:40:50 -05:00
topjohnwu
348d47076a Finish Magisk Fragment UI
Remove AboutActivity at the same time
2019-02-01 04:39:54 -05:00
topjohnwu
6e7b90a184 Make advanced settings expandable 2019-02-01 00:36:13 -05:00
topjohnwu
28d7a7a6d2 Update libsu 2019-01-31 23:49:57 -05:00
topjohnwu
da13b5dbf2 Improve MagiskHide app listing
- Prevent platform apps from showing up
- Add new option to toggle whether to show system apps
2019-01-31 23:40:33 -05:00
dark-basic
a60710e3bb Update strings.xml
New linea added.
2019-01-31 03:54:12 -05:00
paphonb
7d2a2b9983 Add Thai translations 2019-01-31 03:53:54 -05:00
topjohnwu
749df5dacd Better method to change Locale 2019-01-31 03:48:45 -05:00
topjohnwu
af88b7c807 Move more code to app-core 2019-01-31 03:24:18 -05:00
topjohnwu
4091687733 Separate FingerprintHelper and AuthDialog 2019-01-31 00:05:59 -05:00
topjohnwu
cfb0a3ba2a Yet another restructuring 2019-01-30 23:23:49 -05:00
topjohnwu
6c4d082f35 Remove unnecessary BroadcastReceiver 2019-01-30 17:54:25 -05:00
topjohnwu
262185046a Add unbinder 2019-01-30 17:41:12 -05:00
topjohnwu
da9d00be7d Update Topic 2019-01-30 17:11:32 -05:00
topjohnwu
454abc388b Update SafetyNet 2019-01-30 17:11:03 -05:00
topjohnwu
3e9174deed Remove core only card 2019-01-30 14:45:45 -05:00
topjohnwu
4df1047b07 Native project restructuring 2019-01-30 03:35:07 -05:00
topjohnwu
60f69feaff Full project restructuring 2019-01-30 03:10:12 -05:00
topjohnwu
5df426380d More complete DelegateWorker 2019-01-28 16:12:59 -05:00
topjohnwu
976c299657 Separate ExpandableViewHolder 2019-01-28 14:51:29 -05:00
topjohnwu
18ab6b51fd Magisk info UI redesign
Major UI overhaul WIP
2019-01-28 14:24:52 -05:00
topjohnwu
4be8bd4d18 Use proper arrow colors 2019-01-27 01:13:39 -05:00
topjohnwu
075bc4a6d5 Update dependencies 2019-01-26 15:07:54 -05:00
topjohnwu
1c61feb368 Update native su connect broadcast code
Use -p <pkg> for supported platforms
2019-01-26 14:53:49 -05:00
topjohnwu
d32b788988 Rewrite exec_command 2019-01-26 13:39:24 -05:00
topjohnwu
7565ea2787 Remove strdup2 2019-01-26 13:00:19 -05:00
topjohnwu
9275975b2c Re-organize functions 2019-01-26 06:00:23 -05:00
SakuraSa233
b3e0d5ba58 update: Japanese translation 2019-01-26 03:48:22 -05:00
topjohnwu
841dee94c6 Animate arrows 2019-01-26 03:34:09 -05:00
topjohnwu
71638191ee Cleanup messy logging code 2019-01-26 02:41:25 -05:00
Ian Macdonald
9d6851cbbd Redundant use of cat(1). 2019-01-25 17:39:15 -05:00
topjohnwu
d633d05803 Fix patch from #989
Close #991, close #993
2019-01-25 17:38:48 -05:00
am4z1ng
45d7879d7b Refresh logs page after clearing 2019-01-24 20:11:26 -05:00
topjohnwu
4a8375355c Simplify layouts 2019-01-24 15:15:31 -05:00
topjohnwu
d3ebd763a2 More ConstraintLayout 2019-01-24 14:41:12 -05:00
topjohnwu
b7f69238a1 Fix segfault on several devices 2019-01-22 17:19:10 -05:00
topjohnwu
118a9f224e Fix crash when clean install 2019-01-22 03:52:53 -05:00
topjohnwu
a44dc8df37 Migrate to ConstraintLayout (WIP) 2019-01-22 03:52:29 -05:00
topjohnwu
abf19aad74 Remove unused layout 2019-01-21 23:49:27 -05:00
topjohnwu
d73127b175 Merge DonationActivity to AboutActivity 2019-01-21 17:14:48 -05:00
topjohnwu
00f4242fa4 Remember user selection of su timeout
Close #535
2019-01-21 16:26:59 -05:00
topjohnwu
f6a4510659 Update WorkManager 2019-01-21 16:18:27 -05:00
topjohnwu
33215424d8 Small tweaks 2019-01-21 16:12:05 -05:00
topjohnwu
6094bc9210 Use integer for string 2019-01-21 16:06:06 -05:00
topjohnwu
a8cd9b3aa9 Create BasePreferenceFragment 2019-01-21 16:00:58 -05:00
topjohnwu
a189dec1c8 Centralize configuration management 2019-01-21 15:49:03 -05:00
topjohnwu
858216796a Allow API 17 installation 2019-01-20 18:17:24 -05:00
topjohnwu
f24342f117 Disable several features in Jellybean 2019-01-20 17:52:19 -05:00
topjohnwu
50b55a77de Don't mount images when running core-only mode 2019-01-20 17:01:59 -05:00
topjohnwu
fdf167db11 Get API level from build.prop 2019-01-20 15:20:34 -05:00
topjohnwu
a4f8bd4ee0 Bump to C++17 2019-01-20 00:07:58 -05:00
topjohnwu
3e4c12cf56 Migrate to STL 2019-01-19 23:59:37 -05:00
topjohnwu
03c39e692a Switch to libc++ 2019-01-19 13:47:33 -05:00
topjohnwu
ab63b0e970 Don't show progress if content length is unavailable 2019-01-18 16:28:12 -05:00
Ivan Kutepov
6ea42a35a9 Fix reqSizeM check in mount_magisk_img function 2019-01-17 10:19:59 -05:00
dark-basic
d366dfc72b Update strings.xml
Add new line
2019-01-17 10:19:50 -05:00
topjohnwu
85042fbe25 Use the least possible memory for boot signing and verification
Close #971, close #966
2019-01-16 17:12:23 -05:00
topjohnwu
23e5188422 Update scripts
1. Update build.py to use f-strings
2. Directly append busybox binaries to update-binary
3. Remove b64xz
2019-01-15 08:32:18 -05:00
topjohnwu
93ee0c8798 Update Android Studio 2019-01-14 14:41:07 -05:00
topjohnwu
aa88486f59 Fix crashes when APK stored in cache dir 2019-01-13 13:34:51 -05:00
topjohnwu
1d9c441038 Fix string errors and update trad. Chinese translation 2019-01-13 13:23:57 -05:00
Pierre-Hugues Husson
928c56bda2 Don't use (deleted) copy constructor, use constructor directly to fix build 2019-01-13 13:19:00 -05:00
Pierre-Hugues Husson
bc6f37eecc Fixes build error
device/phh/treble/magisk/Magisk/native/jni/systemproperties/prop_area.cpp:386:3: error: no matching function for call to 'atomic_store_explicit'
  atomic_store_explicit(&node->prop, 0, memory_order_release);
  ^~~~~~~~~~~~~~~~~~~~~
external/libcxx/include/atomic:1220:1: note: candidate template ignored: deduced conflicting types for parameter '_Tp' ('unsigned int' vs. 'int')
atomic_store_explicit(volatile atomic<_Tp>* __o, _Tp __d, memory_order __m) _NOEXCEPT
^
external/libcxx/include/atomic:1229:1: note: candidate template ignored: deduced conflicting types for parameter '_Tp' ('unsigned int' vs. 'int')
atomic_store_explicit(atomic<_Tp>* __o, _Tp __d, memory_order __m) _NOEXCEPT
2019-01-13 13:19:00 -05:00
Taras
ffebff8cab Update Ukrainian translation 2019-01-13 13:18:18 -05:00
vvb2060
6d6bd89d6b Update zh-rCN translation 2019-01-13 13:17:59 -05:00
Zackptg5
0a64a7e5d4 Update util_functions.sh
Eliminates `cat: write error`
2019-01-13 13:17:45 -05:00
Albert I
586488af48 Update Indonesian translations
Signed-off-by: Albert I <krascgq@outlook.co.id>
2019-01-13 13:17:03 -05:00
topjohnwu
7b9a45f1a8 Fix post ota scripts 2019-01-13 13:08:39 -05:00
topjohnwu
4ff70aefac Fix stub compile error
Close #950
2019-01-08 04:27:55 -05:00
Davy Defaud
d63b5d7014 A full update to the French translation strings 2019-01-04 18:31:41 +08:00
topjohnwu
ab5f6bf901 Remove unnecessary css files 2019-01-04 18:06:33 +08:00
topjohnwu
04088b34a2 Update gradle scripts 2019-01-04 17:55:17 +08:00
topjohnwu
3edcd2004e Upgrade dependencies 2019-01-04 14:09:12 +08:00
topjohnwu
7bd52d0245 Update net module 2019-01-01 18:45:48 +08:00
topjohnwu
1df65940b9 Support Kirin 960 devices
Close #928
2018-12-31 16:09:14 +08:00
Rom
d9ace35c3e French translation update 2018-12-31 16:06:21 +08:00
Oliver Cervera
1fe92cee6f Update Italian strings
Added latest string
2018-12-31 16:06:02 +08:00
topjohnwu
267868c3b0 Switch internal download dir to cache dir 2018-12-31 16:05:29 +08:00
topjohnwu
6d27eb7f64 Dynamic load updated APK for patching
Magisk Manager sometimes updates the code for patching the APK due to several changes.
When an old manager tries to patch an updated APK using its internal methods, it is
sometimes incomplete, or simply won't work at all.

This commit exposes an API that can be dynamically loaded from an old app to invoke the
updated patchAPK method from the downloaded new APK.
2018-12-31 15:53:24 +08:00
topjohnwu
2e10fa494f Update WorkManager dependencies 2018-12-31 15:43:46 +08:00
topjohnwu
039be65a89 Fix Magisk Manager hiding after using WorkManager 2018-12-31 14:55:03 +08:00
topjohnwu
570ecd9987 Prevent unnecessary setTextColor 2018-12-31 03:04:30 +08:00
topjohnwu
a575180475 Use recyclerlist for FlashActivity console 2018-12-31 02:47:30 +08:00
topjohnwu
07d1a20f3d Improve StringListAdapter 2018-12-31 02:46:50 +08:00
topjohnwu
76491cbb31 Use more general solution 2018-12-31 01:50:41 +08:00
topjohnwu
bf7d6ddcb2 Use recyclerview to show Magisk logs 2018-12-30 22:15:00 +08:00
topjohnwu
44b969e0b6 Minor notification changes 2018-12-30 01:06:31 +08:00
topjohnwu
176e470497 Use platform icons for notifications 2018-12-29 17:56:24 +08:00
topjohnwu
646a10d9bf Use foreground service for downloading modules 2018-12-29 17:49:41 +08:00
topjohnwu
52137fd64f Remove useless service 2018-12-29 14:14:29 +08:00
topjohnwu
3ccac8c3b8 Terminate forked children for exec after failure 2018-12-28 16:33:26 +08:00
topjohnwu
0be158afa1 Official KitKat support 2018-12-28 16:03:23 +08:00
topjohnwu
e6942e0122 Use resource alias for launcher icon on API 21-25 2018-12-28 05:29:28 +08:00
topjohnwu
496b22026f Backwards compatible to SDK 17 2018-12-28 05:15:59 +08:00
topjohnwu
bb2df02dff Update net module targetSdkVersion 2018-12-27 22:28:00 +08:00
Igor Sorocean
4c850ecc31 Update romanian translation 2018-12-27 22:27:02 +08:00
topjohnwu
da9c6f6e23 Switch to WorkManager 2018-12-27 22:07:47 +08:00
topjohnwu
58ba0b0b4e Stop showing dialog when update available 2018-12-27 18:11:03 +08:00
topjohnwu
1d0b87246a Handle vector drawables 2018-12-27 17:28:06 +08:00
topjohnwu
920b60da19 Support SDK 17 for stub APK 2018-12-27 14:35:55 +08:00
topjohnwu
523e66294b Simpler su_info caching system 2018-12-26 11:56:49 +08:00
topjohnwu
23f8f35098 Stop using system STL since it is no longer supported 2018-12-25 19:38:44 +08:00
topjohnwu
8d210b5e37 Enhance EMUI 9 user experience 2018-12-25 01:08:46 +08:00
topjohnwu
3c6c0e6700 Support EMUI 9.0 2018-12-24 21:36:37 +08:00
topjohnwu
01344c451f Move more logic to core module 2018-12-24 21:16:51 +08:00
topjohnwu
2c42c79482 Fix crashes on OOS 2018-12-24 21:04:58 +08:00
topjohnwu
75c2cfe7bf Run onResult in main thread 2018-12-24 20:51:14 +08:00
topjohnwu
6c6eeb3f28 Several minor adjustments 2018-12-24 18:23:33 +08:00
kykdev
31053e0cd0 Update Korean translation 2018-12-24 01:49:52 -05:00
topjohnwu
aad9aced18 Render Markdown natively
Stop using problematic WebView
2018-12-23 19:29:25 +08:00
Imre Kristoffer Eilertsen
dd2c9eeafe Removed strings that weren't to be translated, just in case 2018-12-14 19:02:51 -05:00
Imre Kristoffer Eilertsen
740d76bc42 Created a Norwegian Bokmål translation, part 3/3(?) 2018-12-14 19:02:51 -05:00
Imre Kristoffer Eilertsen
45f4f5afd9 Created a Norwegian Bokmål translation, part 2/3 2018-12-14 19:02:51 -05:00
Imre Kristoffer Eilertsen
e875de3e98 Created a Norwegian Bokmål translation, part 1 2018-12-14 19:02:51 -05:00
topjohnwu
fd7786633d Small refactoring fixes 2018-12-13 06:05:19 -05:00
topjohnwu
bce9cfa39a Update LocaleManager 2018-12-13 05:53:39 -05:00
topjohnwu
ff3d66a661 Separate backend logic from frontend UI 2018-12-13 04:35:50 -05:00
topjohnwu
006d28abd5 Minor documentation fix 2018-12-12 06:10:11 -05:00
topjohnwu
59b1e63bdf Use internal library for networking 2018-12-12 05:52:13 -05:00
Rom
eab74ef06b Little fix for French translation 2018-12-11 04:54:09 -05:00
Mevlüt TOPÇU
89837de9b0 Update strings.xml 2018-12-11 04:53:55 -05:00
topjohnwu
b245931c79 Prevent duplicates when "." or ".." occurs 2018-12-09 22:12:04 -05:00
topjohnwu
fd5e42698c Update docs
Close #823
2018-12-09 14:49:35 -05:00
topjohnwu
c75512ba6e Don't try to force reload if network drop 2018-12-09 03:54:57 -05:00
Oliver Cervera
a22e7aa0b1 Update italian translation
Added missing host systemless toast notification
2018-12-09 03:53:31 -05:00
Rom
020dd97f99 Update French translation 2018-12-09 03:53:18 -05:00
topjohnwu
e9882d9702 Use am to launch apps
Close #838
2018-12-09 03:52:13 -05:00
topjohnwu
fd4a27dbf2 Fix NPE when unexpected network drop
Fix #839
2018-12-09 03:28:28 -05:00
topjohnwu
9c63e31da6 Remove unnecessary empty lines 2018-12-08 03:58:33 -05:00
topjohnwu
c91f809eba Remove all backwards compatibility nonsense
This also allows full obfuscation
2018-12-08 03:54:00 -05:00
topjohnwu
a54eaf5371 Hardcode snet extension URL and version 2018-12-08 00:43:50 -05:00
topjohnwu
8032bd4bb9 Add v6.1.0 changelog 2018-12-07 23:25:49 -05:00
topjohnwu
ea1beec2f7 Tweak some strings 2018-12-07 22:08:03 -05:00
JoanVC100
05f2f6820e Little correction ca-string 2018-12-07 21:57:30 -05:00
topjohnwu
0f5f15a5ce Stop signing module zips
Nobody should be using the signature verification in recoveries
2018-12-07 21:56:54 -05:00
topjohnwu
14ac37e8a5 Fix and optimize APK installations 2018-12-07 21:42:53 -05:00
topjohnwu
1fae89cbb6 Add new cpio command: "exists", to magiskboot 2018-12-05 20:27:48 -05:00
topjohnwu
8b4008798f Add backward compat paths 2018-12-05 20:10:59 -05:00
topjohnwu
fd4faf59b8 Use tr for replacing whitespace to newline
Close #824
2018-12-05 20:07:15 -05:00
topjohnwu
109891d668 Make apk_install more portable 2018-12-05 18:36:27 -05:00
topjohnwu
bdea796121 Fix strings 2018-12-05 17:39:32 -05:00
Oliver Cervera
c8813c05c9 Italian translation update
Update based on latest commits, mainly from here ee2c801fe0
2018-12-05 12:53:54 -05:00
Pzqqt
1cff08ce5d Fix possible error block counts
Add "-k" parameter to force the unit to 1024 bytes.
2018-12-05 12:53:06 -05:00
topjohnwu
a868118f6f Use defined symbols in SDK 16 libsqlite.so 2018-12-05 12:48:01 -05:00
topjohnwu
e5c62f5750 Allow post-fs-data module scripts to change module state 2018-12-05 12:47:29 -05:00
topjohnwu
4084e8790b Fix APK installation on old Android versions 2018-12-04 20:27:09 -05:00
linar10
8d931dd773 Update strings.xml 2018-12-04 14:35:18 -05:00
dark-basic
25d6366297 Update String Spanish full ver
New aggregate lines and structure changes
2018-12-04 14:34:41 -05:00
topjohnwu
08cd5b81d1 Try to repair boot_hdr v1 entries 2018-12-04 03:30:43 -05:00
Albert I
5d3a8a5b1a Update Indonesian translations
Signed-off-by: Albert I <krascgq@outlook.co.id>
2018-12-04 02:15:15 -05:00
topjohnwu
79b84da4b8 Adjust for new FrankeNDK 2018-12-04 02:08:51 -05:00
topjohnwu
68b07c5913 Use flags for smaller binary 2018-12-03 19:43:02 -05:00
topjohnwu
553db9124d Update trad. Chinese translation 2018-12-03 10:14:13 -05:00
topjohnwu
b495f37299 Optimize imports 2018-12-03 10:09:14 -05:00
Rom
1915547594 Update French translation 2018-12-03 10:07:57 -05:00
vvb2060
03de29164a Update zh-rCN translation 2018-12-03 10:06:58 -05:00
topjohnwu
86d8b50547 Update CheckUpdate 2018-12-03 10:05:33 -05:00
topjohnwu
7b04386162 Patch app label when repackaging 2018-12-03 09:52:41 -05:00
topjohnwu
07bfdf3e4d Allow multiple progress notifications 2018-12-03 02:28:20 -05:00
topjohnwu
d510224e2a Use notifications for hiding manager 2018-12-03 02:24:07 -05:00
topjohnwu
e658f9297d Make progress notifications persist 2018-12-03 01:52:36 -05:00
topjohnwu
2b502e9a0f Small reorganization 2018-12-03 01:44:13 -05:00
topjohnwu
59141f9bbe Show failure when download fails 2018-12-02 23:44:56 -05:00
topjohnwu
3af66b72f2 Use notifications when downloading modules 2018-12-02 23:41:16 -05:00
topjohnwu
422c24bd68 Remove debug loggin in GeneralReceiver 2018-12-02 22:52:23 -05:00
topjohnwu
f0f87c8eb9 Reduce BroadcastReceivers 2018-12-02 16:53:00 -05:00
topjohnwu
80dad54119 Some cleanups 2018-12-02 15:28:18 -05:00
topjohnwu
56a76df28e Fix string resources in shortcut 2018-12-02 15:16:05 -05:00
topjohnwu
ee2c801fe0 Better progress notifications 2018-12-02 15:15:42 -05:00
Rom
fc314cc248 French translation update 2018-12-02 12:19:31 -05:00
topjohnwu
fe231a4c80 Rename app name to Manager 2018-12-02 05:36:14 -05:00
Eray Rafet
2e2bbe0a7f A small fix 2018-12-02 05:34:51 -05:00
topjohnwu
857e6e8345 Tweak notifications 2018-12-02 05:33:53 -05:00
topjohnwu
3402981ada Move some string resources 2018-12-02 05:15:16 -05:00
topjohnwu
f401e577e5 Better Proguard optimization 2018-12-02 04:56:13 -05:00
topjohnwu
0241a50c6f Stop using platform provided DownloadManager 2018-12-02 04:47:57 -05:00
topjohnwu
2a2e1236fc Use magic macros 2018-12-01 03:53:58 -05:00
topjohnwu
9b170f2b4f Switch from deprecated AUDITDENY to DONTAUDIT 2018-11-29 06:42:04 -05:00
topjohnwu
51e9ff59de Temporarily suppress warnings when applying Magisk rules 2018-11-29 06:31:05 -05:00
topjohnwu
2977dbcded Remove all dontaudit in magisk rules 2018-11-29 06:28:37 -05:00
topjohnwu
ac60b51035 Support removing redundant avtab nodes 2018-11-29 05:42:08 -05:00
topjohnwu
4c2f33a089 Remove '--install' 2018-11-29 04:35:43 -05:00
topjohnwu
3b071116ac Update magiskpolicy
- Generalize avtab node extraction and insertion
- Add new supported rules: type_change, type_member
- Update help message with official policy language
2018-11-29 03:46:29 -05:00
Oliver Cervera
a9f265a591 Small grammatical changes / values-it 2018-11-28 01:41:05 -05:00
Eray Rafet
5b62fc8103 Update Bulgarian translation 2018-11-28 01:40:50 -05:00
Eray Rafet
0598f5f89a Update Bulgarian translation
Grammar, spelling and punctuation fixes
2018-11-28 01:40:41 -05:00
topjohnwu
f723427b8b Add built-in procfs protection on SDK 24+
More information in the Medium Post:
https://medium.com/@topjohnwu/from-anime-game-to-android-system-security-vulnerability-9b955a182f20
2018-11-28 01:27:32 -05:00
topjohnwu
f69a004c1c Use raw execve
Some devices have broken libc...
2018-11-28 00:07:57 -05:00
topjohnwu
1134b18a8b Rename application label to "Magic" to prevent detection 2018-11-27 03:56:14 -05:00
topjohnwu
2e4aa507f7 Use magisk to clone file attributes 2018-11-27 03:56:14 -05:00
topjohnwu
5fb96cdcf4 Auto launch new app after repackaging/restoring Manager 2018-11-27 03:56:14 -05:00
topjohnwu
e8cba3524e Kill target processes properly 2018-11-27 03:56:14 -05:00
younis12c
7e6b5363f1 Update strings.xml
complete translation added
2018-11-26 20:13:31 -05:00
topjohnwu
29457a1d28 Small adjustments 2018-11-26 03:26:45 -05:00
topjohnwu
731455f164 Update exec functions signatures 2018-11-26 03:06:48 -05:00
topjohnwu
b01a8cace6 Always try native accept4 2018-11-26 02:57:34 -05:00
vvb2060
72db5b4fac Update zh-rCN translation 2018-11-25 17:04:45 -05:00
topjohnwu
ddfd42994e Module id and name can no longer be null
Close #797
2018-11-25 17:04:23 -05:00
topjohnwu
2a9ff9c5ef Update dependencies 2018-11-25 03:33:41 -05:00
Ilya Kushnir
6d49f05356 Minor fixes to RU strings 2018-11-24 15:53:42 -05:00
Albert I
85a5e62e36 Update Indonesian translations
Signed-off-by: Albert I <krascgq@outlook.co.id>
2018-11-24 15:53:35 -05:00
topjohnwu
e67965a381 Silent some errors 2018-11-24 15:53:15 -05:00
topjohnwu
ec4723096f Prevent file descriptor from unclosed 2018-11-23 21:15:44 -05:00
topjohnwu
762b678d24 Prevent any SELinux issues of root shell streams 2018-11-23 21:08:06 -05:00
topjohnwu
38fcc57bbf Use component name as targets
Services can name their process name arbitrarily, for instance the service in
com.google.android.gms that is responsible for SafetyNet is named
com.google.android.gms.unstable. There are many apps out in the wild use
dedicated services with special names to detect root, and previously the user
is expected to add all of them to the hide list.

In this commit, we change from targeting process names to component names.
On Android, component names are composed of <pkg>/<cls>. When targeting
component names, we can always know what application spawned the new process.
This means that if the user adds a package name to the hidelist, MagiskHide can
now target ALL possible processes of that specific application.

To abide with this change, the default SafetyNet target is now changed from
com.google.android.gms.unstable (process name) to
com.google.android.gms/.droidguard.DroidGuardService (component name)
2018-11-23 15:47:49 -05:00
topjohnwu
c8c57c74cc Optimize proc_monitor 2018-11-23 14:32:33 -05:00
topjohnwu
0784448c69 Remove /.backup folder on start 2018-11-20 05:24:40 -05:00
topjohnwu
de0064af47 Fix SIGWINCH never followed
Close #786
2018-11-20 04:40:42 -05:00
topjohnwu
baae1fc84f Modernize selinux stub 2018-11-20 03:49:44 -05:00
topjohnwu
2ab999f4ca Fix bug in DB query wrapper 2018-11-20 02:20:49 -05:00
topjohnwu
c9f390d6e0 Abort upon any error occurred 2018-11-20 02:20:49 -05:00
Igor Sorocean
af05922ecc Update romanian strings 2018-11-20 02:19:52 -05:00
Nguyễn Trung Hậu
299edbf3ab Updated Vietnamese translations 2018-11-20 02:19:42 -05:00
Rom
c8abed9d48 French translation update 2018-11-20 02:19:30 -05:00
topjohnwu
3622c49ce1 Update busybox 2018-11-18 15:58:41 -05:00
topjohnwu
0462e9a7d9 Update external dependencies 2018-11-18 03:34:59 -05:00
topjohnwu
c3a6091908 Update to 1.29.3 2018-11-18 02:45:21 -05:00
topjohnwu
ab5fedda0b Prevent Magisk database race condition
The database should only be accessed by a single process, which is magiskd.
This means 'magisk --sqlite [SQL]' has to be updated to pass the SQL command to the daemon.
In addition, open the database connection with SQLITE_OPEN_FULLMUTEX to support multithread in magiskd.
2018-11-16 03:20:30 -05:00
topjohnwu
ba70269398 Directly print output over socket 2018-11-16 01:49:15 -05:00
topjohnwu
77fd5fa7de Do not follow symlink when checking legacy paths 2018-11-16 01:16:25 -05:00
topjohnwu
ab74290fe3 Move magiskhide config into database 2018-11-16 01:15:34 -05:00
topjohnwu
3aad9d8166 Add CLI to detect MagiskHide status 2018-11-16 00:37:41 -05:00
topjohnwu
572e078d87 Fully deprecate <mount_point>/.core folder
Symlinks are preserved for backwards compatibility
2018-11-15 22:55:28 -05:00
topjohnwu
ee4548230b Disable native systemless hosts, add built-in systemless hosts module 2018-11-15 13:57:41 -05:00
topjohnwu
96b93bd876 Add function to find manager APK
Close #673
2018-11-15 03:12:31 -05:00
marciozomb13
927f69fe30 Brazilian Portuguese Update 2018-11-15 03:03:21 -05:00
Ian Macdonald
7e9ad5927a Fix grammatical errors, unnatural-sounding English and bad punctuation 2018-11-15 03:03:06 -05:00
Ian Macdonald
6d6b07865e Add 15 and 45 second Request Timeout options. 2018-11-15 03:02:45 -05:00
topjohnwu
376e7977f0 Deprecate path /sbin/.core, switch to /sbin/.magisk
Symlink is preserved for backwards compatibility
2018-11-15 01:36:03 -05:00
topjohnwu
83ae66daea Change stock boot image SHA1 backup method 2018-11-15 00:33:20 -05:00
topjohnwu
89e0be0099 Fix a bug causing magiskhide CLI freezing 2018-11-13 02:22:55 -05:00
topjohnwu
ef40c1212e Prevent infinite loop if process is killed
Close #761
2018-11-13 02:11:02 -05:00
topjohnwu
3a2a2a4ffa Micro optimizations 2018-11-13 02:07:02 -05:00
topjohnwu
9592a69986 Prevent unmounting non-custom mount points 2018-11-13 01:53:48 -05:00
topjohnwu
89be07e1f2 Update to libsu 2.0.3 2018-11-13 00:21:42 -05:00
topjohnwu
c61c3ae0e9 Fix su shell environment setup 2018-11-10 02:17:13 -05:00
topjohnwu
817350c8c5 Update AndroidX 2018-11-09 22:04:04 -05:00
topjohnwu
3603b7c82b Move cmdline and extra_cmdline to the same line 2018-11-08 20:57:30 -05:00
topjohnwu
5743c72cca Minor cleanup 2018-11-08 15:23:36 -05:00
topjohnwu
4cdd66ceff Fix lowmemorykiller crash hell in Pixel 3 2018-11-08 13:41:03 -05:00
topjohnwu
d3947d2cfa Adjust logging in magiskpolicy 2018-11-08 06:43:11 -05:00
topjohnwu
07718b994a Fix magiskinit
The behavior of C and C++ is slightly different, and causes unable to set excl_list
2018-11-08 06:07:52 -05:00
topjohnwu
ef9d463bd7 Fix PLOGE 2018-11-08 06:07:02 -05:00
topjohnwu
8745c7884e Rename Array to Vector
Finally get rid of the C style vector, rename the template class to its proper name
2018-11-08 05:03:59 -05:00
topjohnwu
b6965105b7 Better parsing logic 2018-11-08 04:57:16 -05:00
topjohnwu
3d269fe8be Migrate MagiskInit to C++ 2018-11-08 04:20:16 -05:00
topjohnwu
be5f00aa1a Prevent stack overflow when managing hide list 2018-11-07 22:46:56 -05:00
topjohnwu
59ba350f34 Fix copy and move assigments of Array 2018-11-07 04:09:37 -05:00
topjohnwu
803c5377a6 Clean init.c 2018-11-07 02:21:15 -05:00
topjohnwu
7c12bf7fa1 Modernize code base 2018-11-07 02:10:38 -05:00
topjohnwu
ca35a9681f Minor code improvements 2018-11-06 05:02:30 -05:00
topjohnwu
9fe5f37337 Minor code improvements 2018-11-05 14:37:47 -05:00
topjohnwu
0742901cd2 Modernize database code 2018-11-04 18:24:08 -05:00
topjohnwu
5e4d2dedbe Minor log_daemon changes 2018-11-04 17:23:08 -05:00
topjohnwu
411ea56a3e Add personal update script to gitignore 2018-11-04 04:16:11 -05:00
topjohnwu
cda57dd4b4 Fully migrate Magisk to C++ 2018-11-04 04:15:51 -05:00
topjohnwu
4351de503f Migrate exec function to C++ arrays 2018-11-03 04:03:11 -04:00
topjohnwu
6339ba6bfb Upgrade libutils to C++ 2018-11-03 03:06:01 -04:00
topjohnwu
ef6677f43d Source reorganization 2018-11-03 00:26:04 -04:00
topjohnwu
a7824af5a8 Expose persist prop API 2018-11-03 00:15:21 -04:00
vvb2060
1eb7d7b7a8 Add FLAG_INCLUDE_STOPPED_PACKAGES for broadcast 2018-11-03 00:04:27 -04:00
topjohnwu
11c33d4447 Migrate resetprop to C++ 2018-11-02 23:56:15 -04:00
topjohnwu
b8a3cc8b60 Separate magiskhide logic from main daemon 2018-11-01 14:08:33 -04:00
topjohnwu
27c688252d Store hidelist in magisk database 2018-11-01 13:23:12 -04:00
topjohnwu
3e2afd4b1d Better debugging output 2018-11-01 01:16:15 -04:00
topjohnwu
f45b0686d2 Mount ext4 images with noatime flag 2018-10-29 21:44:22 -04:00
vvb2060
1f3f881f81 Skip files when scanning modules 2018-10-28 17:21:58 -04:00
topjohnwu
ceb51bb14f daemon.c uses external flags 2018-10-28 16:55:51 -04:00
topjohnwu
3e22573d8d Upgrade snet extension 2018-10-28 16:55:51 -04:00
topjohnwu
79418a3767 Upgrade Bouncycastle 2018-10-28 16:55:51 -04:00
Shahmi Saidi
40d4683de1 Hint what FBE means in details.md 2018-10-28 15:15:19 -04:00
topjohnwu
79e5b54ec7 Remove redundant semicolon 2018-10-28 15:13:30 -04:00
topjohnwu
bd81923f2f Revert "Make dark theme cards slightly darker"
This reverts commit 675d6d8328.
2018-10-28 14:59:45 -04:00
topjohnwu
69560b8ad7 Fix and prevent crashes 2018-10-28 14:54:07 -04:00
topjohnwu
dc413e7b73 Retry db construction if first time failed 2018-10-28 14:49:04 -04:00
topjohnwu
7fc00c446b Buffer OutputStream to prevent broken pipe error 2018-10-28 05:25:33 -04:00
topjohnwu
2efc423cf8 Add missing flags and move debug logging logic to libutils 2018-10-28 04:25:31 -04:00
topjohnwu
8ec3086cdd Make sure magisklogd is properly initialized 2018-10-28 04:24:53 -04:00
topjohnwu
5fc7079023 Sort Policies before returning 2018-10-28 03:00:49 -04:00
topjohnwu
bfbd254be7 Update donation link 2018-10-28 02:48:01 -04:00
topjohnwu
f8ea43466c Only allow device owner to hide/restore Magisk Manager 2018-10-28 00:58:22 -04:00
topjohnwu
75ab1fa570 Micro optimizations 2018-10-28 00:54:56 -04:00
topjohnwu
bf4a46d57c Optimize logging in Magisk Manager 2018-10-27 22:06:24 -04:00
topjohnwu
1046dd5eda Default to cmdline logging 2018-10-27 18:34:38 -04:00
topjohnwu
f9e32a119a Fix bug when query database with specific keys 2018-10-27 17:56:20 -04:00
topjohnwu
dbb8b8a439 Handle magisk.db completely natively
Prevent database corruption due to different Android application sqlite default settings
2018-10-27 17:54:48 -04:00
topjohnwu
2a65c3dc8f Prepare for new database implementation 2018-10-27 17:38:23 -04:00
topjohnwu
f17ec9e9d7 Update sqlite header 2018-10-27 03:30:20 -04:00
Nicholas
675d6d8328 Make dark theme cards slightly darker
Use #323232 instead of #424242

Of course this is just a suggestion, use other codes if you wish. I just find the current color a bit too light for a dark theme.
2018-10-26 17:09:56 -04:00
topjohnwu
6dc9ccad75 Use const char* 2018-10-26 17:02:56 -04:00
topjohnwu
6add02702b Fix bug in MagiskBoot 2018-10-26 17:02:07 -04:00
topjohnwu
958d6377e3 Improve XML string matching code 2018-10-26 02:50:45 -04:00
topjohnwu
9954154ca2 Move functions out of libutils 2018-10-24 22:23:14 -04:00
topjohnwu
4ecbf8c12c Remove recovery_dtbo when cleanup 2018-10-24 22:23:14 -04:00
topjohnwu
fc8a3c5fb4 Migrate MagiskBoot to C++ 2018-10-24 22:23:14 -04:00
vvb2060
01e7dff1a0 Fix crash when using other su 2018-10-24 04:59:29 -04:00
topjohnwu
018c0064cd Make sure boot_img is initialized correctly 2018-10-22 01:58:50 -04:00
topjohnwu
c2b016370b Make a copy of logcat and use that instead
When Magisk is magic mounting /system/bin, there is a chance that logcat would be temporarily unavailable. Leave a copy and use that for magisklogd
2018-10-20 21:46:12 -04:00
daveyannihilation
fc791b4371 Fix Dark theme to display cards as slightly lighter than background as per Material Design standards. Also redirect colors to app as opposed to calling on framework 2018-10-20 21:13:13 -04:00
topjohnwu
f76bb009f4 Update changelogs 2018-10-20 20:11:09 -04:00
topjohnwu
8a1292b295 Ask permissions to read internal storage 2018-10-20 19:42:46 -04:00
topjohnwu
d7d80d3fc1 Update encryption detection for determining default flags 2018-10-20 17:10:35 -04:00
topjohnwu
41b01003fd Always ACK before doing anything 2018-10-20 16:12:08 -04:00
topjohnwu
6557070ae1 Try to flush database before uninstalling 2018-10-20 15:31:41 -04:00
topjohnwu
e7e580e177 Remove support for Magisk lower than 1500 2018-10-20 15:04:15 -04:00
topjohnwu
dd9ddd2019 Remove unnecessary instruction from Defex hexpatch
Close #489
2018-10-20 00:28:09 -04:00
topjohnwu
74aae523ba Properly support boot image header v1
Close #695
2018-10-20 00:27:56 -04:00
topjohnwu
48c40f9516 Prevent Resources
Fix #619
2018-10-17 19:44:48 -04:00
topjohnwu
e0e7674715 Fix close button in FlashActivity 2018-10-17 15:36:09 -04:00
topjohnwu
e1a65276b9 Switch to general Samsung defex patch
Should be future proof unless code changes
2018-10-17 03:17:24 -04:00
muhammeteminturgut
469adc85ad Update Turkish translations 2018-10-16 21:11:43 -04:00
vvb2060
e1b181ca4e Hide system in MagiskHide list 2018-10-16 21:09:18 -04:00
topjohnwu
a4f0fbf8b7 Switch to butterknife
Finally support AndroidX and obfuscation
2018-10-16 21:00:01 -04:00
topjohnwu
190cdaddf8 Update README 2018-10-16 02:06:07 -04:00
topjohnwu
5c4ba13839 Add installation details 2018-10-16 01:55:28 -04:00
topjohnwu
e62630cf3e Add MagiskHide tutorials 2018-10-15 18:04:51 -04:00
topjohnwu
36fe7846c0 Update documentations
Still WIP
2018-10-15 04:33:42 -04:00
topjohnwu
8d150dd67a Update documentation
Still WIP
2018-10-15 00:46:37 -04:00
topjohnwu
506df00d81 Upgrade AGP 2018-10-12 21:51:58 -04:00
topjohnwu
a9121fa28f Reorganize libutils and cleanups 2018-10-12 21:46:09 -04:00
topjohnwu
d5a56d9e85 Fix bootloop for some devices with two /data
Close #654
2018-10-12 00:54:55 -04:00
topjohnwu
acf7c0c665 Minor reorganization of daemons 2018-10-12 00:50:47 -04:00
topjohnwu
619d48c97a Remove doc changelogs 2018-10-05 17:55:06 -04:00
topjohnwu
2cb198c38c Update README 2018-10-05 17:52:40 -04:00
topjohnwu
e8e39e0f3c Use poll instead of select
Close #637
2018-10-04 15:06:13 -04:00
topjohnwu
37860181d4 Finish su implementation 2018-10-04 14:41:48 -04:00
topjohnwu
d119dd9a0c Rewrite su daemon and client 2018-10-04 04:59:51 -04:00
topjohnwu
09ef19f7ec Code cleanups 2018-10-04 01:49:52 -04:00
topjohnwu
6a06c92fa6 Simplify su_info caches
No more lists. 99.999% it will only handle a single excessive requestor anyways.
2018-10-03 23:31:15 -04:00
topjohnwu
58ae596b0f Require fp auth when toggling su permission if required
Close #656
2018-09-29 02:21:14 -04:00
topjohnwu
f1ca21678d Set boolean when toggling 2018-09-29 02:02:41 -04:00
topjohnwu
d7eeef2c8a Separate fingerprint authentication dialog code 2018-09-29 01:57:51 -04:00
topjohnwu
4f626897f2 Cleanup 2018-09-29 00:28:12 -04:00
topjohnwu
b127e01845 Simplify debug flag propagation 2018-09-28 02:05:55 -04:00
topjohnwu
2118beeb23 Magisk-Modules-Repo now names repo with ID, simplify logic here 2018-09-28 01:58:28 -04:00
topjohnwu
5020cd1bbf Small cleanup 2018-09-28 01:25:43 -04:00
topjohnwu
cce636224c Reorganization 2018-09-27 18:26:41 -04:00
topjohnwu
60b3b8ddce Better incremental builds 2018-09-27 03:56:56 -04:00
topjohnwu
41446ec9ba Separate libutils and libsystemproperties 2018-09-27 03:30:16 -04:00
topjohnwu
df8b047bca Generalize logging interface 2018-09-27 03:11:10 -04:00
topjohnwu
12ced52012 Remove unused flag 2018-09-27 00:30:10 -04:00
topjohnwu
1d53335ae5 Dynamic load libselinux 2018-09-27 00:09:59 -04:00
topjohnwu
971a50d290 Update to Android Studio 3.2 2018-09-25 00:39:49 -04:00
topjohnwu
36dd9106a8 Stable AndroidX 2018-09-21 21:46:09 -04:00
John Wu
0a4ee3ffc7 Update README.MD 2018-09-21 12:01:59 -04:00
topjohnwu
cfe32f1a70 Update Magisk Manager changelogs 2018-09-20 22:34:09 -04:00
Taras
d877f5d5c6 update Ukrainian strings 2018-09-20 16:56:17 -04:00
yuchenlin
0ab6ffefb4 utils/misc.c: prevent file staying opened when function leaving
The utils function may be called in any situation, such as in daemon. We
should guarantee that all the resource got from this function released
normally.

Signed-off-by: yuchenlin <npes87184@gmail.com>
2018-09-20 16:55:48 -04:00
topjohnwu
a292a1d23a Cleanup and add new rules
Close #607
2018-09-20 16:55:16 -04:00
topjohnwu
3f87f6aee3 Fix output in Magisk Manager if no root exists 2018-09-20 16:21:22 -04:00
topjohnwu
04bcd145d3 Add a.a alias to BootSigner 2018-09-20 15:37:59 -04:00
topjohnwu
244e811291 Remove icon padding in preference screen
Courtesy of https://stackoverflow.com/a/51568782
2018-09-19 00:06:14 -04:00
topjohnwu
ac7467fb59 Optimize boot signing to use as little memory as possible 2018-09-18 23:48:21 -04:00
topjohnwu
2c0436216f Prevent null strings in modules/repos
Close #620, close #621
2018-09-18 10:04:12 -04:00
topjohnwu
017fbf267b Fix small theme config issue 2018-09-17 23:29:38 -04:00
topjohnwu
e6afbf2ec0 Force remove busybox from APK 2018-09-17 23:03:37 -04:00
topjohnwu
906b4aad9e New method of communication
Introduce a new communication method between Magisk and Magisk Manager.

Magisk used to hardcode classnames and send broadcast/start activities to
specific components. This new method makes no assumption of any class names,
so Magisk Manager can easily be fully obfuscated.

In addition, the new method connects Magisk and Magisk Manager with random
abstract Linux sockets instead of socket files in filesystems, bypassing
file system complexities (selinux, permissions and such)
2018-09-16 04:16:18 -04:00
topjohnwu
4cf8d41f6a Fix FlashActivity crash 2018-09-16 00:18:34 -04:00
topjohnwu
47c860142e Use ClassMaps to prevent errors 2018-09-16 00:08:13 -04:00
topjohnwu
2fba3f213b Use proper socket address length 2018-09-15 02:49:19 -04:00
topjohnwu
af7c6f9fce Fix FlashActivity crash 2018-09-15 01:45:10 -04:00
topjohnwu
78534deab6 Excessive obfuscation when building in release mode
Close #606
2018-09-14 23:00:39 -04:00
topjohnwu
6710314832 Allow all context to SIGCLD magisk
Fix #596
2018-09-11 11:04:51 -04:00
topjohnwu
0cd4fa6fa0 Simplify SignAPK code 2018-09-11 10:48:36 -04:00
topjohnwu
065949496e Migrate to AndroidX support library 2018-09-10 02:27:45 -04:00
topjohnwu
39c82576ae Prevent warning
Close #524
2018-09-09 12:36:42 -04:00
John Wu
37221a508d Update README.MD 2018-09-09 12:25:22 -04:00
John Wu
6b43a32a10 Delete repo_description.png 2018-09-09 10:41:02 -04:00
ImgBotApp
d7cd1ff142 [ImgBot] optimizes images
*Total -- 990.86kb -> 771.48kb (22.14%)

/docs/images/flashfire.png -- 223.55kb -> 153.39kb (31.39%)
/docs/images/repo_description.png -- 38.55kb -> 27.31kb (29.15%)
/docs/images/manager_reboot.png -- 147.43kb -> 111.50kb (24.37%)
/docs/images/install_inactive_slot.png -- 123.15kb -> 99.79kb (18.97%)
/docs/images/restore_img.png -- 134.17kb -> 109.22kb (18.59%)
/docs/images/disable_auto_ota.png -- 160.04kb -> 132.05kb (17.49%)
/docs/images/ota_done.png -- 163.97kb -> 138.22kb (15.71%)
2018-09-09 10:40:40 -04:00
Sandro Jäckel
659d947863 Updated German translations 2018-09-09 10:40:33 -04:00
Rom
39be7a6288 Update stub French translation 2018-09-09 00:38:47 -04:00
Rom
8ac976c579 Update French translation (#576) 2018-09-09 00:38:33 -04:00
Vladimír Kubala
70fd432c57 Update Slovak translation 2018-09-09 00:38:25 -04:00
Jonas Schubert
00135f2f49 updated full\res\values.de\strings.xml 2018-09-09 00:38:11 -04:00
Albert I
9b944bc29c Update Indonesian translations
Signed-off-by: Albert I <krascgq@outlook.co.id>
2018-09-09 00:38:02 -04:00
topjohnwu
d520b3d2a0 Request storage permission when patching boot images 2018-09-08 23:27:19 -04:00
topjohnwu
6f41d9855b Randomize service names
Fix Aniplex Game detections.
Close #502, close #513
2018-09-08 23:17:00 -04:00
topjohnwu
2d7c1da741 Better support for external config file 2018-09-06 14:25:35 -04:00
topjohnwu
c0f45b6b1e Add resetprop magic 2018-09-06 02:57:02 -04:00
topjohnwu
7a0025673c Use libsystemproperties in resetprop
Upstream to latest Android Pie
2018-09-06 02:57:02 -04:00
topjohnwu
ad7ec79903 Support custom config paths 2018-09-05 14:24:28 -04:00
topjohnwu
0543239cca Do not merge binaries if fake symlink 2018-09-01 11:15:05 -04:00
topjohnwu
ff3dad2457 Prevent upgrading database before upgrading to v17.0 2018-09-01 10:46:13 -04:00
topjohnwu
298d5e197b Update Magisk Manager changelog 2018-09-01 02:37:56 -04:00
Eray Rafet
d73c0a998d Update Bulgarian 2018-09-01 02:15:53 -04:00
topjohnwu
1b79a3ddbf Update OTA tutorial for v17 2018-08-31 21:40:02 -04:00
topjohnwu
a8478ace18 Use macros 2018-08-31 03:51:30 -04:00
topjohnwu
72cf5f3f9f Temporary disable module bootloop prevention
Some devices don't like it, need further tests before pushing to production
2018-08-31 03:23:59 -04:00
vvb2060
6f9d493a18 Update zh-rCN translation 2018-08-31 02:20:52 -04:00
dark-basic
08f7d5ebff Update strings.xml
New Line Added.
2018-08-31 02:20:43 -04:00
Ilya Kushnir
1fe3675403 Update RU strings 2018-08-31 02:20:36 -04:00
Oliver Cervera
a0f956d2c1 Update Italian translation - Twitter string
Added new Twitter string.
2018-08-31 02:20:25 -04:00
topjohnwu
1560f91b4a Move layout from main to full 2018-08-30 05:15:44 -04:00
topjohnwu
c20f362594 Update trad. Chinese translation 2018-08-30 05:09:28 -04:00
topjohnwu
7ae8c26e50 Improve About and Donation page 2018-08-30 05:05:29 -04:00
topjohnwu
adfffe6121 Better back pressing logic 2018-08-30 04:19:08 -04:00
topjohnwu
64601baa76 Update Magisk Manager README 2018-08-30 04:03:14 -04:00
topjohnwu
aa374b51f1 Move fragments to separate package 2018-08-30 03:57:48 -04:00
topjohnwu
5c483745ff Move settings out of separate Activity 2018-08-30 00:52:02 -04:00
topjohnwu
0c247110a0 Also get default flags in non-root environment 2018-08-29 13:31:26 -04:00
Vladimír Kubala
1643638a78 Slovak language
Added Slovak language
2018-08-29 00:41:53 -04:00
Nicholas
4ace228fc2 Update SnackbarMaker.java
Zip downloads don't go into /MagiskManager anymore, they go into /Download instead. Snackbar should be updated accordingly.
2018-08-29 00:41:43 -04:00
Taras
25aa86a0dc update Ukrainian translation 2018-08-29 00:41:18 -04:00
topjohnwu
70d3b24338 Keep dm/avb-verity when device is using system_root_image
Close #512
2018-08-29 00:40:14 -04:00
topjohnwu
8664e9d19b Update scripts 2018-08-28 22:03:12 -04:00
topjohnwu
50d9877446 Sign debug builds with custom keystore if applicable 2018-08-28 12:17:27 -04:00
topjohnwu
fe06352089 Remove unused import 2018-08-27 00:10:43 -04:00
Rom
7b599419b5 Update French translation 2018-08-26 22:50:26 -04:00
Ilya Kushnir
491adf072e Update RU strings 2018-08-26 22:50:18 -04:00
topjohnwu
f6aae2b048 Add hexpatch to remove Samsung defex in kernel
Close #499
2018-08-26 22:38:13 -04:00
Eray Rafet
d2d5c94633 Update Bulgarian 2018-08-25 23:03:06 -04:00
Oliver Cervera
10581f9ef2 Add new fingerprint string
Added new fingerprint string
2018-08-25 23:02:59 -04:00
JoanVC100
c7e0e1c038 Fix ca-strings
Added new line and corrected lines.
2018-08-25 23:02:48 -04:00
vvb2060
a914d701eb Update zh-rCN translation 2018-08-25 23:02:31 -04:00
dark-basic
0f9dee6e9c Update Strings.xml
-New Line added.
------------------------------------------------------------------------------------
Require authentication to toggle fingerprint settings -  Requerir autenticación para alternar configuraciones de huellas dactilares
2018-08-25 23:02:23 -04:00
topjohnwu
aa383e2190 Properly get color from attribute 2018-08-25 23:01:14 -04:00
topjohnwu
9bbfcf326c Do not place files into /sdcard/MagiskManager 2018-08-25 16:00:27 -04:00
topjohnwu
3948e67c8f Require authentication to toggle fingerprint settings
Close #474
2018-08-22 17:49:51 -04:00
topjohnwu
d56e1b2cc5 Move fingerprint settings to global database 2018-08-22 15:05:00 -04:00
topjohnwu
bfac1f1bc2 SN checks is possible after repackage if using new API 2018-08-22 12:32:53 +08:00
topjohnwu
d4a956c355 Fix strings 2018-08-22 12:28:15 +08:00
dark-basic
6c71fefa58 Old Translators removed.
Fisrt of all, I thank you  Gawenda, netizen, Deiki, and Nosi : D
They were the first people to translate Magisk Manager in Spanish.
He had left ther names for their contributions, but I think it´s time to do a cleanup.
-----------------------------------------------------------------------------------
Topjohnwu. Left under your consent to merge or not this modifications.
-----------------------------------------------------------------------------------
My English is a bit of a translator and mine 👍
2018-08-22 00:25:06 -04:00
JoanVC100
ad3003c00a Catalan language for Magisk 2018-08-22 00:24:23 -04:00
Albert I
0ad5dcb258 Update Indonesian translation
Signed-off-by: Albert I <krascgq@outlook.co.id>
2018-08-22 00:23:34 -04:00
Rom
d790309b02 Update French translation
Ready to be merged.

Have a good day!
2018-08-22 00:23:27 -04:00
Oliver Cervera
1072faf309 Update Italian strings
Added latest strings
2018-08-22 00:23:18 -04:00
topjohnwu
d2c196896d Update snet extension 2018-08-22 11:50:21 +08:00
vvb2060
e42b608444 Hide SafetyNet check if no GMS 2018-08-21 23:40:06 -04:00
topjohnwu
89a501a3af Fix build scripts 2018-08-21 00:31:41 +08:00
topjohnwu
c19b78180c Read props directly in Gradle 2018-08-20 12:02:38 +08:00
Taras
c0b750a09a added new lines, translations corrections 2018-08-14 00:21:04 +08:00
topjohnwu
c967e618a1 Adjustment to direct install 2018-08-13 02:57:03 +08:00
topjohnwu
59f78d7dfc Update to BusyBox 1.29.2 2018-08-13 01:30:15 +08:00
topjohnwu
d8405f0d05 Make recovery installed on on system_root devices normal 2018-08-12 00:16:59 +08:00
topjohnwu
0f34f0033c Switch to FrankeNDK for building native 2018-08-11 18:46:55 +08:00
topjohnwu
190646d50c Fix incorrect magisk metadata in ramdisk 2018-08-11 16:31:46 +08:00
topjohnwu
a46c6252c6 Detect insufficient partition size
Close #388
2018-08-11 15:56:12 +08:00
topjohnwu
5c1886c8f5 Update scripts 2018-08-10 18:59:14 +08:00
topjohnwu
afcb3d8f34 Fix XZ decompression in magiskinit 2018-08-10 15:04:32 +08:00
topjohnwu
9fbffafdbf Improve build script 2018-08-10 05:57:12 +08:00
topjohnwu
075f0458f7 Split stub APK to new task 2018-08-10 05:57:12 +08:00
topjohnwu
d4568aa0a7 Compress binaries and use xz-embedded in magiskinit 2018-08-10 05:57:12 +08:00
topjohnwu
97588408a2 Reorganize build script 2018-08-10 05:57:11 +08:00
topjohnwu
1def9b301b Use xz-embedded for b64xz 2018-08-10 05:57:11 +08:00
topjohnwu
5bac442b18 Reorganize sources 2018-08-10 03:49:25 +08:00
topjohnwu
6add682705 Remove high compression mode 2018-08-10 03:49:25 +08:00
topjohnwu
8b50d84a05 Hide unnecessary error log 2018-08-09 15:10:00 +08:00
topjohnwu
d3858b81e2 Add new boot service: boot-complete 2018-08-09 14:52:44 +08:00
topjohnwu
bdff9769be Move remount,ro back to post-fs-data mode 2018-08-09 03:57:29 +08:00
Ilya Kushnir
c61df75e5e Update RU strings 2018-08-09 03:25:32 +08:00
vvb2060
a74bf2cc27 Update zh-rCN translation 2018-08-09 03:25:15 +08:00
topjohnwu
ada0f93686 Apply all sepolicy patches pre-init
Boot services tend to fail in the middle when the kernel loads a sepolicy live.
It seems that moving full patch (allow magisk * * *) to late_start is still not enough to fix service startup failures.
So screw it, apply all patched in magiskinit, which makes sure that all rules are only loaded in a single step.
The only down side is that some OEM with a HUGE set of secontexts (e.g. Samsung) might suffer a slightly longer boot time, which IS the reason why the rules are split to 2 parts in the first place.
2018-08-09 03:20:28 +08:00
topjohnwu
ff36f2ba17 Add 1 more byte to mark
Prevent crashes on higher Android versions
2018-08-09 03:01:33 +08:00
topjohnwu
5164cfd399 Move butterknife config to full only 2018-08-08 23:09:29 +08:00
topjohnwu
5fa021503e Update to libsu 2.0.1 2018-08-08 18:57:55 +08:00
topjohnwu
7b5d79d313 Kill all processes using the same UID of the target
To workaround OOS embryo optimization
2018-08-08 05:47:58 +08:00
topjohnwu
3e3f38500d Only use required memory size 2018-08-08 03:20:37 +08:00
topjohnwu
5109b9abfd Allow modules be managed in core only mode, and add notice in UI 2018-08-07 16:31:00 +08:00
topjohnwu
7fb4777c1c Improve update channel settings
Fix #446
2018-08-07 15:48:43 +08:00
topjohnwu
c38533e0f8 Prevent problematic modules causing device stuck in bootloop
If boot failed after 2 times, it will enable core only mode (which disables all modules)
2018-08-07 04:41:48 +08:00
dark-basic #DarkBasic BasicHD
51ba99d09e Update Strings Spanish
New Line Added.
2018-08-07 02:24:12 +08:00
topjohnwu
9159f86a9e Improvements to system_root devices booting as recovery 2018-08-07 02:20:40 +08:00
topjohnwu
e139f4fc13 Small build script adjustments 2018-08-06 19:32:37 +08:00
tonymanou
2fbfeacb87 Show toast when intent to open a link is not resolved 2018-08-06 18:56:20 +08:00
tonymanou
ebb7a9fcda Open links in a new task 2018-08-06 18:56:20 +08:00
tonymanou
9e72317302 Ensure intent are resolved when opening link 2018-08-06 18:56:20 +08:00
topjohnwu
d764c20c08 Fix crash on boot on Android pre-O
Close #448
2018-08-06 18:52:28 +08:00
topjohnwu
9c17b8a098 Better subprocess support
Close #444
2018-08-06 02:01:04 +08:00
Ilya Kushnir
3084873154 Fix missing RU translate 2018-08-05 23:34:05 +08:00
topjohnwu
32809e56d0 Sign release zips with release-key.jks
Close #408
2018-08-05 02:29:40 +08:00
topjohnwu
9f05b182a2 Verify existing file checksum to prevent needless downloads 2018-08-05 00:37:02 +08:00
vvb2060
525484e834 Update zh-rCN translation 2018-08-03 23:12:16 +08:00
Rom
65a4e69cae Updating French translation
According to commit `20e0fe3`
2018-08-03 23:12:07 +08:00
Ilya Kushnir
e973f8bab9 Update RU strings pt.2 2018-08-03 23:11:54 +08:00
Albert I
92466671ff Update Indonesian translations
Signed-off-by: Albert I <krascgq@outlook.co.id>
2018-08-03 23:09:40 +08:00
Eray Rafet
6d61106070 Update Bulgarian 2018-08-03 23:09:31 +08:00
Ilya Kushnir
ac13749fb8 Update UK strings 2018-08-03 23:09:21 +08:00
Ilya Kushnir
7ec1a9a316 Update RU strings 2018-08-03 23:09:21 +08:00
topjohnwu
cf17e21ad3 Proper callback to trigger UI update 2018-08-03 23:04:35 +08:00
topjohnwu
0e0240c4ab Better download UI 2018-08-03 22:48:44 +08:00
topjohnwu
d1b290b91a Fix install failure 2018-08-03 22:41:53 +08:00
topjohnwu
a63696836c Proper addon.d-v2 support 2018-08-03 22:40:49 +08:00
topjohnwu
46aad00f16 Use buffer on stack 2018-08-03 21:30:44 +08:00
topjohnwu
252afe8932 Use mirror in post-fs-data scripts 2018-08-03 17:09:24 +08:00
topjohnwu
9dd467a613 Update Trad. Chinese translations 2018-08-03 05:29:17 +08:00
topjohnwu
4c14df67cc Add warning before installing to inactive slot 2018-08-03 05:19:46 +08:00
Eray Rafet
20e0fe3ba1 Update Bulgarian 2018-08-03 04:56:29 +08:00
vvb2060
6a005135f2 Update zh-rCN translation 2018-08-03 04:56:21 +08:00
topjohnwu
82e8375957 Respect filesystem type when mounting mirrors
Close #405
2018-08-03 04:45:07 +08:00
topjohnwu
bb25edc09e Use own busybox for get_outfd 2018-08-03 04:25:00 +08:00
topjohnwu
169c0fe4af Stop use clashing names 2018-08-03 03:43:02 +08:00
topjohnwu
cd6918e6eb Stop altering PATH to mirror 2018-08-03 03:38:36 +08:00
topjohnwu
5be035fd44 Try logging a little harder 2018-08-03 01:58:56 +08:00
topjohnwu
f1edc8443c Make root shell always use dev_pts
Close #433
2018-08-02 20:29:18 +08:00
topjohnwu
d9564bd04c Delay full sepolicy patch loading time 2018-08-02 05:35:01 +08:00
topjohnwu
35f1c396f2 Request write external storage permission 2018-08-02 04:27:01 +08:00
topjohnwu
6acb950990 Simplify repo update logic 2018-08-02 01:55:34 +08:00
topjohnwu
27e0d1641a Show proper time of repo updates 2018-08-02 01:55:34 +08:00
topjohnwu
9ac71ff8af Simplify asynchronous tasks 2018-08-02 00:41:10 +08:00
topjohnwu
075737a4ec Fix crash 2018-08-01 18:56:11 +08:00
topjohnwu
6d0e4a6a5e Rename base activity and fragments 2018-08-01 17:57:11 +08:00
topjohnwu
a2544768a0 Remove boilderplate 2018-08-01 14:30:59 +08:00
topjohnwu
8574a14ed2 Improve locale settings 2018-08-01 14:16:44 +08:00
topjohnwu
e90c555c18 Some cleanups 2018-08-01 03:09:44 +08:00
topjohnwu
863b9a410f Rewrite Topics 2018-08-01 00:47:31 +08:00
topjohnwu
23c7bbc7d5 Move Const to upper package 2018-07-31 17:42:35 +08:00
topjohnwu
f900189f90 Rename and move methods 2018-07-31 17:41:54 +08:00
topjohnwu
7c74be2790 Create LocaleManager 2018-07-31 17:35:58 +08:00
topjohnwu
70dd2d4829 More moving 2018-07-31 16:57:52 +08:00
topjohnwu
914b7ee056 Start moving things outside of top Application class 2018-07-31 03:51:11 +08:00
topjohnwu
e39f83edbf Do not unmount database when cleaning up repackaged manager 2018-07-31 01:09:25 +08:00
topjohnwu
52fe0c6abb Fix restore manager on Android P 2018-07-31 01:05:56 +08:00
darken
5cb3e5937f Update policy list when resuming the superuser fragment.
Closes #414
2018-07-30 21:52:36 +08:00
dark-basic #DarkBasic BasicHD
e0cd224831 Update Strings.xml Spanish
New Line added.
2018-07-30 21:51:07 +08:00
Madis
de225ac64a Estonian update
Made all latest strings.xml files evenly translated with English ones
2018-07-30 21:51:07 +08:00
Oliver Cervera
5807808a10 Update Italian Translation
Added and translated new strings after commit b8eaff6
2018-07-30 21:51:07 +08:00
switchtegrax1
362877d18f Update strings.xml
Just Updated the brazilian translation for the Inactive Slot Option
2018-07-30 21:51:07 +08:00
Rom
88b8dd0149 Update French translation 2018-07-30 21:51:07 +08:00
topjohnwu
1552f32e09 Keep the methods in SN check interface
For some reason, Proguard optimization will remove the method
2018-07-30 20:42:42 +08:00
topjohnwu
50b73a6720 Clear up more component in stub APK 2018-07-30 20:37:00 +08:00
topjohnwu
53e51f1735 Allow incomplete update JSONs 2018-07-29 23:36:29 +08:00
topjohnwu
40b63bfebe Don't use DownloadManager for Magisk 2018-07-29 22:58:22 +08:00
topjohnwu
89861eceef Install to Second Slot -> Install to Inactive slot 2018-07-29 15:45:04 +08:00
topjohnwu
b8eaff66fa Shrink snet APK, and prevent crashing 2018-07-28 23:40:41 +08:00
topjohnwu
a747fdd27d Organize dialog code 2018-07-28 22:52:40 +08:00
topjohnwu
27851bdefa Update README.md 2018-07-28 15:10:06 +08:00
topjohnwu
3fdeb40ddf Update SNET extension dialog interface 2018-07-28 14:56:14 +08:00
topjohnwu
546c7cebd3 Fix #411 2018-07-27 22:44:09 +08:00
topjohnwu
473902f5f4 Proper detect MagiskHide status 2018-07-27 22:32:47 +08:00
topjohnwu
41c0721159 Use internal thread pool for update repos 2018-07-27 21:59:30 +08:00
topjohnwu
413d4badfd Strip logging code with Proguard 2018-07-27 21:52:09 +08:00
topjohnwu
c5d67ebf72 Update libsu to 2.0.0 2018-07-27 04:48:32 +08:00
topjohnwu
91818cfa1a Support compiling split cils via magiskpolicy CLI 2018-07-21 05:12:22 +08:00
topjohnwu
6263d684d9 Migrate to JobIntentService to prevent boot notification 2018-07-21 02:59:36 +08:00
topjohnwu
07140d33a7 Bring back installing to second slot after OTA on A/B devices 2018-07-21 01:59:28 +08:00
topjohnwu
4ffc388491 Allow bootctl to run 2018-07-20 22:22:49 +08:00
topjohnwu
0ef026c610 Remove system root when running addon.d 2018-07-20 00:37:38 +08:00
716 changed files with 41418 additions and 29252 deletions

1
.gitattributes vendored
View File

@@ -16,3 +16,4 @@ chromeos/** binary
*.exe binary
*.apk binary
*.png binary
*.jpg binary

5
.gitignore vendored
View File

@@ -3,9 +3,7 @@ out
*.jks
*.apk
config.prop
# Manually dumped jars
snet/libs
update.sh
# Built binaries
native/out
@@ -17,4 +15,3 @@ native/out
/.idea
/build
/captures
.externalNativeBuild

127
README.MD
View File

@@ -1,74 +1,75 @@
# 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)
## 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).
## 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.
## Building Environment Requirements
1. Python 3.5+: 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. Building is tested on macOS, Ubuntu, and Windows 10 using the latest stable NDK and NDK r10e. Officially released binaries were built with NDK r10e.
2. Set configurations in `config.prop`. A sample file `config.prop.sample` is provided as an example.
3. 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`
4. By default, `build.py` build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (via the `--release` flag), you need a Java Keystore file `release-key.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
5. The SafetyNet extension pack requires the full Magisk Manager as a `compileOnly` dependency. Build the **release** APK, convert it back to Java `.class` files (I use [dex2jar](https://github.com/pxb1988/dex2jar)), and place the converted JAR under `snet/libs` before compiling.
- 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 are scattered throughout
- `app/src/main/res/values/strings.xml`
- `stub/src/main/res/values/strings.xml`
- `shared/src/main/res/values/strings.xml`
Translate each and place them in the respective locations (`<module>/src/main/res/values-<lang>/strings.xml`).
## Signature Verification
Official release zips and APKs are signed with my personal private key. You can verify the key certificate to make sure the binaries you downloaded are not manipulated in anyway.
``` bash
# Use the keytool command from JDK to print certificates
keytool -printcert -jarfile <APK or Magisk zip>
# The output should contain the following signature
Owner: CN=John Wu, L=Taipei, C=TW
Issuer: CN=John Wu, L=Taipei, C=TW
Serial number: 50514879
Valid from: Sun Aug 14 13:23:44 EDT 2016 until: Tue Jul 21 13:23:44 EDT 2116
Certificate fingerprints:
MD5: CE:DA:68:C1:E1:74:71:0A:EF:58:89:7D:AE:6E:AB:4F
SHA1: DC:0F:2B:61:CB:D7:E9:D3:DB:BE:06:0B:2B:87:0D:46:BB:06:02:11
SHA256: B4:CB:83:B4:DA:D9:9F:99:7D:BE:87:2F:01:3A:A1:6C:14:EE:C4:1D:16:70:21:F3:71:F7:E1:33:0F:27:3E:E6
Signature algorithm name: SHA256withRSA
Version: 3
```
## 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/>.
```
## Credits
**MagiskManager** (`app`)
* Copyright 2016-2018, John Wu (@topjohnwu)
* All contributors and translators on Github
**MagiskSU** (`native/jni/su`)
* Copyright 2016-2018, John Wu (@topjohnwu)
* Copyright 2015, Pierre-Hugues Husson (phh@phh.me)
* Copyright 2013, Koushik Dutta (@koush)
* Copyright 2010, Adam Shanks (@ChainsDD)
* Copyright 2008, Zinx Verituse (@zinxv)
**MagiskPolicy** (`native/jni/magiskpolicy`)
* Copyright 2016-2018, John Wu (@topjohnwu)
* Copyright 2015, Pierre-Hugues Husson (phh@phh.me)
* Copyright 2015, Joshua Brindle (@joshua_brindle)
**MagiskHide** (`native/jni/magiskhide`)
* Copyright 2016-2018, John Wu (@topjohnwu)
* Copyright 2016, Pierre-Hugues Husson (phh@phh.me)
**resetprop** (`native/jni/resetprop`)
* Copyright 2016-2018 John Wu (@topjohnwu)
* Copyright 2016 nkk71 (nkk71x@gmail.com)
**External Dependencies** (`native/jni/external`)
* Makefile for busybox, generated by [ndk-busybox-kitchen](https://github.com/topjohnwu/ndk-busybox-kitchen)
* Each dependencies has its own license/copyright information in each subdirectory.
All of them are either GPL or GPL compatible.
**Others Not Mentioned**
* Copyright 2016-2018, John Wu (@topjohnwu)
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

1
app/.gitignore vendored
View File

@@ -6,7 +6,6 @@
app/release
*.hprof
.externalNativeBuild/
src/full/res/raw/util_functions.sh
public.certificate.x509.pem
private.key.pk8
*.apk

View File

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

View File

@@ -1,13 +1,24 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
kapt {
correctErrorTypes = true
useBuildCache = true
mapDiagnosticLocations = true
javacOptions {
option("-Xmaxerrs", 1000)
}
}
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.topjohnwu.magisk"
minSdkVersion 21
targetSdkVersion rootProject.ext.compileSdkVersion
applicationId 'com.topjohnwu.magisk'
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
versionName configProps['appVersion']
versionCode configProps['appVersionCode'] as Integer
javaCompileOptions {
annotationProcessorOptions {
argument('butterknife.debuggable', 'false')
@@ -17,49 +28,56 @@ android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
flavorDimensions "mode"
productFlavors {
full {
versionCode 129
versionName "5.8.3"
}
stub {
versionCode 1
versionName "stub"
}
dataBinding {
enabled = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
dexOptions {
preDexLibraries true
javaMaxHeapSize "2g"
}
lintOptions {
disable 'MissingTranslation'
packagingOptions {
exclude '/META-INF/*.version'
exclude '/META-INF/*.kotlin_module'
exclude '/META-INF/rxkotlin.properties'
exclude '/androidsupportmultidexversion.txt'
exclude '/org/**'
exclude '/kotlin/**'
exclude '/kotlinx/**'
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
fullImplementation project(':utils')
implementation "com.android.support:support-core-utils:${rootProject.ext.supportLibVersion}"
fullImplementation "com.android.support:preference-v7:${rootProject.ext.supportLibVersion}"
fullImplementation "com.android.support:recyclerview-v7:${rootProject.ext.supportLibVersion}"
fullImplementation "com.android.support:cardview-v7:${rootProject.ext.supportLibVersion}"
fullImplementation "com.android.support:design:${rootProject.ext.supportLibVersion}"
fullImplementation 'com.github.topjohnwu:libsu:1.3.0'
fullImplementation 'com.atlassian.commonmark:commonmark:0.11.0'
fullImplementation 'org.kamranzafar:jtar:2.3'
fullImplementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation project(':net')
implementation project(':shared')
implementation project(':signing')
implementation 'com.github.topjohnwu:jtar:1.0.0'
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'com.github.skoumalcz:teanity:0.3.3'
implementation 'com.ncapdevi:frag-nav:3.2.0'
def markwonVersion = '3.0.1'
implementation "ru.noties.markwon:core:${markwonVersion}"
implementation "ru.noties.markwon:html:${markwonVersion}"
implementation "ru.noties.markwon:image-svg:${markwonVersion}"
def libsuVersion = '2.5.0'
implementation "com.github.topjohnwu.libsu:core:${libsuVersion}"
implementation "com.github.topjohnwu.libsu:io:${libsuVersion}"
def koin = "2.0.0-rc-2"
implementation "org.koin:koin-core:${koin}"
implementation "org.koin:koin-android:${koin}"
implementation "org.koin:koin-androidx-viewmodel:${koin}"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.preference:preference:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha05'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.android.material:material:1.1.0-alpha06'
implementation 'androidx.work:work-runtime:2.0.1'
implementation 'androidx.transition:transition:1.2.0-alpha01'
implementation 'androidx.multidex:multidex:2.0.1'
}

View File

@@ -16,14 +16,34 @@
# public *;
#}
# Keep all names, we are open source anyway :)
-keepnames class ** { *; }
# 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 {
void onResponse(int);
}
# BouncyCastle
-keep class org.bouncycastle.jcajce.provider.asymmetric.rsa.**SHA1** { *; }
-keep class org.bouncycastle.jcajce.provider.asymmetric.RSA** { *; }
-keep class org.bouncycastle.jcajce.provider.digest.SHA1** { *; }
-dontwarn javax.naming.**
# Keep all fragment constructors
-keepclassmembers class * extends androidx.fragment.app.Fragment {
public <init>(...);
}
# Gson
-keepattributes Signature
# DelegateWorker
-keep,allowobfuscation class * extends com.topjohnwu.magisk.model.worker.DelegateWorker
# BootSigner
-keepclassmembers class com.topjohnwu.signing.BootSigner { *; }
# Strip logging
-assumenosideeffects class com.topjohnwu.magisk.utils.Logger {
public *** debug(...);
}
# Excessive obfuscation
-repackageclasses 'a'
-allowaccessmodification
# QOL
-dontnote **
-dontwarn com.caverock.androidsvg.**
-dontwarn ru.noties.markwon.**

View File

@@ -1,82 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.topjohnwu.magisk">
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<application
android:name=".MagiskManager"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:exported="true" />
<activity
android:name=".SplashActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".AboutActivity"
android:theme="@style/AppTheme.StatusBar" />
<activity
android:name=".SettingsActivity"
android:theme="@style/AppTheme.StatusBar" />
<activity
android:name=".FlashActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="nosensor"
android:theme="@style/AppTheme.StatusBar" />
<activity
android:name=".NoUIActivity"
android:theme="@style/AppTheme.Translucent" />
<activity
android:name=".superuser.RequestActivity"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:taskAffinity="internal.superuser"
android:theme="@style/SuRequest" />
<receiver android:name=".superuser.SuReceiver" />
<receiver android:name=".receivers.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".receivers.PackageReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver android:name=".receivers.ManagerUpdate" />
<receiver android:name=".receivers.RebootReceiver" />
<receiver android:name=".receivers.ShortcutReceiver">
<intent-filter>
<action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter>
</receiver>
<service android:name=".services.OnBootIntentService" />
<service
android:name=".services.UpdateCheckService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
<!-- Hardcode GMS version -->
<meta-data
android:name="com.google.android.gms.version"
android:value="7095000" />
</application>
</manifest>

View File

@@ -1,80 +0,0 @@
package com.topjohnwu.magisk;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.View;
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
import com.topjohnwu.magisk.components.AboutCardRow;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.Const;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
public class AboutActivity extends Activity {
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.app_version_info) AboutCardRow appVersionInfo;
@BindView(R.id.app_changelog) AboutCardRow appChangelog;
@BindView(R.id.app_translators) AboutCardRow appTranslators;
@BindView(R.id.app_source_code) AboutCardRow appSourceCode;
@BindView(R.id.support_thread) AboutCardRow supportThread;
@BindView(R.id.donation) AboutCardRow donation;
@Override
public int getDarkTheme() {
return R.style.AppTheme_StatusBar_Dark;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setTitle(R.string.about);
ab.setDisplayHomeAsUpEnabled(true);
}
appVersionInfo.setSummary(String.format(Locale.US, "%s (%d) (%s)",
BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, getPackageName()));
appChangelog.removeSummary();
appChangelog.setOnClickListener(v -> {
new MarkDownWindow(this, getString(R.string.app_changelog),
getResources().openRawResource(R.raw.changelog)).exec();
});
String translators = getString(R.string.translators);
if (TextUtils.isEmpty(translators)) {
appTranslators.setVisibility(View.GONE);
} else {
appTranslators.setSummary(translators);
}
appSourceCode.removeSummary();
appSourceCode.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.SOURCE_CODE_URL))));
supportThread.removeSummary();
supportThread.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.XDA_THREAD))));
donation.removeSummary();
donation.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.DONATION_URL))));
setFloating();
}
}

View File

@@ -1,155 +0,0 @@
package com.topjohnwu.magisk;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.topjohnwu.magisk.asyncs.FlashZip;
import com.topjohnwu.magisk.asyncs.InstallMagisk;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.superuser.CallbackList;
import com.topjohnwu.superuser.Shell;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class FlashActivity extends Activity {
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.txtLog) TextView flashLogs;
@BindView(R.id.button_panel) public LinearLayout buttonPanel;
@BindView(R.id.reboot) public Button reboot;
@BindView(R.id.scrollView) ScrollView sv;
private List<String> logs;
@OnClick(R.id.no_thanks)
void dismiss() {
finish();
}
@OnClick(R.id.reboot)
void reboot() {
Shell.Async.su("/system/bin/reboot");
}
@OnClick(R.id.save_logs)
void saveLogs() {
Calendar now = Calendar.getInstance();
String filename = String.format(Locale.US,
"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 + "/logs", filename);
logFile.getParentFile().mkdirs();
try (FileWriter writer = new FileWriter(logFile)) {
for (String s : logs) {
writer.write(s);
writer.write('\n');
}
} catch (IOException e) {
e.printStackTrace();
return;
}
MagiskManager.toast(logFile.getPath(), Toast.LENGTH_LONG);
}
@Override
public int getDarkTheme() {
return R.style.AppTheme_StatusBar_Dark;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flash);
ButterKnife.bind(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 = new ArrayList<>();
CallbackList<String> console = new CallbackList<String>(new ArrayList<>()) {
@Override
public void onAddElement(String s) {
logs.add(s);
flashLogs.setText(TextUtils.join("\n", this));
sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10);
}
};
// We must receive a Uri of the target zip
Intent intent = getIntent();
Uri uri = intent.getData();
switch (intent.getStringExtra(Const.Key.FLASH_ACTION)) {
case Const.Value.FLASH_ZIP:
new FlashZip(this, uri, console, logs).exec();
break;
case Const.Value.UNINSTALL:
new UninstallMagisk(this, uri, console, logs).exec();
break;
case Const.Value.FLASH_MAGISK:
new InstallMagisk(this, console, logs, uri, InstallMagisk.DIRECT_MODE).exec();
break;
case Const.Value.FLASH_SECOND_SLOT:
new InstallMagisk(this, console, logs, uri, InstallMagisk.SECOND_SLOT_MODE).exec();
break;
case Const.Value.PATCH_BOOT:
new InstallMagisk(this, console, logs, uri,
intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT)).exec();
break;
}
}
@Override
public void onBackPressed() {
// Prevent user accidentally press back button
}
private static class UninstallMagisk extends FlashZip {
private UninstallMagisk(Activity context, Uri uri, List<String> console, List<String> logs) {
super(context, uri, console, logs);
}
@Override
protected void onPostExecute(Integer result) {
if (result == 1) {
new Handler().postDelayed(() ->
RootUtils.uninstallPkg(getActivity().getPackageName()), 3000);
} else {
super.onPostExecute(result);
}
}
}
}

View File

@@ -1,55 +0,0 @@
package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.topjohnwu.magisk.adapters.TabFragmentAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.utils.Const;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class LogFragment extends Fragment {
private Unbinder unbinder;
@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 = ButterKnife.bind(this, v);
((MainActivity) getActivity()).toolbar.setElevation(0);
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
if (!(Const.USER_ID > 0 && getApplication().multiuserMode == Const.Value.MULTIUSER_MODE_OWNER_MANAGED)) {
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;
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}

View File

@@ -1,313 +0,0 @@
package com.topjohnwu.magisk;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.CardView;
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.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.topjohnwu.magisk.asyncs.CheckSafetyNet;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
import com.topjohnwu.magisk.utils.ShowUI;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import butterknife.BindColor;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
public class MagiskFragment extends Fragment
implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener, ExpandableView {
private Container expandableContainer = new Container();
private MagiskManager mm;
private Unbinder unbinder;
private static boolean shownDialog = false;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.magisk_update) RelativeLayout magiskUpdate;
@BindView(R.id.magisk_update_icon) ImageView magiskUpdateIcon;
@BindView(R.id.magisk_update_status) TextView magiskUpdateText;
@BindView(R.id.magisk_update_progress) ProgressBar magiskUpdateProgress;
@BindView(R.id.magisk_status_icon) ImageView magiskStatusIcon;
@BindView(R.id.magisk_version) TextView magiskVersionText;
@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.expand_layout) LinearLayout 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;
@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_button) CardView installButton;
@BindView(R.id.install_text) TextView installText;
@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.grey500) int colorNeutral;
@BindColor(R.color.blue500) int colorInfo;
@OnClick(R.id.safetyNet_title)
void safetyNet() {
Runnable task = () -> {
safetyNetProgress.setVisibility(View.VISIBLE);
safetyNetRefreshIcon.setVisibility(View.GONE);
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
new CheckSafetyNet(getActivity()).exec();
collapse();
};
if (!TextUtils.equals(mm.getPackageName(), Const.ORIG_PKG_NAME)) {
new AlertDialogBuilder(getActivity())
.setTitle(R.string.cannot_check_sn_title)
.setMessage(R.string.cannot_check_sn_notice)
.setCancelable(true)
.setPositiveButton(R.string.ok, null)
.show();
} else if (!CheckSafetyNet.dexPath.exists()) {
// Show dialog
new AlertDialogBuilder(getActivity())
.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();
}
}
@OnClick(R.id.install_button)
void install() {
shownDialog = true;
// Show Manager update first
if (mm.remoteManagerVersionCode > BuildConfig.VERSION_CODE) {
ShowUI.managerInstallDialog(getActivity());
return;
}
((NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll();
ShowUI.magiskInstallDialog(getActivity());
}
@OnClick(R.id.uninstall_button)
void uninstall() {
ShowUI.uninstallDialog(getActivity());
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_magisk, container, false);
unbinder = ButterKnife.bind(this, v);
getActivity().setTitle(R.string.magisk);
mm = getApplication();
expandableContainer.expandLayout = expandLayout;
setupExpandable();
keepVerityChkbox.setChecked(mm.keepVerity);
keepVerityChkbox.setOnCheckedChangeListener((view, checked) -> mm.keepVerity = checked);
keepEncChkbox.setChecked(mm.keepEnc);
keepEncChkbox.setOnCheckedChangeListener((view, checked) -> mm.keepEnc = checked);
mSwipeRefreshLayout.setOnRefreshListener(this);
updateUI();
return v;
}
@Override
public void onRefresh() {
mm.loadMagiskInfo();
updateUI();
magiskUpdateText.setText(R.string.checking_for_updates);
magiskUpdateProgress.setVisibility(View.VISIBLE);
magiskUpdateIcon.setVisibility(View.GONE);
safetyNetStatusText.setText(R.string.safetyNet_check_text);
mm.safetyNetDone.reset();
mm.updateCheckDone.reset();
mm.remoteMagiskVersionString = null;
mm.remoteMagiskVersionCode = -1;
collapse();
shownDialog = false;
// Trigger state check
if (Utils.checkNetworkStatus()) {
new CheckUpdates().exec();
} else {
mSwipeRefreshLayout.setRefreshing(false);
}
}
@Override
public void onTopicPublished(Topic topic) {
if (topic == mm.updateCheckDone) {
updateCheckUI();
} else if (topic == mm.safetyNetDone) {
updateSafetyNetUI((int) topic.getResults()[0]);
}
}
@Override
public Topic[] getSubscription() {
return new Topic[] { mm.updateCheckDone, mm.safetyNetDone };
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@Override
public Container getContainer() {
return expandableContainer;
}
private void updateUI() {
((MainActivity) getActivity()).checkHideSection();
boolean hasNetwork = Utils.checkNetworkStatus();
boolean hasRoot = Shell.rootAccess();
boolean isUpToDate = mm.magiskVersionCode > Const.MAGISK_VER.UNIFIED;
magiskUpdate.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
safetyNetCard.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
installOptionCard.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
uninstallButton.setVisibility(isUpToDate && hasRoot ? View.VISIBLE : View.GONE);
int image, color;
if (mm.magiskVersionCode < 0) {
color = colorBad;
image = R.drawable.ic_cancel;
magiskVersionText.setText(R.string.magisk_version_error);
} else {
color = colorOK;
image = R.drawable.ic_check_circle;
magiskVersionText.setText(getString(R.string.current_magisk_title, "v" + mm.magiskVersionString));
}
magiskStatusIcon.setImageResource(image);
magiskStatusIcon.setColorFilter(color);
}
private void updateCheckUI() {
int image, color;
if (mm.remoteMagiskVersionCode < 0) {
color = colorNeutral;
image = R.drawable.ic_help;
magiskUpdateText.setText(R.string.invalid_update_channel);
installButton.setVisibility(View.GONE);
} else {
color = colorOK;
image = R.drawable.ic_check_circle;
magiskUpdateText.setText(getString(R.string.install_magisk_title, "v" + mm.remoteMagiskVersionString));
installButton.setVisibility(View.VISIBLE);
if (mm.remoteManagerVersionCode > BuildConfig.VERSION_CODE) {
installText.setText(getString(R.string.update, getString(R.string.app_name)));
} else if (mm.magiskVersionCode > 0 && mm.remoteMagiskVersionCode > mm.magiskVersionCode) {
installText.setText(getString(R.string.update, getString(R.string.magisk)));
} else {
installText.setText(R.string.install);
}
}
magiskUpdateIcon.setImageResource(image);
magiskUpdateIcon.setColorFilter(color);
magiskUpdateIcon.setVisibility(View.VISIBLE);
magiskUpdateProgress.setVisibility(View.GONE);
mSwipeRefreshLayout.setRefreshing(false);
if (!shownDialog) {
if (mm.remoteMagiskVersionCode > mm.magiskVersionCode
|| mm.remoteManagerVersionCode > BuildConfig.VERSION_CODE) {
install();
} else if (mm.remoteMagiskVersionCode >= Const.MAGISK_VER.FIX_ENV &&
!ShellUtils.fastCmdResult("env_check")) {
ShowUI.envFixDialog(getActivity());
}
}
}
private void updateSafetyNetUI(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);
expand();
} else {
@StringRes int resid;
switch (response) {
case ISafetyNetHelper.CAUSE_SERVICE_DISCONNECTED:
resid = R.string.safetyNet_network_loss;
break;
case ISafetyNetHelper.CAUSE_NETWORK_LOST:
resid = R.string.safetyNet_service_disconnected;
break;
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);
}
}
}

View File

@@ -1,92 +0,0 @@
package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SearchView;
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.utils.Topic;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class MagiskHideFragment extends Fragment implements Topic.Subscriber {
private Unbinder unbinder;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
private ApplicationAdapter appAdapter;
private SearchView.OnQueryTextListener searchListener;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_magisk_hide, container, false);
unbinder = ButterKnife.bind(this, view);
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.setOnRefreshListener(() -> appAdapter.refresh());
appAdapter = new ApplicationAdapter();
recyclerView.setAdapter(appAdapter);
searchListener = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
appAdapter.filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
appAdapter.filter(newText);
return false;
}
};
getActivity().setTitle(R.string.magiskhide);
return view;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_magiskhide, menu);
SearchView search = (SearchView) menu.findItem(R.id.app_search).getActionView();
search.setOnQueryTextListener(searchListener);
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@Override
public void onTopicPublished(Topic topic) {
mSwipeRefreshLayout.setRefreshing(false);
appAdapter.filter(null);
}
@Override
public Topic[] getSubscription() {
return new Topic[] { getApplication().magiskHideDone };
}
}

View File

@@ -1,145 +0,0 @@
package com.topjohnwu.magisk;
import android.Manifest;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.text.TextUtils;
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.HorizontalScrollView;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class MagiskLogFragment extends Fragment {
private Unbinder unbinder;
@BindView(R.id.txtLog) TextView txtLog;
@BindView(R.id.svLog) ScrollView svLog;
@BindView(R.id.hsvLog) HorizontalScrollView hsvLog;
@BindView(R.id.progressBar) ProgressBar progressBar;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_magisk_log, container, false);
unbinder = ButterKnife.bind(this, view);
setHasOptionsMenu(true);
txtLog.setTextIsSelectable(true);
return view;
}
@Override
public void onStart() {
super.onStart();
getActivity().setTitle(R.string.log);
}
@Override
public void onResume() {
super.onResume();
readLogs();
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@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();
return true;
default:
return true;
}
}
public void readLogs() {
Shell.Async.su(new Shell.Async.Callback() {
@Override
public void onTaskResult(@Nullable List<String> out, @Nullable List<String> err) {
progressBar.setVisibility(View.GONE);
if (ShellUtils.isValidOutput(out)) {
txtLog.setText(TextUtils.join("\n", out));
} else {
txtLog.setText(R.string.log_is_empty);
}
svLog.postDelayed(() -> svLog.fullScroll(ScrollView.FOCUS_DOWN), 100);
hsvLog.postDelayed(() -> hsvLog.fullScroll(ScrollView.FOCUS_LEFT), 100);
}
@Override
public void onTaskError(@NonNull Throwable throwable) {
txtLog.setText(R.string.log_is_empty);
}
}, "cat " + Const.MAGISK_LOG + " | tail -n 5000");
}
public 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 targetFile = new File(Const.EXTERNAL_PATH + "/logs", filename);
targetFile.getParentFile().mkdirs();
try {
targetFile.createNewFile();
} catch (IOException e) {
return;
}
Shell.Async.su(new Shell.Async.Callback() {
@Override
public void onTaskResult(@Nullable List<String> out, @Nullable List<String> err) {
SnackbarMaker.make(txtLog, targetFile.getPath(), Snackbar.LENGTH_SHORT).show();
}
@Override
public void onTaskError(@NonNull Throwable throwable) {}
}, "cat " + Const.MAGISK_LOG + " > " + targetFile);
}
public void clearLogs() {
Shell.Async.su("echo -n > " + Const.MAGISK_LOG);
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
}
}

View File

@@ -1,292 +0,0 @@
package com.topjohnwu.magisk;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Xml;
import com.topjohnwu.magisk.components.Application;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.database.MagiskDatabaseHelper;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.services.UpdateCheckService;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.magisk.utils.ShellInitializer;
import com.topjohnwu.magisk.utils.Topic;
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;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class MagiskManager extends Application implements Shell.Container {
// Topics
public final Topic magiskHideDone = new Topic();
public final Topic reloadActivity = new Topic();
public final Topic moduleLoadDone = new Topic();
public final Topic repoLoadDone = new Topic();
public final Topic updateCheckDone = new Topic();
public final Topic safetyNetDone = new Topic();
public final Topic localeDone = new Topic();
// Info
public boolean hasInit = false;
public String magiskVersionString;
public int magiskVersionCode = -1;
public String remoteMagiskVersionString;
public int remoteMagiskVersionCode = -1;
public String remoteManagerVersionString;
public int remoteManagerVersionCode = -1;
public String magiskLink;
public String magiskNoteLink;
public String managerLink;
public String managerNoteLink;
public String uninstallerLink;
public boolean keepVerity = false;
public boolean keepEnc = false;
// Data
public Map<String, Module> moduleMap;
public List<Locale> locales;
public boolean magiskHide;
public boolean isDarkTheme;
public int suRequestTimeout;
public int suLogTimeout = 14;
public int suAccessState;
public int multiuserMode;
public int suResponseType;
public int suNotificationType;
public int suNamespaceMode;
public String localeConfig;
public int updateChannel;
public String bootFormat;
public int repoOrder;
// Global resources
public SharedPreferences prefs;
public MagiskDatabaseHelper mDB;
public RepoDatabaseHelper repoDB;
private volatile Shell mShell;
public MagiskManager() {
weakSelf = new WeakReference<>(this);
Shell.setContainer(this);
}
@Nullable
@Override
public Shell getShell() {
return mShell;
}
@Override
public void setShell(@Nullable Shell shell) {
mShell = shell;
}
@Override
public void onCreate() {
super.onCreate();
Shell.setFlags(Shell.FLAG_MOUNT_MASTER);
Shell.verboseLogging(BuildConfig.DEBUG);
Shell.setInitializer(ShellInitializer.class);
prefs = PreferenceManager.getDefaultSharedPreferences(this);
mDB = MagiskDatabaseHelper.getInstance(this);
String pkg = mDB.getStrings(Const.Key.SU_MANAGER, null);
if (pkg != null && getPackageName().equals(Const.ORIG_PKG_NAME)) {
mDB.setStrings(Const.Key.SU_MANAGER, null);
RootUtils.uninstallPkg(pkg);
}
if (TextUtils.equals(pkg, getPackageName())) {
try {
// We are the manager, remove com.topjohnwu.magisk as it could be malware
getPackageManager().getApplicationInfo(Const.ORIG_PKG_NAME, 0);
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);
} catch (PackageManager.NameNotFoundException ignored) {}
}
setLocale();
loadConfig();
}
public static MagiskManager get() {
return (MagiskManager) weakSelf.get();
}
public void setLocale() {
localeConfig = prefs.getString(Const.Key.LOCALE, "");
if (localeConfig.isEmpty()) {
locale = defaultLocale;
} else {
locale = Locale.forLanguageTag(localeConfig);
}
Resources res = getBaseContext().getResources();
Configuration config = new Configuration(res.getConfiguration());
config.setLocale(locale);
res.updateConfiguration(config, res.getDisplayMetrics());
}
public void loadConfig() {
// su
suRequestTimeout = Utils.getPrefsInt(prefs, Const.Key.SU_REQUEST_TIMEOUT, Const.Value.timeoutList[2]);
suResponseType = Utils.getPrefsInt(prefs, Const.Key.SU_AUTO_RESPONSE, Const.Value.SU_PROMPT);
suNotificationType = Utils.getPrefsInt(prefs, Const.Key.SU_NOTIFICATION, Const.Value.NOTIFICATION_TOAST);
suAccessState = mDB.getSettings(Const.Key.ROOT_ACCESS, Const.Value.ROOT_ACCESS_APPS_AND_ADB);
multiuserMode = mDB.getSettings(Const.Key.SU_MULTIUSER_MODE, Const.Value.MULTIUSER_MODE_OWNER_ONLY);
suNamespaceMode = mDB.getSettings(Const.Key.SU_MNT_NS, Const.Value.NAMESPACE_MODE_REQUESTER);
// config
isDarkTheme = prefs.getBoolean(Const.Key.DARK_THEME, false);
updateChannel = Utils.getPrefsInt(prefs, Const.Key.UPDATE_CHANNEL, Const.Value.STABLE_CHANNEL);
bootFormat = prefs.getString(Const.Key.BOOT_FORMAT, ".img");
repoOrder = prefs.getInt(Const.Key.REPO_ORDER, Const.Value.ORDER_NAME);
}
public void writeConfig() {
prefs.edit()
.putBoolean(Const.Key.DARK_THEME, isDarkTheme)
.putBoolean(Const.Key.MAGISKHIDE, magiskHide)
.putBoolean(Const.Key.HOSTS, Const.MAGISK_HOST_FILE.exists())
.putBoolean(Const.Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists())
.putString(Const.Key.SU_REQUEST_TIMEOUT, String.valueOf(suRequestTimeout))
.putString(Const.Key.SU_AUTO_RESPONSE, String.valueOf(suResponseType))
.putString(Const.Key.SU_NOTIFICATION, String.valueOf(suNotificationType))
.putString(Const.Key.ROOT_ACCESS, String.valueOf(suAccessState))
.putString(Const.Key.SU_MULTIUSER_MODE, String.valueOf(multiuserMode))
.putString(Const.Key.SU_MNT_NS, String.valueOf(suNamespaceMode))
.putString(Const.Key.UPDATE_CHANNEL, String.valueOf(updateChannel))
.putString(Const.Key.LOCALE, localeConfig)
.putString(Const.Key.BOOT_FORMAT, bootFormat)
.putInt(Const.Key.UPDATE_SERVICE_VER, Const.UPDATE_SERVICE_VER)
.putInt(Const.Key.REPO_ORDER, repoOrder)
.apply();
}
public void loadMagiskInfo() {
try {
magiskVersionString = ShellUtils.fastCmd("magisk -v").split(":")[0];
magiskVersionCode = Integer.parseInt(ShellUtils.fastCmd("magisk -V"));
String s = ShellUtils.fastCmd((magiskVersionCode >= Const.MAGISK_VER.RESETPROP_PERSIST ?
"resetprop -p " : "getprop ") + Const.MAGISKHIDE_PROP);
magiskHide = s == null || Integer.parseInt(s) != 0;
} catch (Exception ignored) {}
}
public void getDefaultInstallFlags() {
keepVerity = Boolean.parseBoolean(ShellUtils.fastCmd("echo $KEEPVERITY"));
keepEnc = Boolean.parseBoolean(ShellUtils.fastCmd("echo $KEEPFORCEENCRYPT"));
}
public void setupUpdateCheck() {
JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
if (prefs.getBoolean(Const.Key.CHECK_UPDATES, true)) {
if (scheduler.getAllPendingJobs().isEmpty() ||
Const.UPDATE_SERVICE_VER > prefs.getInt(Const.Key.UPDATE_SERVICE_VER, -1)) {
ComponentName service = new ComponentName(this, UpdateCheckService.class);
JobInfo info = new JobInfo.Builder(Const.ID.UPDATE_SERVICE_ID, service)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.setPeriodic(8 * 60 * 60 * 1000)
.build();
scheduler.schedule(info);
}
} else {
scheduler.cancel(Const.UPDATE_SERVICE_VER);
}
}
public void dumpPrefs() {
// Flush prefs to disk
prefs.edit().commit();
File xml = new File(getFilesDir().getParent() + "/shared_prefs",
getPackageName() + "_preferences.xml");
Shell.Sync.su(Utils.fmt("for usr in /data/user/*; do cat %s > ${usr}/%s; done", xml, Const.MANAGER_CONFIGS));
}
public void loadPrefs() {
SuFile config = new SuFile(Utils.fmt("/data/user/%d/%s", Const.USER_ID, Const.MANAGER_CONFIGS));
if (config.exists()) {
SharedPreferences.Editor editor = prefs.edit();
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(Const.Key.ETAG_KEY);
editor.apply();
loadConfig();
config.delete();
}
}
}

View File

@@ -1,219 +0,0 @@
package com.topjohnwu.magisk;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainActivity extends Activity
implements NavigationView.OnNavigationItemSelectedListener, Topic.Subscriber {
private final Handler mDrawerHandler = new Handler();
private int mDrawerItem;
private boolean fromShortcut = true;
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.drawer_layout) DrawerLayout drawer;
@BindView(R.id.nav_view) public NavigationView navigationView;
private float toolbarElevation;
@Override
public int getDarkTheme() {
return R.style.AppTheme_Dark;
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
MagiskManager mm = getMagiskManager();
if (!mm.hasInit) {
Intent intent = new Intent(this, SplashActivity.class);
String section = getIntent().getStringExtra(Const.Key.OPEN_SECTION);
if (section != null) {
intent.putExtra(Const.Key.OPEN_SECTION, section);
}
startActivity(intent);
finish();
}
String perm = getIntent().getStringExtra(Const.Key.INTENT_PERM);
if (perm != null) {
ActivityCompat.requestPermissions(this, new String[] { perm }, 0);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(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
}
};
toolbarElevation = toolbar.getElevation();
drawer.addDrawerListener(toggle);
toggle.syncState();
if (savedInstanceState == null)
navigate(getIntent().getStringExtra(Const.Key.OPEN_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 onTopicPublished(Topic topic) {
recreate();
}
@Override
public Topic[] getSubscription() {
return new Topic[] { getMagiskManager().reloadActivity };
}
public void checkHideSection() {
MagiskManager mm = getMagiskManager();
Menu menu = navigationView.getMenu();
menu.findItem(R.id.magiskhide).setVisible(
Shell.rootAccess() && mm.magiskVersionCode >= Const.MAGISK_VER.UNIFIED
&& mm.prefs.getBoolean(Const.Key.MAGISKHIDE, false));
menu.findItem(R.id.modules).setVisible(!mm.prefs.getBoolean(Const.Key.COREONLY, false) &&
Shell.rootAccess() && mm.magiskVersionCode >= 0);
menu.findItem(R.id.downloads).setVisible(!mm.prefs.getBoolean(Const.Key.COREONLY, false)
&& Utils.checkNetworkStatus() && Shell.rootAccess() && mm.magiskVersionCode >= 0);
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
menu.findItem(R.id.superuser).setVisible(Shell.rootAccess() &&
!(Const.USER_ID > 0 && mm.multiuserMode == Const.Value.MULTIUSER_MODE_OWNER_MANAGED));
}
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;
case "about":
itemId = R.id.app_about;
break;
}
}
navigate(itemId);
}
public void navigate(int itemId) {
int bak = mDrawerItem;
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:
startActivity(new Intent(this, SettingsActivity.class));
mDrawerItem = bak;
break;
case R.id.app_about:
startActivity(new Intent(this, AboutActivity.class));
mDrawerItem = bak;
break;
}
}
private void displayFragment(@NonNull Fragment navFragment, boolean setElevation) {
supportInvalidateOptionsMenu();
getSupportFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.content_frame, navFragment)
.commitNow();
toolbar.setElevation(setElevation ? toolbarElevation : 0);
}
}

View File

@@ -1,144 +0,0 @@
package com.topjohnwu.magisk;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
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.adapters.ModulesAdapter;
import com.topjohnwu.magisk.asyncs.LoadModules;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.superuser.Shell;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
public class ModulesFragment extends Fragment implements Topic.Subscriber {
private Unbinder unbinder;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
@BindView(R.id.empty_rv) TextView emptyRv;
@OnClick(R.id.fab)
public 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(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_modules, container, false);
unbinder = ButterKnife.bind(this, view);
setHasOptionsMenu(true);
mSwipeRefreshLayout.setOnRefreshListener(() -> {
recyclerView.setVisibility(View.GONE);
new LoadModules().exec();
});
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);
}
});
getActivity().setTitle(R.string.modules);
return view;
}
@Override
public void onTopicPublished(Topic topic) {
updateUI();
}
@Override
public Topic[] getSubscription() {
return new Topic[] { getApplication().moduleLoadDone };
}
@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(), FlashActivity.class);
intent.setData(data.getData()).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
startActivity(intent);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@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:
Shell.Async.su("/system/bin/reboot");
return true;
case R.id.reboot_recovery:
Shell.Async.su("/system/bin/reboot recovery");
return true;
case R.id.reboot_bootloader:
Shell.Async.su("/system/bin/reboot bootloader");
return true;
case R.id.reboot_download:
Shell.Async.su("/system/bin/reboot download");
return true;
default:
return false;
}
}
private void updateUI() {
listModules.clear();
listModules.addAll(getApplication().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,26 +0,0 @@
package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.Const;
public class NoUIActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] perms = getIntent().getStringArrayExtra(Const.Key.INTENT_PERM);
if (perms != null) {
ActivityCompat.requestPermissions(this, perms, 0);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
finish();
}
}

View File

@@ -1,126 +0,0 @@
package com.topjohnwu.magisk;
import android.app.AlertDialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
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.adapters.ReposAdapter;
import com.topjohnwu.magisk.asyncs.UpdateRepos;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Topic;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class ReposFragment extends Fragment implements Topic.Subscriber {
private Unbinder unbinder;
private MagiskManager mm;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
@BindView(R.id.empty_rv) TextView emptyRv;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
public static ReposAdapter adapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_repos, container, false);
unbinder = ButterKnife.bind(this, view);
mm = getApplication();
mSwipeRefreshLayout.setRefreshing(mm.repoLoadDone.isPending());
mSwipeRefreshLayout.setOnRefreshListener(() -> {
recyclerView.setVisibility(View.VISIBLE);
emptyRv.setVisibility(View.GONE);
new UpdateRepos(true).exec();
});
getActivity().setTitle(R.string.downloads);
return view;
}
@Override
public void onResume() {
adapter = new ReposAdapter(mm.repoDB, mm.moduleMap);
recyclerView.setAdapter(adapter);
super.onResume();
}
@Override
public void onPause() {
super.onPause();
adapter = null;
}
@Override
public void onTopicPublished(Topic topic) {
mSwipeRefreshLayout.setRefreshing(false);
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
@Override
public Topic[] getSubscription() {
return new Topic[] { mm.repoLoadDone };
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_repo, menu);
SearchView search = (SearchView) menu.findItem(R.id.repo_search).getActionView();
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@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, mm.repoOrder, (d, which) -> {
mm.repoOrder = which;
mm.prefs.edit().putInt(Const.Key.REPO_ORDER, mm.repoOrder).apply();
adapter.notifyDBChanged();
d.dismiss();
}).show();
}
return true;
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}

View File

@@ -1,321 +0,0 @@
package com.topjohnwu.magisk;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.Toast;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
import com.topjohnwu.magisk.asyncs.HideManager;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.receivers.DownloadReceiver;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import java.io.IOException;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
public class SettingsActivity extends Activity implements Topic.Subscriber {
@BindView(R.id.toolbar) Toolbar toolbar;
@Override
public int getDarkTheme() {
return R.style.AppTheme_StatusBar_Dark;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setTitle(R.string.settings);
ab.setDisplayHomeAsUpEnabled(true);
}
setFloating();
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.container, new SettingsFragment()).commit();
}
}
@Override
public void onTopicPublished(Topic topic) {
recreate();
}
@Override
public Topic[] getSubscription() {
return new Topic[] { getMagiskManager().reloadActivity };
}
public static class SettingsFragment extends PreferenceFragmentCompat
implements SharedPreferences.OnSharedPreferenceChangeListener, Topic.Subscriber {
private SharedPreferences prefs;
private PreferenceScreen prefScreen;
private ListPreference updateChannel, suAccess, autoRes, suNotification,
requestTimeout, multiuserMode, namespaceMode;
private MagiskManager mm;
private PreferenceCategory generalCatagory;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.app_settings, rootKey);
mm = Utils.getMagiskManager(getActivity());
prefs = mm.prefs;
prefScreen = getPreferenceScreen();
generalCatagory = (PreferenceCategory) findPreference("general");
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
Preference hideManager = findPreference("hide");
Preference restoreManager = findPreference("restore");
findPreference("clear").setOnPreferenceClickListener((pref) -> {
prefs.edit().remove(Const.Key.ETAG_KEY).apply();
mm.repoDB.clearRepo();
MagiskManager.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT);
return true;
});
updateChannel = (ListPreference) findPreference(Const.Key.UPDATE_CHANNEL);
suAccess = (ListPreference) findPreference(Const.Key.ROOT_ACCESS);
autoRes = (ListPreference) findPreference(Const.Key.SU_AUTO_RESPONSE);
requestTimeout = (ListPreference) findPreference(Const.Key.SU_REQUEST_TIMEOUT);
suNotification = (ListPreference) findPreference(Const.Key.SU_NOTIFICATION);
multiuserMode = (ListPreference) findPreference(Const.Key.SU_MULTIUSER_MODE);
namespaceMode = (ListPreference) findPreference(Const.Key.SU_MNT_NS);
SwitchPreference reauth = (SwitchPreference) findPreference(Const.Key.SU_REAUTH);
SwitchPreference fingerprint = (SwitchPreference) findPreference(Const.Key.SU_FINGERPRINT);
updateChannel.setOnPreferenceChangeListener((pref, o) -> {
mm.updateChannel = Integer.parseInt((String) o);
if (mm.updateChannel == Const.Value.CUSTOM_CHANNEL) {
View v = LayoutInflater.from(getActivity()).inflate(R.layout.custom_channel_dialog, null);
EditText url = v.findViewById(R.id.custom_url);
url.setText(mm.prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
new AlertDialog.Builder(getActivity())
.setTitle(R.string.settings_update_custom)
.setView(v)
.setPositiveButton(R.string.ok, (d, i) ->
prefs.edit().putString(Const.Key.CUSTOM_CHANNEL,
url.getText().toString()).apply())
.setNegativeButton(R.string.close, null)
.show();
}
return true;
});
setSummary();
// Disable dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserMode);
}
// Disable re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
reauth.setEnabled(false);
reauth.setSummary(R.string.android_o_not_support);
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.setEnabled(false);
fingerprint.setSummary(R.string.disable_fingerprint);
}
if (mm.magiskVersionCode >= Const.MAGISK_VER.MANAGER_HIDE) {
if (mm.getPackageName().equals(Const.ORIG_PKG_NAME)) {
hideManager.setOnPreferenceClickListener((pref) -> {
new HideManager(getActivity()).exec();
return true;
});
generalCatagory.removePreference(restoreManager);
} else {
if (Utils.checkNetworkStatus()) {
restoreManager.setOnPreferenceClickListener((pref) -> {
Utils.dlAndReceive(
getActivity(), new DownloadReceiver() {
@Override
public void onDownloadDone(Context context, Uri uri) {
mm.dumpPrefs();
if (ShellUtils.fastCmdResult("pm install " + uri.getPath()))
RootUtils.uninstallPkg(context.getPackageName());
}
},
mm.managerLink,
Utils.fmt("MagiskManager-v%s.apk", mm.remoteManagerVersionString)
);
return true;
});
} else {
generalCatagory.removePreference(restoreManager);
}
generalCatagory.removePreference(hideManager);
}
} else {
generalCatagory.removePreference(restoreManager);
generalCatagory.removePreference(hideManager);
}
if (!Shell.rootAccess() || (Const.USER_ID > 0 &&
mm.multiuserMode == Const.Value.MULTIUSER_MODE_OWNER_MANAGED)) {
prefScreen.removePreference(suCategory);
}
if (!Shell.rootAccess()) {
prefScreen.removePreference(magiskCategory);
generalCatagory.removePreference(hideManager);
} else if (mm.magiskVersionCode < Const.MAGISK_VER.UNIFIED) {
prefScreen.removePreference(magiskCategory);
}
}
private void setLocalePreference(ListPreference lp) {
CharSequence[] entries = new CharSequence[mm.locales.size() + 1];
CharSequence[] entryValues = new CharSequence[mm.locales.size() + 1];
entries[0] = Utils.getLocaleString(MagiskManager.defaultLocale, R.string.system_default);
entryValues[0] = "";
int i = 1;
for (Locale locale : mm.locales) {
entries[i] = locale.getDisplayName(locale);
entryValues[i++] = locale.toLanguageTag();
}
lp.setEntries(entries);
lp.setEntryValues(entryValues);
lp.setSummary(MagiskManager.locale.getDisplayName(MagiskManager.locale));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
prefs.registerOnSharedPreferenceChangeListener(this);
subscribeTopics();
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onDestroyView() {
prefs.unregisterOnSharedPreferenceChangeListener(this);
unsubscribeTopics();
super.onDestroyView();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
switch (key) {
case Const.Key.DARK_THEME:
mm.isDarkTheme = prefs.getBoolean(key, false);
mm.reloadActivity.publish(false);
return;
case Const.Key.COREONLY:
if (prefs.getBoolean(key, false)) {
try {
Const.MAGISK_DISABLE_FILE.createNewFile();
} catch (IOException ignored) {}
} else {
Const.MAGISK_DISABLE_FILE.delete();
}
Toast.makeText(getActivity(), R.string.settings_reboot_toast, Toast.LENGTH_LONG).show();
break;
case Const.Key.MAGISKHIDE:
if (prefs.getBoolean(key, false)) {
Shell.Async.su("magiskhide --enable");
} else {
Shell.Async.su("magiskhide --disable");
}
break;
case Const.Key.HOSTS:
if (prefs.getBoolean(key, false)) {
Shell.Async.su(
"cp -af /system/etc/hosts " + Const.MAGISK_HOST_FILE,
"mount -o bind " + Const.MAGISK_HOST_FILE + " /system/etc/hosts");
} else {
Shell.Async.su(
"umount -l /system/etc/hosts",
"rm -f " + Const.MAGISK_HOST_FILE);
}
break;
case Const.Key.ROOT_ACCESS:
case Const.Key.SU_MULTIUSER_MODE:
case Const.Key.SU_MNT_NS:
mm.mDB.setSettings(key, Utils.getPrefsInt(prefs, key));
break;
case Const.Key.LOCALE:
mm.setLocale();
mm.reloadActivity.publish(false);
break;
case Const.Key.UPDATE_CHANNEL:
new CheckUpdates().exec();
break;
case Const.Key.CHECK_UPDATES:
mm.setupUpdateCheck();
break;
}
mm.loadConfig();
setSummary();
}
private void setSummary() {
updateChannel.setSummary(getResources()
.getStringArray(R.array.update_channel)[mm.updateChannel]);
suAccess.setSummary(getResources()
.getStringArray(R.array.su_access)[mm.suAccessState]);
autoRes.setSummary(getResources()
.getStringArray(R.array.auto_response)[mm.suResponseType]);
suNotification.setSummary(getResources()
.getStringArray(R.array.su_notification)[mm.suNotificationType]);
requestTimeout.setSummary(
getString(R.string.request_timeout_summary, prefs.getString(Const.Key.SU_REQUEST_TIMEOUT, "10")));
multiuserMode.setSummary(getResources()
.getStringArray(R.array.multiuser_summary)[mm.multiuserMode]);
namespaceMode.setSummary(getResources()
.getStringArray(R.array.namespace_summary)[mm.suNamespaceMode]);
}
@Override
public void onTopicPublished(Topic topic) {
setLocalePreference((ListPreference) findPreference(Const.Key.LOCALE));
}
@Override
public Topic[] getSubscription() {
return new Topic[] { mm.localeDone };
}
}
}

View File

@@ -1,88 +0,0 @@
package com.topjohnwu.magisk;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
import com.topjohnwu.magisk.asyncs.LoadModules;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.asyncs.UpdateRepos;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.receivers.ShortcutReceiver;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
public class SplashActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RootUtils.init();
MagiskManager mm = getMagiskManager();
mm.repoDB = new RepoDatabaseHelper(this);
mm.loadMagiskInfo();
mm.getDefaultInstallFlags();
mm.loadPrefs();
// Dynamic detect all locales
new LoadLocale().exec();
// Create notification channel on Android O
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(Const.ID.NOTIFICATION_CHANNEL,
getString(R.string.magisk_updates), NotificationManager.IMPORTANCE_DEFAULT);
getSystemService(NotificationManager.class).createNotificationChannel(channel);
}
// Setup shortcuts
sendBroadcast(new Intent(this, ShortcutReceiver.class));
LoadModules loadModuleTask = new LoadModules();
if (Utils.checkNetworkStatus()) {
// Fire update check
new CheckUpdates().exec();
// Add repo update check
loadModuleTask.setCallBack(() -> new UpdateRepos(false).exec());
}
// Magisk working as expected
if (Shell.rootAccess() && mm.magiskVersionCode > 0) {
// Update check service
mm.setupUpdateCheck();
// Fire asynctasks
loadModuleTask.exec();
}
// Write back default values
mm.writeConfig();
mm.hasInit = true;
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION));
intent.putExtra(Const.Key.INTENT_PERM, getIntent().getStringExtra(Const.Key.INTENT_PERM));
startActivity(intent);
finish();
}
static class LoadLocale extends ParallelTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
MagiskManager.get().locales = Utils.getAvailableLocale();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
MagiskManager.get().localeDone.publish();
}
}
}

View File

@@ -1,89 +0,0 @@
package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
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.adapters.SuLogAdapter;
import com.topjohnwu.magisk.components.Fragment;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class SuLogFragment extends Fragment {
@BindView(R.id.empty_rv) TextView emptyRv;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
private Unbinder unbinder;
private MagiskManager mm;
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 = ButterKnife.bind(this, v);
mm = getApplication();
adapter = new SuLogAdapter(mm.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:
mm.mDB.clearLogs();
updateList();
return true;
default:
return true;
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}

View File

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

View File

@@ -1,158 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.TextView;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.superuser.Shell;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
private List<ApplicationInfo> fullList, showList;
private List<String> hideList;
private PackageManager pm;
private ApplicationFilter filter;
public ApplicationAdapter() {
fullList = showList = Collections.emptyList();
hideList = Collections.emptyList();
filter = new ApplicationFilter();
pm = MagiskManager.get().getPackageManager();
new LoadApps().exec();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_app, parent, false);
return new ViewHolder(mView);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
ApplicationInfo info = showList.get(position);
holder.appIcon.setImageDrawable(info.loadIcon(pm));
holder.appName.setText(info.loadLabel(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.Async.su("magiskhide --add " + info.packageName);
hideList.add(info.packageName);
} else {
Shell.Async.su("magiskhide --rm " + info.packageName);
hideList.remove(info.packageName);
}
});
}
@Override
public int getItemCount() {
return showList.size();
}
public void filter(String constraint) {
filter.filter(constraint);
}
public void refresh() {
new LoadApps().exec();
}
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);
ButterKnife.bind(this, itemView);
}
}
private class ApplicationFilter extends Filter {
private boolean lowercaseContains(String s, CharSequence filter) {
return !TextUtils.isEmpty(s) && s.toLowerCase().contains(filter);
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (constraint == null || constraint.length() == 0) {
showList = fullList;
} else {
showList = new ArrayList<>();
String filter = constraint.toString().toLowerCase();
for (ApplicationInfo info : fullList) {
if (lowercaseContains(info.loadLabel(pm).toString(), filter)
|| lowercaseContains(info.packageName, filter)) {
showList.add(info);
}
}
}
return null;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
notifyDataSetChanged();
}
}
private class LoadApps extends ParallelTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
fullList = pm.getInstalledApplications(0);
hideList = Shell.Sync.su("magiskhide --ls");
for (Iterator<ApplicationInfo> i = fullList.iterator(); i.hasNext(); ) {
ApplicationInfo info = i.next();
if (Const.HIDE_BLACKLIST.contains(info.packageName) || !info.enabled) {
i.remove();
}
}
Collections.sort(fullList, (a, b) -> {
boolean ah = hideList.contains(a.packageName);
boolean bh = hideList.contains(b.packageName);
if (ah == bh) {
return a.loadLabel(pm).toString().toLowerCase().compareTo(
b.loadLabel(pm).toString().toLowerCase());
} else if (ah) {
return -1;
} else {
return 1;
}
});
return null;
}
@Override
protected void onPostExecute(Void v) {
MagiskManager.get().magiskHideDone.publish(false);
}
}
}

View File

@@ -1,125 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.content.Context;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
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.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.superuser.Shell;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHolder> {
private final List<Module> mList;
public ModulesAdapter(List<Module> list) {
mList = list;
}
@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);
ButterKnife.bind(this, itemView);
if (!Shell.rootAccess()) {
checkBox.setEnabled(false);
delete.setEnabled(false);
}
}
}
}

View File

@@ -1,150 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.database.MagiskDatabaseHelper;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import butterknife.BindView;
import butterknife.ButterKnife;
public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder> {
private List<Policy> policyList;
private MagiskDatabaseHelper dbHelper;
private PackageManager pm;
private Set<Policy> expandList = new HashSet<>();
public PolicyAdapter(List<Policy> list, MagiskDatabaseHelper db, PackageManager pm) {
policyList = list;
dbHelper = db;
this.pm = pm;
}
@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.setExpanded(expandList.contains(policy));
holder.itemView.setOnClickListener(view -> {
if (holder.isExpanded()) {
holder.collapse();
expandList.remove(policy);
} else {
holder.expand();
expandList.add(policy);
}
});
holder.appName.setText(policy.appName);
holder.packageName.setText(policy.packageName);
holder.appIcon.setImageDrawable(policy.info.loadIcon(pm));
holder.masterSwitch.setOnCheckedChangeListener((v, isChecked) -> {
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);
}
});
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 AlertDialogBuilder((Activity) v.getContext())
.setTitle(R.string.su_revoke_title)
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
.setPositiveButton(R.string.yes, (dialog, which) -> {
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());
holder.masterSwitch.setChecked(policy.policy == Policy.ALLOW);
holder.notificationSwitch.setChecked(policy.notification);
holder.loggingSwitch.setChecked(policy.logging);
// Hide for now
holder.moreInfo.setVisibility(View.GONE);
}
@Override
public int getItemCount() {
return policyList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder implements ExpandableView {
@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) Switch masterSwitch;
@BindView(R.id.notification_switch) Switch notificationSwitch;
@BindView(R.id.logging_switch) Switch loggingSwitch;
@BindView(R.id.expand_layout) ViewGroup expandLayout;
@BindView(R.id.delete) ImageView delete;
@BindView(R.id.more_info) ImageView moreInfo;
private Container container = new Container();
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
container.expandLayout = expandLayout;
setupExpandable();
}
@Override
public Container getContainer() {
return container;
}
}
}

View File

@@ -1,192 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.utils.Utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ReposAdapter extends 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();
holder.title.setText(repo.getName());
holder.versionName.setText(repo.getVersion());
String author = repo.getAuthor();
holder.author.setText(TextUtils.isEmpty(author) ? null : context.getString(R.string.author, author));
holder.description.setText(repo.getDescription());
holder.updateTime.setText(context.getString(R.string.updated_on, repo.getLastUpdateString()));
holder.infoLayout.setOnClickListener(v ->
new MarkDownWindow((Activity) context, null, repo.getDetailUrl()).exec());
holder.downloadImage.setOnClickListener(v -> {
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
new AlertDialogBuilder((Activity) context)
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
.setMessage(context.getString(R.string.repo_install_msg, filename))
.setCancelable(true)
.setPositiveButton(R.string.install, (d, i) ->
new ProcessRepoZip((Activity) context, repo.getZipUrl(),
Utils.getLegalFilename(filename), true).exec()
)
.setNeutralButton(R.string.download, (d, i) ->
new ProcessRepoZip((Activity) context, repo.getZipUrl(),
Utils.getLegalFilename(filename), false).exec())
.setNegativeButton(R.string.no_thanks, null)
.show();
});
}
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);
ButterKnife.bind(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) LinearLayout infoLayout;
@BindView(R.id.download) ImageView downloadImage;
@BindView(R.id.update_time) TextView updateTime;
RepoHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}

View File

@@ -1,93 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
public abstract class SectionedAdapter<S extends RecyclerView.ViewHolder, C extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int SECTION_TYPE = Integer.MIN_VALUE;
@Override
final public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == SECTION_TYPE)
return onCreateSectionViewHolder(parent);
return onCreateItemViewHolder(parent, viewType);
}
@Override
@SuppressWarnings("unchecked")
final public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
PositionInfo info = getPositionInfo(position);
if (info.position == -1)
onBindSectionViewHolder((S) holder, info.section);
else
onBindItemViewHolder((C) holder, info.section, info.position);
}
@Override
final public int getItemCount() {
int size, sec;
size = sec = getSectionCount();
for (int i = 0; i < sec; ++i){
size += getItemCount(i);
}
return size;
}
@Override
final public int getItemViewType(int position) {
PositionInfo info = getPositionInfo(position);
if (info.position == -1)
return SECTION_TYPE;
else
return getItemViewType(info.section, info.position);
}
public int getItemViewType(int section, int position) {
return 0;
}
protected int getSectionPosition(int section) {
return getItemPosition(section, -1);
}
protected int getItemPosition(int section, int position) {
int realPosition = 0;
// Previous sections
for (int i = 0; i < section; ++i) {
realPosition += getItemCount(i) + 1;
}
// Current section
realPosition += position + 1;
return realPosition;
}
private PositionInfo getPositionInfo(int position) {
int section = 0;
while (true) {
if (position == 0)
return new PositionInfo(section, -1);
position -= 1;
if (position < getItemCount(section))
return new PositionInfo(section, position);
position -= getItemCount(section++);
}
}
private static class PositionInfo {
int section;
int position;
PositionInfo(int section, int position) {
this.section = section;
this.position = position;
}
}
public abstract int getSectionCount();
public abstract int getItemCount(int section);
public abstract S onCreateSectionViewHolder(ViewGroup parent);
public abstract C onCreateItemViewHolder(ViewGroup parent, int viewType);
public abstract void onBindSectionViewHolder(S holder, int section);
public abstract void onBindItemViewHolder(C holder, int section, int position);
}

View File

@@ -1,155 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
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.components.ExpandableView;
import com.topjohnwu.magisk.container.SuLogEntry;
import com.topjohnwu.magisk.database.MagiskDatabaseHelper;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import butterknife.BindView;
import butterknife.ButterKnife;
public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, SuLogAdapter.LogViewHolder> {
private List<List<Integer>> logEntryList;
private Set<Integer> itemExpanded, sectionExpanded;
private MagiskDatabaseHelper suDB;
private Cursor suLogCursor = null;
public SuLogAdapter(MagiskDatabaseHelper db) {
suDB = db;
logEntryList = Collections.emptyList();
sectionExpanded = new HashSet<>();
itemExpanded = new HashSet<>();
}
@Override
public int getSectionCount() {
return logEntryList.size();
}
@Override
public int getItemCount(int section) {
return sectionExpanded.contains(section) ? logEntryList.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) {
suLogCursor.moveToPosition(logEntryList.get(section).get(0));
SuLogEntry entry = new SuLogEntry(suLogCursor);
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), logEntryList.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), logEntryList.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) {
int sqlPosition = logEntryList.get(section).get(position);
suLogCursor.moveToPosition(sqlPosition);
SuLogEntry entry = new SuLogEntry(suLogCursor);
holder.setExpanded(itemExpanded.contains(sqlPosition));
holder.itemView.setOnClickListener(view -> {
if (holder.isExpanded()) {
holder.collapse();
itemExpanded.remove(sqlPosition);
} else {
holder.expand();
itemExpanded.add(sqlPosition);
}
});
holder.appName.setText(entry.appName);
holder.action.setText(entry.action ? R.string.grant : R.string.deny);
holder.command.setText(entry.command);
holder.fromPid.setText(String.valueOf(entry.fromPid));
holder.toUid.setText(String.valueOf(entry.toUid));
holder.time.setText(entry.getTimeString());
}
public void notifyDBChanged() {
if (suLogCursor != null)
suLogCursor.close();
suLogCursor = suDB.getLogCursor();
logEntryList = suDB.getLogStructure();
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);
ButterKnife.bind(this, itemView);
}
}
static class LogViewHolder extends RecyclerView.ViewHolder implements ExpandableView {
@BindView(R.id.app_name) TextView appName;
@BindView(R.id.action) TextView action;
@BindView(R.id.time) TextView time;
@BindView(R.id.fromPid) TextView fromPid;
@BindView(R.id.toUid) TextView toUid;
@BindView(R.id.command) TextView command;
@BindView(R.id.expand_layout) ViewGroup expandLayout;
private Container container = new Container();
LogViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
container.expandLayout = expandLayout;
setupExpandable();
}
@Override
public Container getContainer() {
return container;
}
}
}

View File

@@ -1,41 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import java.util.ArrayList;
import java.util.List;
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,84 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
import com.topjohnwu.magisk.utils.WebService;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import dalvik.system.DexClassLoader;
public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
public static final File dexPath =
new File(MagiskManager.get().getFilesDir().getParent() + "/snet", "snet.apk");
private ISafetyNetHelper helper;
public CheckSafetyNet(Activity activity) {
super(activity);
}
private void dlSnet() throws Exception {
Shell.Sync.sh("rm -rf " + dexPath.getParent());
dexPath.getParentFile().mkdir();
HttpURLConnection conn = WebService.request(Const.Url.SNET_URL, null);
try (
OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath));
InputStream in = new BufferedInputStream(conn.getInputStream())) {
ShellUtils.pump(in, out);
} finally {
conn.disconnect();
}
}
private void dyload() throws Exception {
DexClassLoader loader = new DexClassLoader(dexPath.getPath(), dexPath.getParent(),
null, ISafetyNetHelper.class.getClassLoader());
Class<?> clazz = loader.loadClass("com.topjohnwu.snet.SafetyNetHelper");
helper = (ISafetyNetHelper) clazz.getConstructors()[0]
.newInstance(getActivity(), (ISafetyNetHelper.Callback)
code -> MagiskManager.get().safetyNetDone.publish(false, code));
if (helper.getVersion() != Const.SNET_VER) {
throw new Exception();
}
}
@Override
protected Exception doInBackground(Void... voids) {
try {
try {
dyload();
} catch (Exception e) {
// If dynamic load failed, try re-downloading and reload
dlSnet();
dyload();
}
} catch (Exception e) {
return e;
}
return null;
}
@Override
protected void onPostExecute(Exception e) {
if (e == null) {
helper.attest();
} else {
e.printStackTrace();
MagiskManager.get().safetyNetDone.publish(false, -1);
}
super.onPostExecute(e);
}
}

View File

@@ -1,70 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.ShowUI;
import com.topjohnwu.magisk.utils.WebService;
import org.json.JSONException;
import org.json.JSONObject;
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
private boolean showNotification;
public CheckUpdates() {
this(false);
}
public CheckUpdates(boolean b) {
showNotification = b;
}
@Override
protected Void doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
String jsonStr = "";
switch (mm.updateChannel) {
case Const.Value.STABLE_CHANNEL:
jsonStr = WebService.getString(Const.Url.STABLE_URL);
break;
case Const.Value.BETA_CHANNEL:
jsonStr = WebService.getString(Const.Url.BETA_URL);
break;
case Const.Value.CUSTOM_CHANNEL:
jsonStr = WebService.getString(mm.prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
break;
}
try {
JSONObject json = new JSONObject(jsonStr);
JSONObject magisk = json.getJSONObject("magisk");
mm.remoteMagiskVersionString = magisk.getString("version");
mm.remoteMagiskVersionCode = magisk.getInt("versionCode");
mm.magiskLink = magisk.getString("link");
mm.magiskNoteLink = magisk.getString("note");
JSONObject manager = json.getJSONObject("app");
mm.remoteManagerVersionString = manager.getString("version");
mm.remoteManagerVersionCode = manager.getInt("versionCode");
mm.managerLink = manager.getString("link");
mm.managerNoteLink = manager.getString("note");
JSONObject uninstaller = json.getJSONObject("uninstaller");
mm.uninstallerLink = uninstaller.getString("link");
} catch (JSONException ignored) {}
return null;
}
@Override
protected void onPostExecute(Void v) {
MagiskManager mm = MagiskManager.get();
if (showNotification) {
if (BuildConfig.VERSION_CODE < mm.remoteManagerVersionCode) {
ShowUI.managerUpdateNotification();
} else if (mm.magiskVersionCode < mm.remoteMagiskVersionCode) {
ShowUI.magiskUpdateNotification();
}
}
mm.updateCheckDone.publish();
super.onPostExecute(v);
}
}

View File

@@ -1,109 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.net.Uri;
import android.text.TextUtils;
import android.view.View;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
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 class FlashZip extends ParallelTask<Void, Void, Integer> {
private Uri mUri;
private File mCachedFile;
private List<String> console, logs;
public FlashZip(Activity context, Uri uri, List<String> console, List<String> logs) {
super(context);
mUri = uri;
this.console = console;
this.logs = logs;
mCachedFile = new File(context.getCacheDir(), "install.zip");
}
private boolean unzipAndCheck() throws Exception {
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", true);
return ShellUtils.fastCmdResult("grep -q '#MAGISK' " + new File(mCachedFile.getParentFile(), "updater-script"));
}
@Override
protected Integer doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
try {
console.add("- Copying zip to temp directory");
mCachedFile.delete();
try (
InputStream in = mm.getContentResolver().openInputStream(mUri);
OutputStream out = new BufferedOutputStream(new FileOutputStream(mCachedFile))
) {
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;
}
if (!unzipAndCheck()) return 0;
console.add("- Installing " + Utils.getNameFromUri(mm, mUri));
Shell.Sync.su(console, logs,
"cd " + mCachedFile.getParent(),
"BOOTMODE=true sh update-binary dummy 1 " + mCachedFile + " || echo 'Failed!'"
);
if (TextUtils.equals(console.get(console.size() - 1), "Failed!"))
return -1;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
console.add("- All done!");
return 1;
}
// -1 = error, manual install; 0 = invalid zip; 1 = success
@Override
protected void onPostExecute(Integer result) {
FlashActivity activity = (FlashActivity) getActivity();
Shell.Async.su(
"rm -rf " + mCachedFile.getParent(),
"rm -rf " + Const.TMP_FOLDER_PATH
);
switch (result) {
case -1:
console.add("! Installation failed");
SnackbarMaker.showUri(getActivity(), mUri);
break;
case 0:
console.add("! This zip is not a Magisk Module!");
break;
case 1:
// Success
new LoadModules().exec();
break;
}
activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE);
activity.buttonPanel.setVisibility(View.VISIBLE);
}
}

View File

@@ -1,95 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.widget.Toast;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.PatchAPK;
import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileOutputStream;
import java.io.FileNotFoundException;
import java.security.SecureRandom;
public class HideManager extends ParallelTask<Void, Void, Boolean> {
private ProgressDialog dialog;
public HideManager(Activity activity) {
super(activity);
}
private String genPackageName(String prefix, int length) {
StringBuilder builder = new StringBuilder(length);
builder.append(prefix);
length -= prefix.length();
SecureRandom random = new SecureRandom();
String base = "abcdefghijklmnopqrstuvwxyz";
String alpha = base + base.toUpperCase();
String full = alpha + "0123456789..........";
char next, prev = '\0';
for (int i = 0; i < length; ++i) {
if (prev == '.' || i == length - 1 || i == 0) {
next = alpha.charAt(random.nextInt(alpha.length()));
} else {
next = full.charAt(random.nextInt(full.length()));
}
builder.append(next);
prev = next;
}
return builder.toString();
}
@Override
protected void onPreExecute() {
dialog = ProgressDialog.show(getActivity(),
getActivity().getString(R.string.hide_manager_toast),
getActivity().getString(R.string.hide_manager_toast2));
}
@Override
protected Boolean doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
// Generate a new app with random package name
SuFile repack = new SuFile("/data/local/tmp/repack.apk");
String pkg = genPackageName("com.", Const.ORIG_PKG_NAME.length());
try {
if (!PatchAPK.patchPackageID(
mm.getPackageCodePath(),
new SuFileOutputStream(repack),
Const.ORIG_PKG_NAME, pkg))
return false;
} catch (FileNotFoundException e) {
return false;
}
// Install the application
if (!ShellUtils.fastCmdResult(Shell.getShell(), "pm install " + repack))
return false;
repack.delete();
mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
mm.dumpPrefs();
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);
return true;
}
@Override
protected void onPostExecute(Boolean b) {
dialog.dismiss();
if (!b) {
MagiskManager.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
}
super.onPostExecute(b);
}
}

View File

@@ -1,327 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.view.View;
import android.widget.Toast;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.TarEntry;
import com.topjohnwu.magisk.utils.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.io.SuFileInputStream;
import com.topjohnwu.utils.SignBoot;
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.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.List;
public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
private static final int PATCH_MODE = 0;
public static final int DIRECT_MODE = 1;
private static final int FIX_ENV_MODE = 2;
public static final int SECOND_SLOT_MODE = 3;
private Uri bootUri, mZip;
private List<String> console, logs;
private String mBoot;
private int mode;
private File installDir;
private ProgressDialog dialog;
private MagiskManager mm;
public InstallMagisk(Activity context, Uri zip) {
super(context);
mZip = zip;
mm = MagiskManager.get();
mode = FIX_ENV_MODE;
}
public InstallMagisk(Activity context, List<String> console, List<String> logs, Uri zip, int mode) {
this(context, zip);
this.console = console;
this.logs = logs;
this.mode = mode;
}
public InstallMagisk(FlashActivity context, List<String> console, List<String> logs, Uri zip, Uri boot) {
this(context, console, logs, zip, PATCH_MODE);
bootUri = boot;
}
@Override
protected void onPreExecute() {
if (mode == FIX_ENV_MODE) {
Activity a = getActivity();
dialog = ProgressDialog.show(a, a.getString(R.string.setup_title), a.getString(R.string.setup_msg));
console = new NOPList<>();
}
}
private void extractFiles(String arch) throws IOException {
console.add("- Extracting files");
try (InputStream in = mm.getContentResolver().openInputStream(mZip)) {
if (in == null) throw new FileNotFoundException();
BufferedInputStream buf = new BufferedInputStream(in);
buf.mark(Integer.MAX_VALUE);
ZipUtils.unzip(buf, installDir, arch + "/", true);
buf.reset();
ZipUtils.unzip(buf, installDir, "common/", true);
buf.reset();
ZipUtils.unzip(buf, installDir, "chromeos/", false);
buf.reset();
ZipUtils.unzip(buf, installDir, "META-INF/com/google/android/update-binary", true);
buf.close();
} catch (FileNotFoundException e) {
console.add("! Invalid Uri");
throw e;
} catch (IOException e) {
console.add("! Cannot unzip zip");
throw e;
}
Shell.Sync.sh(Utils.fmt("chmod -R 755 %s/*; %s/magiskinit -x magisk %s/magisk",
installDir, installDir, installDir));
}
private boolean dumpBoot() {
console.add("- Copying image locally");
// Copy boot image to local
try (InputStream in = mm.getContentResolver().openInputStream(bootUri);
OutputStream out = new FileOutputStream(mBoot)
) {
if (in == null)
throw new FileNotFoundException();
InputStream src;
if (Utils.getNameFromUri(mm, 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;
}
private File patchBoot() throws IOException {
boolean isSigned;
try (InputStream in = new SuFileInputStream(mBoot)) {
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");
throw e;
}
// Patch boot image
Shell.Sync.sh(console, logs,
"cd " + installDir,
Utils.fmt("KEEPFORCEENCRYPT=%b KEEPVERITY=%b sh update-binary indep " +
"boot_patch.sh %s || echo 'Failed!'",
mm.keepEnc, mm.keepVerity, mBoot));
if (TextUtils.equals(console.get(console.size() - 1), "Failed!"))
return null;
Shell.Sync.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);
}
Shell.Sync.su("mv -f " + signed + " " + patched);
}
return patched;
}
private void outputBoot(File patched) throws IOException {
switch (mode) {
case PATCH_MODE:
File dest = new File(Const.EXTERNAL_PATH, "patched_boot" + mm.bootFormat);
dest.getParentFile().mkdirs();
OutputStream out;
switch (mm.bootFormat) {
case ".img.tar":
out = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
((TarOutputStream) out).putNextEntry(new TarEntry(patched, "boot.img"));
break;
default:
case ".img":
out = new BufferedOutputStream(new FileOutputStream(dest));
break;
}
try (InputStream in = new SuFileInputStream(patched)) {
ShellUtils.pump(in, out);
out.close();
}
Shell.Sync.su("rm -f " + patched);
console.add("");
console.add("****************************");
console.add(" Patched image is placed in ");
console.add(" " + dest + " ");
console.add("****************************");
break;
case SECOND_SLOT_MODE:
case DIRECT_MODE:
Shell.Sync.sh(console, logs,
Utils.fmt("direct_install %s %s %s", patched, mBoot, installDir));
if (!mm.keepVerity)
Shell.Sync.sh(console, logs, "find_dtbo_image", "patch_dtbo_image");
break;
}
}
@Override
protected Boolean doInBackground(Void... voids) {
if (mode == FIX_ENV_MODE) {
installDir = new File("/data/adb/magisk");
Shell.Sync.sh("rm -rf /data/adb/magisk/*");
} else {
installDir = new File(
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?
mm.createDeviceProtectedStorageContext() : mm)
.getFilesDir().getParent()
, "install");
Shell.Sync.sh("rm -rf " + installDir);
installDir.mkdirs();
}
switch (mode) {
case PATCH_MODE:
mBoot = new File(installDir, "boot.img").getAbsolutePath();
if (!dumpBoot())
return false;
break;
case DIRECT_MODE:
console.add("- Detecting target image");
mBoot = ShellUtils.fastCmd("find_boot_image", "echo \"$BOOTIMAGE\"");
break;
case SECOND_SLOT_MODE:
console.add("- Detecting target image");
char slot[] = ShellUtils.fastCmd("echo $SLOT").toCharArray();
if (slot[1] == 'a') slot[1] = 'b';
else slot[1] = 'a';
mBoot = ShellUtils.fastCmd("SLOT=" + String.valueOf(slot),
"find_boot_image", "echo \"$BOOTIMAGE\"");
Shell.Async.su("mount_partitions");
break;
case FIX_ENV_MODE:
mBoot = "";
break;
}
if (mBoot == null) {
console.add("! Unable to detect target image");
return false;
}
console.add("- Target image: " + mBoot);
List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS);
String arch;
if (mm.remoteMagiskVersionCode >= Const.MAGISK_VER.SEPOL_REFACTOR) {
// 32-bit only
if (abis.contains("x86")) arch = "x86";
else arch = "arm";
} else {
if (abis.contains("x86_64")) arch = "x64";
else if (abis.contains("arm64-v8a")) arch = "arm64";
else if (abis.contains("x86")) arch = "x86";
else arch = "arm";
}
console.add("- Device platform: " + Build.SUPPORTED_ABIS[0]);
try {
extractFiles(arch);
if (mode == FIX_ENV_MODE) {
Shell.Sync.sh("fix_env");
} else {
File patched = patchBoot();
if (patched == null)
return false;
outputBoot(patched);
console.add("- All done!");
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
protected void onPostExecute(Boolean result) {
if (mode == FIX_ENV_MODE) {
dialog.dismiss();
MagiskManager.toast(result ? R.string.setup_done : R.string.setup_fail, Toast.LENGTH_LONG);
} else {
// Running in FlashActivity
FlashActivity activity = (FlashActivity) getActivity();
if (!result) {
Shell.Async.sh("rm -rf " + installDir);
console.add("! Installation failed");
activity.reboot.setVisibility(View.GONE);
}
activity.buttonPanel.setVisibility(View.VISIBLE);
}
}
private static class NOPList<E> extends AbstractList<E> {
@Override
public E get(int index) {
return null;
}
@Override
public int size() {
return 0;
}
@Override
public void add(int index, E element) {}
}
}

View File

@@ -1,36 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.container.ValueSortedMap;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.superuser.Shell;
import java.util.List;
public class LoadModules extends ParallelTask<Void, Void, Void> {
private List<String> getModList() {
String command = "ls -d " + Const.MAGISK_PATH + "/* | grep -v lost+found";
return Shell.Sync.su(command);
}
@Override
protected Void doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
mm.moduleMap = new ValueSortedMap<>();
for (String path : getModList()) {
Module module = new Module(path);
mm.moduleMap.put(module.getId(), module);
}
return null;
}
@Override
protected void onPostExecute(Void v) {
MagiskManager.get().moduleLoadDone.publish();
super.onPostExecute(v);
}
}

View File

@@ -1,86 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.support.v7.app.AlertDialog;
import android.webkit.WebView;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.WebService;
import com.topjohnwu.superuser.ShellUtils;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class MarkDownWindow extends ParallelTask<Void, Void, String> {
private String mTitle;
private String mUrl;
private InputStream is;
public MarkDownWindow(Activity context, String title, String url) {
super(context);
mTitle = title;
mUrl = url;
}
public MarkDownWindow(Activity context, String title, InputStream in) {
super(context);
mTitle = title;
is = in;
}
@Override
protected String doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
String md;
if (mUrl != null) {
md = WebService.getString(mUrl);
} else {
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
ShellUtils.pump(is, out);
md = out.toString();
is.close();
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
String css;
try (
InputStream in = mm.getResources().openRawResource(
mm.isDarkTheme ? R.raw.dark : R.raw.light);
ByteArrayOutputStream out = new ByteArrayOutputStream()
) {
ShellUtils.pump(in, out);
css = out.toString();
in.close();
} catch (IOException e) {
e.printStackTrace();
return "";
}
Parser parser = Parser.builder().build();
HtmlRenderer renderer = HtmlRenderer.builder().build();
Node doc = parser.parse(md);
return String.format("<style>%s</style>%s", css, renderer.render(doc));
}
@Override
protected void onPostExecute(String html) {
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setTitle(mTitle);
WebView wv = new WebView(getActivity());
wv.loadDataWithBaseURL("fake://", html, "text/html", "UTF-8", null);
alert.setView(wv);
alert.setNegativeButton(R.string.close, (dialog, id) -> dialog.dismiss());
alert.show();
}
}

View File

@@ -1,39 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.os.AsyncTask;
import java.lang.ref.WeakReference;
public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
private WeakReference<Activity> weakActivity;
private Runnable callback = null;
public ParallelTask() {}
public ParallelTask(Activity context) {
weakActivity = new WeakReference<>(context);
}
protected Activity getActivity() {
return weakActivity.get();
}
@SuppressWarnings("unchecked")
public ParallelTask<Params, Progress, Result> exec(Params... params) {
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
return this;
}
@Override
protected void onPostExecute(Result result) {
if (callback != null) callback.run();
}
public ParallelTask<Params, Progress, Result> setCallBack(Runnable next) {
callback = next;
return this;
}
}

View File

@@ -1,199 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.Manifest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.widget.Toast;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.WebService;
import com.topjohnwu.magisk.utils.ZipUtils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
private ProgressDialog progressDialog;
private boolean mInstall;
private String mLink;
private File mFile;
private int progress = 0, total = -1;
private Handler mHandler;
public ProcessRepoZip(Activity context, String link, String filename, boolean install) {
super(context);
mLink = link;
mFile = new File(Const.EXTERNAL_PATH, filename);
mInstall = install;
mHandler = new Handler();
}
private void removeTopFolder(File input, File output) throws IOException {
JarEntry entry;
try (
JarInputStream in = new JarInputStream(new BufferedInputStream(new FileInputStream(input)));
JarOutputStream out = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(output)))
) {
String path;
while ((entry = in.getNextJarEntry()) != null) {
// Remove the top directory from the path
path = entry.getName().substring(entry.getName().indexOf("/") + 1);
// If it's the top folder, ignore it
if (path.isEmpty()) {
continue;
}
// Don't include placeholder
if (path.equals("system/placeholder")) {
continue;
}
out.putNextEntry(new JarEntry(path));
ShellUtils.pump(in, out);
}
}
}
@Override
protected void onPreExecute() {
Activity activity = getActivity();
mFile.getParentFile().mkdirs();
progressDialog = ProgressDialog.show(activity, activity.getString(R.string.zip_download_title), activity.getString(R.string.zip_download_msg, 0));
}
@Override
protected Boolean doInBackground(Void... params) {
Activity activity = getActivity();
if (activity == null) return null;
try {
// Request zip from Internet
HttpURLConnection conn;
do {
conn = WebService.request(mLink, null);
total = conn.getContentLength();
if (total < 0)
conn.disconnect();
else
break;
} while (true);
// Temp files
File temp1 = new File(activity.getCacheDir(), "1.zip");
File temp2 = new File(temp1.getParentFile(), "2.zip");
temp1.getParentFile().mkdir();
// First download the zip, Web -> temp1
try (
InputStream in = new BufferedInputStream(new ProgressInputStream(conn.getInputStream()));
OutputStream out = new BufferedOutputStream(new FileOutputStream(temp1))
) {
ShellUtils.pump(in, out);
in.close();
}
conn.disconnect();
mHandler.post(() -> {
progressDialog.setTitle(R.string.zip_process_title);
progressDialog.setMessage(getActivity().getString(R.string.zip_process_msg));
});
// First remove top folder in Github source zip, temp1 -> temp2
removeTopFolder(temp1, temp2);
// Then sign the zip
ZipUtils.signZip(temp2, mFile);
// Delete temp files
temp1.delete();
temp2.delete();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
@Override
protected void onPostExecute(Boolean result) {
Activity activity = getActivity();
if (activity == null) return;
progressDialog.dismiss();
if (result) {
Uri uri = Uri.fromFile(mFile);
if (Shell.rootAccess() && mInstall) {
Intent intent = new Intent(activity, FlashActivity.class);
intent.setData(uri).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
activity.startActivity(intent);
} else {
SnackbarMaker.showUri(activity, uri);
}
} else {
MagiskManager.toast(R.string.process_error, Toast.LENGTH_LONG);
}
super.onPostExecute(result);
}
@Override
public ParallelTask<Void, Object, Boolean> exec(Void... voids) {
com.topjohnwu.magisk.components.Activity.runWithPermission(
getActivity(), new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
() -> super.exec(voids));
return this;
}
private class ProgressInputStream extends FilterInputStream {
ProgressInputStream(InputStream in) {
super(in);
}
private void updateDlProgress(int step) {
progress += step;
progressDialog.setMessage(getActivity().getString(R.string.zip_download_msg, (int) (100 * (double) progress / total + 0.5)));
}
@Override
public synchronized int read() throws IOException {
int b = super.read();
if (b > 0) {
mHandler.post(() -> updateDlProgress(1));
}
return b;
}
@Override
public int read(@NonNull byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public synchronized int read(@NonNull byte[] b, int off, int len) throws IOException {
int read = super.read(b, off, len);
if (read > 0) {
mHandler.post(() -> updateDlProgress(read));
}
return read;
}
}
}

View File

@@ -1,39 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.widget.Toast;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.superuser.ShellUtils;
public class RestoreImages extends ParallelTask<Void, Void, Boolean> {
private ProgressDialog dialog;
public RestoreImages(Activity activity) {
super(activity);
}
@Override
protected void onPreExecute() {
Activity a = getActivity();
dialog = ProgressDialog.show(a, a.getString(R.string.restore_img), a.getString(R.string.restore_img_msg));
}
@Override
protected Boolean doInBackground(Void... voids) {
return ShellUtils.fastCmdResult("restore_imgs");
}
@Override
protected void onPostExecute(Boolean result) {
dialog.cancel();
if (result) {
MagiskManager.toast(R.string.restore_done, Toast.LENGTH_SHORT);
} else {
MagiskManager.toast(R.string.restore_fail, Toast.LENGTH_LONG);
}
}
}

View File

@@ -1,210 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.database.Cursor;
import android.os.AsyncTask;
import android.text.TextUtils;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.ReposFragment;
import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.WebService;
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.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
public class UpdateRepos extends ParallelTask<Void, Void, Void> {
private static final int CHECK_ETAG = 0;
private static final int LOAD_NEXT = 1;
private static final int LOAD_PREV = 2;
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
private MagiskManager mm;
private List<String> etags, newEtags = new LinkedList<>();
private Set<String> cached;
private boolean forceUpdate;
private AtomicInteger taskCount = new AtomicInteger(0);
final private Object allDone = new Object();
public UpdateRepos(boolean force) {
mm = MagiskManager.get();
mm.repoLoadDone.reset();
forceUpdate = force;
}
private void queueTask(Runnable task) {
// Thread pool's queue has an upper bound, batch it with 64 tasks
while (taskCount.get() >= 64) {
waitTasks();
}
taskCount.incrementAndGet();
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
task.run();
if (taskCount.decrementAndGet() == 0) {
synchronized (allDone) {
allDone.notify();
}
}
});
}
private void waitTasks() {
if (taskCount.get() == 0)
return;
synchronized (allDone) {
try {
allDone.wait();
} catch (InterruptedException e) {
// Wait again
waitTasks();
}
}
}
private boolean loadJSON(String jsonString) throws JSONException, ParseException {
JSONArray jsonArray = new JSONArray(jsonString);
// Empty page, halt
if (jsonArray.length() == 0)
return false;
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject rawRepo = jsonArray.getJSONObject(i);
String id = rawRepo.getString("description");
String name = rawRepo.getString("name");
Date date = dateFormat.parse(rawRepo.getString("pushed_at"));
Set<String> set = Collections.synchronizedSet(cached);
queueTask(() -> {
Repo repo = mm.repoDB.getRepo(id);
try {
if (repo == null)
repo = new Repo(name);
else
set.remove(id);
repo.update(date);
mm.repoDB.addRepo(repo);
publishProgress();
} catch (Repo.IllegalRepoException e) {
Logger.debug(e.getMessage());
mm.repoDB.removeRepo(id);
}
});
}
return true;
}
private boolean loadPage(int page, int mode) {
Map<String, String> header = new HashMap<>();
if (mode == CHECK_ETAG && page < etags.size())
header.put(Const.Key.IF_NONE_MATCH, etags.get(page));
String url = Utils.fmt(Const.Url.REPO_URL, page + 1);
try {
HttpURLConnection conn = WebService.request(url, header);
if (conn.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
// Current page is not updated, check the next page
return loadPage(page + 1, CHECK_ETAG);
}
if (!loadJSON(WebService.getString(conn)))
return mode != CHECK_ETAG;
} catch (Exception e) {
e.printStackTrace();
return false;
}
/* If one page is updated, we force update all pages */
// Update ETAG
String etag = header.get(Const.Key.ETAG_KEY);
etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1);
if (mode == LOAD_PREV) {
// We are loading a previous page, push the new tag to the front
newEtags.add(0, etag);
} else {
newEtags.add(etag);
}
String links = header.get(Const.Key.LINK_KEY);
if (links != null) {
for (String s : links.split(", ")) {
if (mode != LOAD_PREV && s.contains("next")) {
// Force load all next pages
loadPage(page + 1, LOAD_NEXT);
}
if (mode != LOAD_NEXT && s.contains("prev")) {
// Back propagation
loadPage(page - 1, LOAD_PREV);
}
}
}
return true;
}
@Override
protected void onProgressUpdate(Void... values) {
if (ReposFragment.adapter != null)
ReposFragment.adapter.notifyDBChanged();
}
@Override
protected void onPreExecute() {
mm.repoLoadDone.setPending();
}
@Override
protected Void doInBackground(Void... voids) {
etags = Arrays.asList(mm.prefs.getString(Const.Key.ETAG_KEY, "").split(","));
cached = mm.repoDB.getRepoIDSet();
if (loadPage(0, CHECK_ETAG)) {
waitTasks();
// The leftover cached means they are removed from online repo
mm.repoDB.removeRepo(cached);
// Update ETag
mm.prefs.edit().putString(Const.Key.ETAG_KEY, TextUtils.join(",", newEtags)).apply();
} else if (forceUpdate) {
Cursor c = mm.repoDB.getRawCursor();
while (c.moveToNext()) {
Repo repo = new Repo(c);
queueTask(() -> {
try {
repo.update();
mm.repoDB.addRepo(repo);
} catch (Repo.IllegalRepoException e) {
Logger.debug(e.getMessage());
mm.repoDB.removeRepo(repo);
}
});
}
waitTasks();
}
return null;
}
@Override
protected void onPostExecute(Void v) {
mm.repoLoadDone.publish();
super.onPostExecute(v);
}
}

View File

@@ -1,89 +0,0 @@
/*
* Copyright 2016 dvdandroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.topjohnwu.magisk.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
/**
* @author dvdandroid
*/
public class AboutCardRow extends LinearLayout {
private final String title;
private final Drawable icon;
private final TextView mTitle;
private final TextView mSummary;
private final ImageView mIcon;
private final View mView;
public AboutCardRow(Context context) {
this(context, null);
}
public AboutCardRow(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AboutCardRow(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
LayoutInflater.from(context).inflate(R.layout.info_item_row, this);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AboutCardRow, 0, 0);
try {
title = a.getString(R.styleable.AboutCardRow_text);
icon = a.getDrawable(R.styleable.AboutCardRow_icon);
} finally {
a.recycle();
}
mView = findViewById(R.id.container);
mTitle = (TextView) findViewById(android.R.id.title);
mSummary = (TextView) findViewById(android.R.id.summary);
mIcon = (ImageView) findViewById(android.R.id.icon);
mTitle.setText(title);
mIcon.setImageDrawable(icon);
}
@Override
public void setOnClickListener(OnClickListener l) {
super.setOnClickListener(l);
mView.setOnClickListener(l);
}
public void setSummary(String s) {
mSummary.setText(s);
}
public void removeSummary() {
mSummary.setVisibility(GONE);
}
}

View File

@@ -1,153 +0,0 @@
package com.topjohnwu.magisk.components;
import android.app.Activity;
import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.annotation.StyleRes;
import android.support.v7.app.AlertDialog;
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 butterknife.BindView;
import butterknife.ButterKnife;
public class AlertDialogBuilder extends AlertDialog.Builder {
@BindView(R.id.button_panel) LinearLayout buttons;
@BindView(R.id.message_panel) LinearLayout messagePanel;
@BindView(R.id.negative) Button negative;
@BindView(R.id.positive) Button positive;
@BindView(R.id.neutral) Button neutral;
@BindView(R.id.message) TextView messageView;
private DialogInterface.OnClickListener positiveListener;
private DialogInterface.OnClickListener negativeListener;
private DialogInterface.OnClickListener neutralListener;
private AlertDialog dialog;
public AlertDialogBuilder(@NonNull Activity context) {
super(context);
setup();
}
public AlertDialogBuilder(@NonNull Activity context, @StyleRes int themeResId) {
super(context, themeResId);
setup();
}
private void setup() {
View v = LayoutInflater.from(getContext()).inflate(R.layout.alert_dialog, null);
ButterKnife.bind(this, v);
super.setView(v);
negative.setVisibility(View.GONE);
positive.setVisibility(View.GONE);
neutral.setVisibility(View.GONE);
buttons.setVisibility(View.GONE);
messagePanel.setVisibility(View.GONE);
}
@Override
public AlertDialog.Builder setTitle(int titleId) {
return super.setTitle(titleId);
}
@Override
public AlertDialog.Builder setView(int layoutResId) { return this; }
@Override
public AlertDialog.Builder setView(View view) { return this; }
@Override
public AlertDialog.Builder setMessage(@Nullable CharSequence message) {
messageView.setText(message);
messagePanel.setVisibility(View.VISIBLE);
return this;
}
@Override
public AlertDialog.Builder setMessage(@StringRes int messageId) {
return setMessage(getContext().getString(messageId));
}
@Override
public AlertDialog.Builder setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) {
buttons.setVisibility(View.VISIBLE);
positive.setVisibility(View.VISIBLE);
positive.setText(text);
positiveListener = listener;
positive.setOnClickListener((v) -> {
if (positiveListener != null) {
positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
}
dialog.dismiss();
});
return this;
}
@Override
public AlertDialog.Builder setPositiveButton(@StringRes int textId, DialogInterface.OnClickListener listener) {
return setPositiveButton(getContext().getString(textId), listener);
}
@Override
public AlertDialog.Builder setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) {
buttons.setVisibility(View.VISIBLE);
negative.setVisibility(View.VISIBLE);
negative.setText(text);
negativeListener = listener;
negative.setOnClickListener((v) -> {
if (negativeListener != null) {
negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
}
dialog.dismiss();
});
return this;
}
@Override
public AlertDialog.Builder setNegativeButton(@StringRes int textId, DialogInterface.OnClickListener listener) {
return setNegativeButton(getContext().getString(textId), listener);
}
@Override
public AlertDialog.Builder setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) {
buttons.setVisibility(View.VISIBLE);
neutral.setVisibility(View.VISIBLE);
neutral.setText(text);
neutralListener = listener;
neutral.setOnClickListener((v) -> {
if (neutralListener != null) {
neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL);
}
dialog.dismiss();
});
return this;
}
@Override
public AlertDialog.Builder 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;
}
}

View File

@@ -1,84 +0,0 @@
package com.topjohnwu.magisk.components;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
public interface ExpandableView {
class Container {
public ViewGroup expandLayout;
ValueAnimator expandAnimator, collapseAnimator;
boolean mExpanded = false;
int expandHeight = 0;
}
// Provide state info
Container getContainer();
default void setupExpandable() {
Container container = getContainer();
container.expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (container.expandHeight == 0) {
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
container.expandLayout.measure(widthSpec, heightSpec);
container.expandHeight = container.expandLayout.getMeasuredHeight();
}
container.expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
container.expandLayout.setVisibility(View.GONE);
container.expandAnimator = slideAnimator(0, container.expandHeight);
container.collapseAnimator = slideAnimator(container.expandHeight, 0);
return true;
}
});
}
default boolean isExpanded() {
return getContainer().mExpanded;
}
default void setExpanded(boolean expanded) {
Container container = getContainer();
container.mExpanded = expanded;
ViewGroup.LayoutParams layoutParams = container.expandLayout.getLayoutParams();
layoutParams.height = expanded ? container.expandHeight : 0;
container.expandLayout.setLayoutParams(layoutParams);
container.expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
}
default void expand() {
Container container = getContainer();
if (container.mExpanded) return;
container.expandLayout.setVisibility(View.VISIBLE);
container.expandAnimator.start();
container.mExpanded = true;
}
default void collapse() {
Container container = getContainer();
if (!container.mExpanded) return;
container.collapseAnimator.start();
container.mExpanded = false;
}
default ValueAnimator slideAnimator(int start, int end) {
Container container = getContainer();
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = container.expandLayout.getLayoutParams();
layoutParams.height = value;
container.expandLayout.setLayoutParams(layoutParams);
});
return animator;
}
}

View File

@@ -1,108 +0,0 @@
package com.topjohnwu.magisk.components;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.Keep;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.support.v7.app.AppCompatActivity;
import android.view.WindowManager;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Topic;
public abstract class FlavorActivity extends AppCompatActivity {
private AssetManager swappedAssetManager = null;
private Resources swappedResources = null;
private Resources.Theme backupTheme = null;
@StyleRes
public int getDarkTheme() {
return -1;
}
public MagiskManager getMagiskManager() {
return (MagiskManager) super.getApplication();
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (this instanceof Topic.Subscriber) {
((Topic.Subscriber) this).subscribeTopics();
}
if (getMagiskManager().isDarkTheme && getDarkTheme() != -1) {
setTheme(getDarkTheme());
}
}
@Override
protected void onDestroy() {
if (this instanceof Topic.Subscriber) {
((Topic.Subscriber) this).unsubscribeTopics();
}
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);
}
}
@Override
public Resources.Theme getTheme() {
return backupTheme == null ? super.getTheme() : backupTheme;
}
@Override
public AssetManager getAssets() {
return swappedAssetManager == null ? super.getAssets() : swappedAssetManager;
}
private AssetManager getAssets(String apk) {
try {
AssetManager asset = AssetManager.class.newInstance();
AssetManager.class.getMethod("addAssetPath", String.class).invoke(asset, apk);
return asset;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public Resources getResources() {
return swappedResources == null ? super.getResources() : swappedResources;
}
@Keep
public void swapResources(String dexPath) {
AssetManager asset = getAssets(dexPath);
if (asset != null) {
backupTheme = super.getTheme();
Resources res = super.getResources();
swappedResources = new Resources(asset, res.getDisplayMetrics(), res.getConfiguration());
swappedAssetManager = asset;
}
}
@Keep
public void restoreResources() {
swappedAssetManager = null;
swappedResources = null;
backupTheme = null;
}
}

View File

@@ -1,43 +0,0 @@
package com.topjohnwu.magisk.components;
import android.content.Intent;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
public class Fragment extends android.support.v4.app.Fragment {
public MagiskManager getApplication() {
return Utils.getMagiskManager(getActivity());
}
@Override
public void onResume() {
super.onResume();
if (this instanceof Topic.Subscriber) {
((Topic.Subscriber) this).subscribeTopics();
}
}
@Override
public void onPause() {
if (this instanceof Topic.Subscriber) {
((Topic.Subscriber) this).unsubscribeTopics();
}
super.onPause();
}
@Override
public void startActivityForResult(Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, this::onActivityResult);
}
public void startActivityForResult(Intent intent, int requestCode, Activity.ActivityResultListener listener) {
((Activity) getActivity()).startActivityForResult(intent, requestCode, listener);
}
public void runWithPermission(String[] permissions, Runnable callback) {
Activity.runWithPermission(getActivity(), permissions, callback);
}
}

View File

@@ -1,92 +0,0 @@
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.database.Cursor;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.WebService;
import java.text.DateFormat;
import java.util.Date;
public class Repo extends BaseModule {
private String repoName;
private Date mLastUpdate;
public Repo(String name) {
repoName = name;
}
public Repo(Cursor c) {
super(c);
repoName = c.getString(c.getColumnIndex("repo_name"));
mLastUpdate = new Date(c.getLong(c.getColumnIndex("last_update")));
}
public void update() throws IllegalRepoException {
String props[] = Utils.dos2unix(WebService.getString(getManifestUrl())).split("\\n");
try {
parseProps(props);
} catch (NumberFormatException e) {
throw new IllegalRepoException("Repo [" + repoName + "] parse error: " + e.getMessage());
}
if (getId() == null) {
throw new IllegalRepoException("Repo [" + repoName + "] does not contain id");
}
if (getVersionCode() < 0) {
throw new IllegalRepoException("Repo [" + repoName + "] does not contain versionCode");
}
if (getMinMagiskVersion() < Const.MIN_MODULE_VER()) {
Logger.debug("Repo [" + repoName + "] is outdated");
}
}
public void update(Date lastUpdate) throws IllegalRepoException {
mLastUpdate = lastUpdate;
update();
}
@Override
public ContentValues getContentValues() {
ContentValues values = super.getContentValues();
values.put("repo_name", repoName);
values.put("last_update", mLastUpdate.getTime());
return values;
}
public String getRepoName() {
return repoName;
}
public String getZipUrl() {
return String.format(Const.Url.ZIP_URL, repoName);
}
public String getManifestUrl() {
return String.format(Const.Url.FILE_URL, repoName, "module.prop");
}
public String getDetailUrl() {
return String.format(Const.Url.FILE_URL, repoName, "README.md");
}
public String getLastUpdateString() {
return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM,
MagiskManager.locale).format(mLastUpdate);
}
public Date getLastUpdate() {
return mLastUpdate;
}
public class IllegalRepoException extends Exception {
IllegalRepoException(String message) {
super(message);
}
}
}

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,301 +0,0 @@
package com.topjohnwu.magisk.database;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Process;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.widget.Toast;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.container.SuLogEntry;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.io.SuFile;
import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class MagiskDatabaseHelper {
private static final int DATABASE_VER = 5;
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;
private SQLiteDatabase db;
@NonNull
public static MagiskDatabaseHelper getInstance(MagiskManager mm) {
try {
return new MagiskDatabaseHelper(mm);
} catch (Exception e) {
// Let's cleanup everything and try again
Shell.Sync.su("db_clean '*'");
return new MagiskDatabaseHelper(mm);
}
}
private MagiskDatabaseHelper(MagiskManager mm) {
pm = mm.getPackageManager();
db = openDatabase(mm);
db.disableWriteAheadLogging();
int version = db.getVersion();
if (version < DATABASE_VER) {
onUpgrade(db, version);
} else if (version > DATABASE_VER) {
onDowngrade(db);
}
db.setVersion(DATABASE_VER);
clearOutdated();
}
private SQLiteDatabase openDatabase(MagiskManager mm) {
final File DB_FILE = new File(Utils.fmt("/sbin/.core/db-%d/magisk.db", Const.USER_ID));
Context de = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
? mm.createDeviceProtectedStorageContext() : mm;
if (!DB_FILE.canWrite()) {
if (!Shell.rootAccess()) {
// We don't want the app to crash, create a db and return
return mm.openOrCreateDatabase("su.db", Context.MODE_PRIVATE, null);
}
mm.loadMagiskInfo();
// Cleanup
Shell.Sync.su("db_clean " + Const.USER_ID);
if (mm.magiskVersionCode < Const.MAGISK_VER.FBE_AWARE) {
// Super old legacy mode
return mm.openOrCreateDatabase("su.db", Context.MODE_PRIVATE, null);
} else if (mm.magiskVersionCode < Const.MAGISK_VER.HIDDEN_PATH) {
// Legacy mode with FBE aware
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
de.moveDatabaseFrom(mm, "su.db");
}
return de.openOrCreateDatabase("su.db", Context.MODE_PRIVATE, null);
} else {
// Global database
final SuFile GLOBAL_DB = new SuFile("/data/adb/magisk.db");
mm.deleteDatabase("su.db");
de.deleteDatabase("su.db");
if (mm.magiskVersionCode < Const.MAGISK_VER.SEPOL_REFACTOR) {
// We need some additional policies on old versions
Shell.Sync.su("db_sepatch");
}
if (!GLOBAL_DB.exists()) {
Shell.Sync.su("db_init");
SQLiteDatabase.openOrCreateDatabase(GLOBAL_DB, null).close();
Shell.Sync.su("db_restore");
}
}
Shell.Sync.su("db_setup " + Process.myUid());
}
// Not using legacy mode, open the mounted global DB
return SQLiteDatabase.openOrCreateDatabase(DB_FILE, null);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion) {
if (oldVersion == 0) {
createTables(db);
oldVersion = 3;
}
if (oldVersion == 1) {
// We're dropping column app_name, rename and re-construct table
db.execSQL(Utils.fmt("ALTER TABLE %s RENAME TO %s_old", POLICY_TABLE));
// Create the new tables
createTables(db);
// Migrate old data to new tables
db.execSQL(Utils.fmt("INSERT INTO %s SELECT " +
"uid, package_name, policy, until, logging, notification FROM %s_old",
POLICY_TABLE, POLICY_TABLE));
db.execSQL(Utils.fmt("DROP TABLE %s_old", POLICY_TABLE));
MagiskManager.get().deleteDatabase("sulog.db");
++oldVersion;
}
if (oldVersion == 2) {
db.execSQL(Utils.fmt("UPDATE %s SET time=time*1000", LOG_TABLE));
++oldVersion;
}
if (oldVersion == 3) {
db.execSQL(Utils.fmt("CREATE TABLE IF NOT EXISTS %s (key TEXT, value TEXT, PRIMARY KEY(key))", STRINGS_TABLE));
++oldVersion;
}
if (oldVersion == 4) {
db.execSQL(Utils.fmt("UPDATE %s SET uid=uid%%100000", POLICY_TABLE));
++oldVersion;
}
}
// Remove everything, we do not support downgrade
public void onDowngrade(SQLiteDatabase db) {
MagiskManager.toast(R.string.su_db_corrupt, Toast.LENGTH_LONG);
db.execSQL("DROP TABLE IF EXISTS " + POLICY_TABLE);
db.execSQL("DROP TABLE IF EXISTS " + LOG_TABLE);
db.execSQL("DROP TABLE IF EXISTS " + SETTINGS_TABLE);
db.execSQL("DROP TABLE IF EXISTS " + STRINGS_TABLE);
onUpgrade(db, 0);
}
private void createTables(SQLiteDatabase db) {
// Policies
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + POLICY_TABLE + " " +
"(uid INT, package_name TEXT, policy INT, " +
"until INT, logging INT, notification INT, " +
"PRIMARY KEY(uid))");
// Logs
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + LOG_TABLE + " " +
"(from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " +
"to_uid INT, action INT, time INT, command TEXT)");
// Settings
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + SETTINGS_TABLE + " " +
"(key TEXT, value INT, PRIMARY KEY(key))");
}
public void clearOutdated() {
// Clear outdated policies
db.delete(POLICY_TABLE, Utils.fmt("until > 0 AND until < %d", System.currentTimeMillis() / 1000), null);
// Clear outdated logs
db.delete(LOG_TABLE, Utils.fmt("time < %d", System.currentTimeMillis() - MagiskManager.get().suLogTimeout * 86400000), null);
}
public void deletePolicy(Policy policy) {
deletePolicy(policy.uid);
}
public void deletePolicy(String pkg) {
db.delete(POLICY_TABLE, "package_name=?", new String[] { pkg });
}
public void deletePolicy(int uid) {
db.delete(POLICY_TABLE, Utils.fmt("uid=%d", uid), null);
}
public Policy getPolicy(int uid) {
Policy policy = null;
try (Cursor c = db.query(POLICY_TABLE, null, Utils.fmt("uid=%d", uid), null, null, null, null)) {
if (c.moveToNext()) {
policy = new Policy(c, pm);
}
} catch (PackageManager.NameNotFoundException e) {
deletePolicy(uid);
return null;
}
return policy;
}
public void addPolicy(Policy policy) {
db.replace(POLICY_TABLE, null, policy.getContentValues());
}
public void updatePolicy(Policy policy) {
db.update(POLICY_TABLE, policy.getContentValues(), Utils.fmt("uid=%d", policy.uid), null);
}
public List<Policy> getPolicyList(PackageManager pm) {
try (Cursor c = db.query(POLICY_TABLE, null, Utils.fmt("uid/100000=%d", Const.USER_ID),
null, null, null, null)) {
List<Policy> ret = new ArrayList<>(c.getCount());
while (c.moveToNext()) {
try {
Policy policy = new Policy(c, pm);
ret.add(policy);
} catch (PackageManager.NameNotFoundException e) {
// The app no longer exist, remove from DB
deletePolicy(c.getInt(c.getColumnIndex("uid")));
}
}
Collections.sort(ret);
return ret;
}
}
public List<List<Integer>> getLogStructure() {
try (Cursor c = db.query(LOG_TABLE, new String[] { "time" }, Utils.fmt("from_uid/100000=%d", Const.USER_ID),
null, null, null, "time DESC")) {
List<List<Integer>> ret = new ArrayList<>();
List<Integer> list = null;
String dateString = null, newString;
while (c.moveToNext()) {
Date date = new Date(c.getLong(c.getColumnIndex("time")));
newString = DateFormat.getDateInstance(DateFormat.MEDIUM, MagiskManager.locale).format(date);
if (!TextUtils.equals(dateString, newString)) {
dateString = newString;
list = new ArrayList<>();
ret.add(list);
}
list.add(c.getPosition());
}
return ret;
}
}
public Cursor getLogCursor() {
return db.query(LOG_TABLE, null, Utils.fmt("from_uid/100000=%d", Const.USER_ID),
null, null, null, "time DESC");
}
public void addLog(SuLogEntry log) {
db.insert(LOG_TABLE, null, log.getContentValues());
}
public void clearLogs() {
db.delete(LOG_TABLE, null, null);
}
public void setSettings(String key, int value) {
ContentValues data = new ContentValues();
data.put("key", key);
data.put("value", value);
db.replace(SETTINGS_TABLE, null, data);
}
public int getSettings(String key, int defaultValue) {
int value = defaultValue;
try (Cursor c = db.query(SETTINGS_TABLE, null, "key=?",new String[] { key }, null, null, null)) {
if (c.moveToNext()) {
value = c.getInt(c.getColumnIndex("value"));
}
}
return value;
}
public void setStrings(String key, String value) {
if (value == null) {
db.delete(STRINGS_TABLE, "key=?", new String[] { key });
} else {
ContentValues data = new ContentValues();
data.put("key", key);
data.put("value", value);
db.replace(STRINGS_TABLE, null, data);
}
}
public String getStrings(String key, String defaultValue) {
String value = defaultValue;
try (Cursor c = db.query(STRINGS_TABLE, null, "key=?",new String[] { key }, null, null, null)) {
if (c.moveToNext()) {
value = c.getString(c.getColumnIndex("value"));
}
}
return value;
}
}

View File

@@ -1,21 +0,0 @@
package com.topjohnwu.magisk.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import com.topjohnwu.magisk.services.OnBootIntentService;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, OnBootIntentService.class));
} else {
context.startService(new Intent(context, OnBootIntentService.class));
}
}
}

View File

@@ -1,47 +0,0 @@
package com.topjohnwu.magisk.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.PatchAPK;
import com.topjohnwu.magisk.utils.Utils;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class ManagerUpdate extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Utils.dlAndReceive(
context, new PatchedInstall(),
intent.getStringExtra(Const.Key.INTENT_SET_LINK),
intent.getStringExtra(Const.Key.INTENT_SET_FILENAME)
);
}
private static class PatchedInstall extends ManagerInstall {
@Override
public void onDownloadDone(Context context, Uri uri) {
if (!context.getPackageName().equals(Const.ORIG_PKG_NAME)) {
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
String o = uri.getPath();
String p = o.substring(0, o.lastIndexOf('.')) + "-patched.apk";
try {
PatchAPK.patchPackageID(o, new BufferedOutputStream(new FileOutputStream(p)),
Const.ORIG_PKG_NAME, context.getPackageName());
} catch (FileNotFoundException ignored) { }
super.onDownloadDone(context, Uri.fromFile(new File(p)));
});
} else {
super.onDownloadDone(context, uri);
}
}
}
}

View File

@@ -1,32 +0,0 @@
package com.topjohnwu.magisk.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
public class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
MagiskManager mm = Utils.getMagiskManager(context);
String pkg = intent.getData().getEncodedSchemeSpecificPart();
switch (intent.getAction()) {
case Intent.ACTION_PACKAGE_REPLACED:
// This will only work pre-O
if (mm.prefs.getBoolean(Const.Key.SU_REAUTH, false)) {
mm.mDB.deletePolicy(pkg);
}
break;
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
mm.mDB.deletePolicy(pkg);
Shell.Async.su("magiskhide --rm " + pkg);
break;
}
}
}

View File

@@ -1,14 +0,0 @@
package com.topjohnwu.magisk.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.topjohnwu.superuser.Shell;
public class RebootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Shell.Async.su("/system/bin/reboot");
}
}

View File

@@ -1,87 +0,0 @@
package com.topjohnwu.magisk.receivers;
import android.content.BroadcastReceiver;
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 android.support.annotation.RequiresApi;
import android.text.TextUtils;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.SplashActivity;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import java.util.ArrayList;
public class ShortcutReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
MagiskManager mm = Utils.getMagiskManager(context);
ShortcutManager manager = context.getSystemService(ShortcutManager.class);
if (TextUtils.equals(intent.getAction(), Intent.ACTION_LOCALE_CHANGED)) {
// It is triggered with locale change, manual load Magisk info
mm.loadMagiskInfo();
}
manager.setDynamicShortcuts(getShortCuts(mm));
}
}
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
private ArrayList<ShortcutInfo> getShortCuts(MagiskManager mm) {
ArrayList<ShortcutInfo> shortCuts = new ArrayList<>();
if (Shell.rootAccess() &&
!(Const.USER_ID > 0 &&
mm.multiuserMode == Const.Value.MULTIUSER_MODE_OWNER_MANAGED)) {
shortCuts.add(new ShortcutInfo.Builder(mm, "superuser")
.setShortLabel(mm.getString(R.string.superuser))
.setIntent(new Intent(mm, SplashActivity.class)
.putExtra(Const.Key.OPEN_SECTION, "superuser")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(mm, R.drawable.sc_superuser))
.setRank(0)
.build());
}
if (Shell.rootAccess() && mm.magiskVersionCode >= Const.MAGISK_VER.UNIFIED
&& mm.prefs.getBoolean(Const.Key.MAGISKHIDE, false)) {
shortCuts.add(new ShortcutInfo.Builder(mm, "magiskhide")
.setShortLabel(mm.getString(R.string.magiskhide))
.setIntent(new Intent(mm, SplashActivity.class)
.putExtra(Const.Key.OPEN_SECTION, "magiskhide")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(mm, R.drawable.sc_magiskhide))
.setRank(1)
.build());
}
if (!mm.prefs.getBoolean(Const.Key.COREONLY, false) &&
Shell.rootAccess() && mm.magiskVersionCode >= 0) {
shortCuts.add(new ShortcutInfo.Builder(mm, "modules")
.setShortLabel(mm.getString(R.string.modules))
.setIntent(new Intent(mm, SplashActivity.class)
.putExtra(Const.Key.OPEN_SECTION, "modules")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(mm, R.drawable.sc_extension))
.setRank(3)
.build());
shortCuts.add(new ShortcutInfo.Builder(mm, "downloads")
.setShortLabel(mm.getString(R.string.download))
.setIntent(new Intent(mm, SplashActivity.class)
.putExtra(Const.Key.OPEN_SECTION, "downloads")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(mm, R.drawable.sc_cloud_download))
.setRank(2)
.build());
}
return shortCuts;
}
}

View File

@@ -1,44 +0,0 @@
package com.topjohnwu.magisk.services;
import android.app.IntentService;
import android.content.Intent;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.RootUtils;
public class OnBootIntentService extends IntentService {
public OnBootIntentService() {
super("OnBootIntentService");
}
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForeground(Const.ID.ONBOOT_NOTIFICATION_ID,
new NotificationCompat.Builder(this, Const.ID.NOTIFICATION_CHANNEL)
.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle("Startup Operations")
.setContentText("Running startup operations...")
.build());
}
}
@Override
protected void onHandleIntent(Intent intent) {
/* Pixel 2 (XL) devices will need to patch dtbo.img.
* However, that is not possible if Magisk is installed by
* patching boot image with Magisk Manager and fastboot flash
* the boot image, 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.
* */
MagiskManager.get().loadMagiskInfo();
RootUtils.patchDTBO();
}
}

View File

@@ -1,23 +0,0 @@
package com.topjohnwu.magisk.services;
import android.app.job.JobParameters;
import android.app.job.JobService;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
import com.topjohnwu.magisk.utils.Utils;
public class UpdateCheckService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
Utils.getMagiskManager(this).loadMagiskInfo();
new CheckUpdates(true)
.setCallBack(() -> jobFinished(params, false)).exec();
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
return true;
}
}

View File

@@ -1,300 +0,0 @@
package com.topjohnwu.magisk.superuser;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.FileObserver;
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.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import com.topjohnwu.magisk.utils.Utils;
import java.io.DataInputStream;
import java.io.IOException;
import butterknife.BindView;
import butterknife.ButterKnife;
public class RequestActivity extends Activity {
@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 String socketPath;
private LocalSocket socket;
private PackageManager pm;
private MagiskManager mm;
private boolean hasTimeout;
private Policy policy;
private CountDownTimer timer;
private FingerprintHelper fingerprintHelper;
@Override
public int getDarkTheme() {
return R.style.SuRequest_Dark;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
pm = getPackageManager();
mm = Utils.getMagiskManager(this);
mm.mDB.clearOutdated();
Intent intent = getIntent();
socketPath = intent.getStringExtra("socket");
hasTimeout = intent.getBooleanExtra("timeout", true);
new FileObserver(socketPath) {
@Override
public void onEvent(int fileEvent, String path) {
if (fileEvent == FileObserver.DELETE_SELF) {
finish();
}
}
}.startWatching();
new SocketManager(this).exec();
}
@Override
public void finish() {
if (timer != null)
timer.cancel();
if (fingerprintHelper != null)
fingerprintHelper.cancel();
super.finish();
}
private boolean cancelTimeout() {
timer.cancel();
deny_btn.setText(getString(R.string.deny));
return false;
}
private void showRequest() {
switch (mm.suResponseType) {
case Const.Value.SU_AUTO_DENY:
handleAction(Policy.DENY, 0);
return;
case Const.Value.SU_AUTO_ALLOW:
handleAction(Policy.ALLOW, 0);
return;
case Const.Value.SU_PROMPT:
default:
}
// If not interactive, response directly
if (policy.policy != Policy.INTERACTIVE) {
handleAction();
return;
}
setContentView(R.layout.activity_request);
ButterKnife.bind(this);
appIcon.setImageDrawable(policy.info.loadIcon(pm));
appNameView.setText(policy.appName);
packageNameView.setText(policy.packageName);
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);
timer = new CountDownTimer(mm.suRequestTimeout * 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 useFingerprint = mm.prefs.getBoolean(Const.Key.SU_FINGERPRINT, false) && FingerprintHelper.canUseFingerprint();
if (useFingerprint) {
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.startAuth();
} catch (Exception e) {
e.printStackTrace();
useFingerprint = false;
}
}
if (!useFingerprint) {
grant_btn.setOnClickListener(v -> {
handleAction(Policy.ALLOW);
timer.cancel();
});
grant_btn.requestFocus();
}
grant_btn.setVisibility(useFingerprint ? View.GONE : View.VISIBLE);
fingerprintImg.setVisibility(useFingerprint ? View.VISIBLE : View.GONE);
deny_btn.setOnClickListener(v -> {
handleAction(Policy.DENY);
timer.cancel();
});
suPopup.setOnClickListener(v -> cancelTimeout());
timeout.setOnTouchListener((v, event) -> cancelTimeout());
if (hasTimeout) {
timer.start();
} else {
cancelTimeout();
}
}
@Override
public void onBackPressed() {
if (policy != null) {
handleAction(Policy.DENY);
} else {
finish();
}
}
void handleAction() {
String response;
if (policy.policy == Policy.ALLOW) {
response = "socket:ALLOW";
} else {
response = "socket:DENY";
}
try {
socket.getOutputStream().write((response).getBytes());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
finish();
}
void handleAction(int action) {
handleAction(action, Const.Value.timeoutList[timeout.getSelectedItemPosition()]);
}
void handleAction(int action, int time) {
policy.policy = action;
if (time >= 0) {
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
mm.mDB.addPolicy(policy);
}
handleAction();
}
private class SocketManager extends ParallelTask<Void, Void, Boolean> {
SocketManager(Activity context) {
super(context);
}
@Override
protected Boolean doInBackground(Void... params) {
try {
socket = new LocalSocket();
socket.connect(new LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM));
DataInputStream is = new DataInputStream(socket.getInputStream());
ContentValues payload = new ContentValues();
while (true) {
int nameLen = is.readInt();
byte[] nameBytes = new byte[nameLen];
is.readFully(nameBytes);
String name = new String(nameBytes);
if (TextUtils.equals(name, "eof"))
break;
int dataLen = is.readInt();
byte[] dataBytes = new byte[dataLen];
is.readFully(dataBytes);
String data = new String(dataBytes);
payload.put(name, data);
}
if (payload.getAsInteger("uid") == null) {
return false;
}
int uid = payload.getAsInteger("uid");
policy = mm.mDB.getPolicy(uid);
if (policy == null) {
policy = new Policy(uid, pm);
}
/* Never allow com.topjohnwu.magisk (could be malware) */
if (TextUtils.equals(policy.packageName, Const.ORIG_PKG_NAME))
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
showRequest();
} else {
finish();
}
}
}
}

View File

@@ -1,90 +0,0 @@
package com.topjohnwu.magisk.superuser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Process;
import android.widget.Toast;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.container.SuLogEntry;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Utils;
import java.util.Date;
public class SuReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int fromUid, toUid, pid, mode;
String command, action;
Policy policy;
MagiskManager mm = Utils.getMagiskManager(context);
if (intent == null) return;
mode = intent.getIntExtra("mode", -1);
if (mode < 0) return;
if (mode == Const.Value.NOTIFY_USER_TO_OWNER) {
MagiskManager.toast(R.string.multiuser_hint_owner_request, Toast.LENGTH_LONG);
return;
}
fromUid = intent.getIntExtra("from.uid", -1);
if (fromUid < 0) return;
if (fromUid == Process.myUid()) return; // Don't show anything if it's Magisk Manager
action = intent.getStringExtra("action");
if (action == null) return;
policy = mm.mDB.getPolicy(fromUid);
if (policy == null) {
try {
policy = new Policy(fromUid, context.getPackageManager());
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return;
}
}
SuLogEntry log = new SuLogEntry(policy);
String message;
switch (action) {
case "allow":
message = context.getString(R.string.su_allow_toast, policy.appName);
log.action = true;
break;
case "deny":
message = context.getString(R.string.su_deny_toast, policy.appName);
log.action = false;
break;
default:
return;
}
if (policy.notification && mm.suNotificationType == Const.Value.NOTIFICATION_TOAST) {
MagiskManager.toast(message, Toast.LENGTH_SHORT);
}
if (mode == Const.Value.NOTIFY_NORMAL_LOG && policy.logging) {
toUid = intent.getIntExtra("to.uid", -1);
if (toUid < 0) return;
pid = intent.getIntExtra("pid", -1);
if (pid < 0) return;
command = intent.getStringExtra("command");
if (command == null) return;
log.toUid = toUid;
log.fromPid = pid;
log.command = command;
log.date = new Date();
mm.mDB.addLog(log);
}
}
}

View File

@@ -1,77 +0,0 @@
package com.topjohnwu.magisk.utils;
import com.topjohnwu.utils.JarMap;
import java.io.OutputStream;
import java.util.jar.JarEntry;
public class PatchAPK {
private static int findOffset(byte buf[], byte pattern[]) {
int offset = -1;
for (int i = 0; i < buf.length - pattern.length; ++i) {
boolean match = true;
for (int j = 0; j < pattern.length; ++j) {
if (buf[i + j] != pattern[j]) {
match = false;
break;
}
}
if (match) {
offset = i;
break;
}
}
return offset;
}
/* It seems that AAPT sometimes generate another type of string format */
private static boolean fallbackPatch(byte xml[], String from, String to) {
byte[] target = new byte[from.length() * 2 + 2];
for (int i = 0; i < from.length(); ++i) {
target[i * 2] = (byte) from.charAt(i);
}
int offset = findOffset(xml, target);
if (offset < 0)
return false;
byte[] dest = new byte[target.length - 2];
for (int i = 0; i < to.length(); ++i) {
dest[i * 2] = (byte) to.charAt(i);
}
System.arraycopy(dest, 0, xml, offset, dest.length);
return true;
}
private static boolean findAndPatch(byte xml[], String from, String to) {
byte target[] = (from + '\0').getBytes();
int offset = findOffset(xml, target);
if (offset < 0)
return fallbackPatch(xml, from, to);
System.arraycopy(to.getBytes(), 0, xml, offset, to.length());
return true;
}
public static boolean patchPackageID(String fileName, OutputStream out, String from, String to) {
try {
JarMap apk = new JarMap(fileName);
JarEntry je = apk.getJarEntry(Const.ANDROID_MANIFEST);
byte xml[] = apk.getRawData(je);
if (!findAndPatch(xml, from, to))
return false;
if (!findAndPatch(xml, from + ".provider", to + ".provider"))
return false;
// Write in changes
apk.getOutputStream(je).write(xml);
// Sign the APK
ZipUtils.signZip(apk, out);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
}

View File

@@ -1,38 +0,0 @@
package com.topjohnwu.magisk.utils;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import com.topjohnwu.superuser.io.SuFile;
public class RootUtils {
public static void init() {
if (Shell.rootAccess()) {
Const.MAGISK_DISABLE_FILE = new SuFile("/cache/.disable_magisk");
SuFile file = new SuFile("/sbin/.core/img");
if (file.exists()) {
Const.MAGISK_PATH = file;
} else if ((file = new SuFile("/dev/magisk/img")).exists()) {
Const.MAGISK_PATH = file;
} else {
Const.MAGISK_PATH = new SuFile("/magisk");
}
Const.MAGISK_HOST_FILE = new SuFile(Const.MAGISK_PATH + "/.core/hosts");
}
}
public static void uninstallPkg(String pkg) {
Shell.Sync.su("db_clean " + Const.USER_ID, "pm uninstall " + pkg);
}
public static void patchDTBO() {
if (Shell.rootAccess()) {
MagiskManager mm = MagiskManager.get();
if (mm.magiskVersionCode >= Const.MAGISK_VER.DTBO_SUPPORT) {
if (Boolean.parseBoolean(ShellUtils.fastCmd("mm_patch_dtbo")))
ShowUI.dtboPatchedNotification();
}
}
}
}

View File

@@ -1,36 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.content.Context;
import android.support.annotation.NonNull;
import com.topjohnwu.magisk.R;
import com.topjohnwu.superuser.BusyBox;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
import java.io.File;
import java.io.InputStream;
public class ShellInitializer extends Shell.Initializer {
static {
BusyBox.BB_PATH = new File(Const.BUSYBOX_PATH);
}
@Override
public boolean onRootShellInit(Context context, @NonNull Shell shell) throws Exception {
try (InputStream magiskUtils = context.getResources().openRawResource(R.raw.util_functions);
InputStream managerUtils = context.getResources().openRawResource(R.raw.utils)
) {
shell.execTask((in, err, out) -> {
ShellUtils.pump(magiskUtils, in);
ShellUtils.pump(managerUtils, in);
});
}
shell.run(null, null,
"mount_partitions",
"get_flags",
"run_migrations");
return true;
}
}

View File

@@ -1,273 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.Manifest;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.widget.Toast;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.SplashActivity;
import com.topjohnwu.magisk.asyncs.InstallMagisk;
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
import com.topjohnwu.magisk.asyncs.RestoreImages;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.receivers.DownloadReceiver;
import com.topjohnwu.magisk.receivers.ManagerUpdate;
import com.topjohnwu.magisk.receivers.RebootReceiver;
import com.topjohnwu.superuser.Shell;
import java.util.ArrayList;
import java.util.List;
public class ShowUI {
public static void magiskUpdateNotification() {
MagiskManager mm = MagiskManager.get();
Intent intent = new Intent(mm, SplashActivity.class);
intent.putExtra(Const.Key.OPEN_SECTION, "magisk");
TaskStackBuilder stackBuilder = TaskStackBuilder.create(mm);
stackBuilder.addParentStack(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(mm, Const.ID.NOTIFICATION_CHANNEL);
builder.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle(mm.getString(R.string.magisk_update_title))
.setContentText(mm.getString(R.string.magisk_update_available, mm.remoteMagiskVersionString))
.setVibrate(new long[]{0, 100, 100, 100})
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build());
}
public static void managerUpdateNotification() {
MagiskManager mm = MagiskManager.get();
String filename = Utils.fmt("MagiskManager-v%s(%d).apk",
mm.remoteManagerVersionString, mm.remoteManagerVersionCode);
Intent intent = new Intent(mm, ManagerUpdate.class);
intent.putExtra(Const.Key.INTENT_SET_LINK, mm.managerLink);
intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mm,
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL);
builder.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle(mm.getString(R.string.manager_update_title))
.setContentText(mm.getString(R.string.manager_download_install))
.setVibrate(new long[]{0, 100, 100, 100})
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build());
}
public static void dtboPatchedNotification() {
MagiskManager mm = MagiskManager.get();
Intent intent = new Intent(mm, RebootReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mm,
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL);
builder.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle(mm.getString(R.string.dtbo_patched_title))
.setContentText(mm.getString(R.string.dtbo_patched_reboot))
.setVibrate(new long[]{0, 100, 100, 100})
.addAction(R.drawable.ic_refresh, mm.getString(R.string.reboot), pendingIntent);
NotificationManager notificationManager =
(NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build());
}
public static void envFixDialog(Activity activity) {
MagiskManager mm = Utils.getMagiskManager(activity);
String filename = Utils.fmt("Magisk-v%s(%d).zip",
mm.remoteMagiskVersionString, mm.remoteMagiskVersionCode);
new AlertDialogBuilder(activity)
.setTitle(R.string.env_fix_title)
.setMessage(R.string.env_fix_msg)
.setCancelable(true)
.setPositiveButton(R.string.yes, (d, i) -> {
Utils.dlAndReceive(activity, new DownloadReceiver() {
@Override
public void onDownloadDone(Context context, Uri uri) {
new InstallMagisk(activity, uri).exec();
}
}, mm.magiskLink, filename);
})
.setNegativeButton(R.string.no_thanks, null)
.show();
}
public static void magiskInstallDialog(Activity activity) {
MagiskManager mm = Utils.getMagiskManager(activity);
String filename = Utils.fmt("Magisk-v%s(%d).zip",
mm.remoteMagiskVersionString, mm.remoteMagiskVersionCode);
AlertDialog.Builder b = new AlertDialogBuilder(activity)
.setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.magisk)))
.setMessage(mm.getString(R.string.repo_install_msg, filename))
.setCancelable(true)
.setPositiveButton(R.string.install, (d, i) -> {
List<String> options = new ArrayList<>();
options.add(mm.getString(R.string.download_zip_only));
options.add(mm.getString(R.string.patch_boot_file));
if (Shell.rootAccess()) {
options.add(mm.getString(R.string.direct_install));
}
new AlertDialog.Builder(activity)
.setTitle(R.string.select_method)
.setItems(
options.toArray(new String [0]),
(dialog, idx) -> {
DownloadReceiver receiver = null;
switch (idx) {
case 1:
if (mm.remoteMagiskVersionCode < 1400) {
MagiskManager.toast(R.string.no_boot_file_patch_support, Toast.LENGTH_LONG);
return;
}
MagiskManager.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG);
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
((com.topjohnwu.magisk.components.Activity) activity)
.startActivityForResult(intent, Const.ID.SELECT_BOOT,
(requestCode, resultCode, data) -> {
if (requestCode == Const.ID.SELECT_BOOT
&& resultCode == Activity.RESULT_OK && data != null) {
Utils.dlAndReceive(
activity,
new DownloadReceiver() {
@Override
public void onDownloadDone(Context context, Uri uri) {
Intent intent = new Intent(mm, FlashActivity.class);
intent.setData(uri)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(Const.Key.FLASH_SET_BOOT, data.getData())
.putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT);
mm.startActivity(intent);
}
},
mm.magiskLink,
filename
);
}
});
return;
case 0:
receiver = new DownloadReceiver() {
@Override
public void onDownloadDone(Context context, Uri uri) {
SnackbarMaker.showUri(activity, uri);
}
};
break;
case 2:
receiver = new DownloadReceiver() {
@Override
public void onDownloadDone(Context context, Uri uri) {
Intent intent = new Intent(mm, FlashActivity.class);
intent.setData(uri).putExtra(Const.Key.FLASH_ACTION,
Const.Value.FLASH_MAGISK);
activity.startActivity(intent);
}
};
break;
case 3:
receiver = new DownloadReceiver() {
@Override
public void onDownloadDone(Context context, Uri uri) {
Intent intent = new Intent(mm, FlashActivity.class);
intent.setData(uri).putExtra(Const.Key.FLASH_ACTION,
Const.Value.FLASH_SECOND_SLOT);
activity.startActivity(intent);
}
};
default:
}
Utils.dlAndReceive(activity, receiver, mm.magiskLink, filename);
}
).show();
})
.setNegativeButton(R.string.no_thanks, null);
if (!TextUtils.isEmpty(mm.magiskNoteLink)) {
b.setNeutralButton(R.string.release_notes, (d, i) -> {
if (mm.magiskNoteLink.contains("forum.xda-developers")) {
// Open forum links in browser
Intent openLink = new Intent(Intent.ACTION_VIEW, Uri.parse(mm.magiskNoteLink));
openLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mm.startActivity(openLink);
} else {
new MarkDownWindow(activity, null, mm.magiskNoteLink).exec();
}
});
}
b.show();
}
public static void managerInstallDialog(Activity activity) {
MagiskManager mm = Utils.getMagiskManager(activity);
String filename = Utils.fmt("MagiskManager-v%s(%d).apk",
mm.remoteManagerVersionString, mm.remoteManagerVersionCode);
AlertDialog.Builder b = new AlertDialogBuilder(activity)
.setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name)))
.setMessage(mm.getString(R.string.repo_install_msg, filename))
.setCancelable(true)
.setPositiveButton(R.string.install, (d, i) -> {
com.topjohnwu.magisk.components.Activity.runWithPermission(activity,
new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, () -> {
Intent intent = new Intent(mm, ManagerUpdate.class);
intent.putExtra(Const.Key.INTENT_SET_LINK, mm.managerLink);
intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename);
mm.sendBroadcast(intent);
});
})
.setNegativeButton(R.string.no_thanks, null);
if (!TextUtils.isEmpty(mm.managerNoteLink)) {
b.setNeutralButton(R.string.app_changelog, (d, i) ->
new MarkDownWindow(activity, null, mm.managerNoteLink).exec());
}
b.show();
}
public static void uninstallDialog(Activity activity) {
MagiskManager mm = Utils.getMagiskManager(activity);
AlertDialog.Builder b = new AlertDialogBuilder(activity)
.setTitle(R.string.uninstall_magisk_title)
.setMessage(R.string.uninstall_magisk_msg)
.setNeutralButton(R.string.restore_img, (d, i) -> new RestoreImages(activity).exec());
if (!TextUtils.isEmpty(mm.uninstallerLink)) {
b.setPositiveButton(R.string.complete_uninstall, (d, i) ->
Utils.dlAndReceive(activity, new DownloadReceiver() {
@Override
public void onDownloadDone(Context context, Uri uri) {
Intent intent = new Intent(context, FlashActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(uri)
.putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL);
context.startActivity(intent);
}
}, mm.uninstallerLink, "magisk-uninstaller.zip"));
}
b.show();
}
}

View File

@@ -1,99 +0,0 @@
package com.topjohnwu.magisk.utils;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class Topic {
private static final int NON_INIT = 0;
private static final int PENDING = 1;
private static final int PUBLISHED = 2;
private int state = NON_INIT;
private List<WeakReference<Subscriber>> subscribers;
private Object[] results;
public Topic() {
subscribers = new SyncArrayList<>();
}
public synchronized void subscribe(Subscriber sub) {
subscribers.add(new WeakReference<>(sub));
}
public synchronized void unsubscribe() {
subscribers = new SyncArrayList<>();
}
public synchronized void unsubscribe(Subscriber sub) {
List<WeakReference<Subscriber>> subs = subscribers;
subscribers = new ArrayList<>();
for (WeakReference<Subscriber> subscriber : subs) {
if (subscriber.get() != null && subscriber.get() != sub)
subscribers.add(subscriber);
}
}
public void reset() {
state = NON_INIT;
results = null;
}
public boolean isPublished() {
return state == PUBLISHED;
}
public void publish() {
publish(true);
}
public void publish(boolean record, Object... results) {
if (record)
state = PUBLISHED;
this.results = results;
// Snapshot
List<WeakReference<Subscriber>> subs = subscribers;
for (WeakReference<Subscriber> subscriber : subs) {
if (subscriber != null && subscriber.get() != null)
subscriber.get().onTopicPublished(this);
}
}
public Object[] getResults() {
return results;
}
public boolean isPending() {
return state == PENDING;
}
public void setPending() {
state = PENDING;
}
public interface Subscriber {
default void subscribeTopics() {
for (Topic topic : getSubscription()) {
if (topic.isPublished()) {
onTopicPublished(topic);
}
topic.subscribe(this);
}
}
default void unsubscribeTopics() {
for (Topic event : getSubscription()) {
event.unsubscribe(this);
}
}
void onTopicPublished(Topic topic);
Topic[] getSubscription();
}
private static class SyncArrayList<E> extends ArrayList<E> {
@Override
public synchronized boolean add(E e) {
return super.add(e);
}
}
}

View File

@@ -1,69 +0,0 @@
package com.topjohnwu.magisk.utils;
import com.topjohnwu.superuser.ShellUtils;
import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileOutputStream;
import com.topjohnwu.utils.JarMap;
import com.topjohnwu.utils.SignAPK;
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))) {
signZip(map, out);
}
}
public static void signZip(JarMap input, OutputStream output) throws Exception {
SignAPK.signZip(null, null, input, output);
}
}

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>

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="#757575"
android:pathData="M11.8,10.9c-2.27,-0.59 -3,-1.2 -3,-2.15 0,-1.09 1.01,-1.85 2.7,-1.85 1.78,0 2.44,0.85 2.5,2.1h2.21c-0.07,-1.72 -1.12,-3.3 -3.21,-3.81V3h-3v2.16c-1.94,0.42 -3.5,1.68 -3.5,3.61 0,2.31 1.91,3.46 4.7,4.13 2.5,0.6 3,1.48 3,2.41 0,0.69 -0.49,1.79 -2.7,1.79 -2.06,0 -2.87,-0.92 -2.98,-2.1h-2.2c0.12,2.19 1.76,3.42 3.68,3.83V21h3v-2.15c1.95,-0.37 3.5,-1.5 3.5,-3.55 0,-2.84 -2.43,-3.81 -4.7,-4.4z"/>
</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="M13,7h-2v2h2L13,7zM13,11h-2v6h2v-6zM17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#757575"
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#757575"
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#757575"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2 0,0.68 0.06,1.34 0.14,2L4.26,14zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zM8.03,8L5.08,8c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14L9.66,14c-0.09,-0.66 -0.16,-1.32 -0.16,-2 0,-0.68 0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2 0,0.68 -0.07,1.34 -0.16,2zM14.59,19.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2 0,-0.68 -0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z"/>
</vector>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<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:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2S10.9,8 12,8zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,10 12,10zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,16 12,16z"
android:fillColor="#757575"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#757575"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</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="#fff"
android:pathData="M10,16h4c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1v-1c0,-1.11 -0.9,-2 -2,-2 -1.11,0 -2,0.9 -2,2v1c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1zM10.8,10c0,-0.66 0.54,-1.2 1.2,-1.2 0.66,0 1.2,0.54 1.2,1.2v1h-2.4v-1zM17,1L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-2 -2,-2zM17,19L7,19L7,5h10v14z"/>
</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="#fff"
android:pathData="M21,10.12h-6.78l2.74,-2.82c-2.73,-2.7 -7.15,-2.8 -9.88,-0.1 -2.73,2.71 -2.73,7.08 0,9.79 2.73,2.71 7.15,2.71 9.88,0C18.32,15.65 19,14.08 19,12.1h2c0,1.98 -0.88,4.55 -2.64,6.29 -3.51,3.48 -9.21,3.48 -12.72,0 -3.5,-3.47 -3.53,-9.11 -0.02,-12.58 3.51,-3.47 9.14,-3.47 12.65,0L21,3v7.12zM12.5,8v4.25l3.5,2.08 -0.72,1.21L11,13V8h1.5z"/>
</vector>

View File

@@ -1,123 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar"/>
<ScrollView
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dp"
tools:ignore="UseCompoundDrawables,ContentDescription">
<LinearLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
style="?attr/cardStyle"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="72dp"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:layout_width="72dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_logo"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:text="@string/app_name"
android:textAppearance="@style/TextAppearance.AppCompat.Headline"/>
</LinearLayout>
<com.topjohnwu.magisk.components.AboutCardRow
android:id="@+id/app_version_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_info_outline"
app:text="@string/app_version"/>
<com.topjohnwu.magisk.components.AboutCardRow
android:id="@+id/app_changelog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_history"
app:text="@string/app_changelog"/>
<com.topjohnwu.magisk.components.AboutCardRow
android:id="@+id/app_translators"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_language"
app:text="@string/app_translators"/>
<com.topjohnwu.magisk.components.AboutCardRow
android:id="@+id/app_source_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_github"
app:text="@string/app_source_code"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
style="?attr/cardStyle"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.topjohnwu.magisk.components.AboutCardRow
android:id="@+id/support_thread"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_xda"
app:text="@string/support_thread"/>
<com.topjohnwu.magisk.components.AboutCardRow
android:id="@+id/donation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_attach_money"
app:text="@string/donation"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@@ -1,70 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/flashing_background_color"
tools:context="com.topjohnwu.magisk.FlashActivity">
<include layout="@layout/toolbar"/>
<ScrollView
android:id="@+id/scrollView"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/txtLog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:padding="8dp"
android:textColor="@android:color/white"
android:textSize="10sp" />
</HorizontalScrollView>
</ScrollView>
<LinearLayout
android:id="@+id/button_panel"
style="?android:buttonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
android:visibility="gone">
<Button
android:id="@+id/no_thanks"
style="?android:borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="@string/close" />
<Button
android:id="@+id/save_logs"
style="?android:borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="@string/menuSaveLog" />
<Button
android:id="@+id/reboot"
style="?android:borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="@string/reboot" />
</LinearLayout>
</LinearLayout>

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:windowBackground"
android:orientation="vertical">
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include layout="@layout/toolbar" />
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="@menu/drawer" />
</android.support.v4.widget.DrawerLayout>

View File

@@ -1,127 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/su_popup"
tools:context=".superuser.RequestActivity"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:minWidth="350dp"
android:layout_gravity="center"
android:orientation="vertical"
android:background="?attr/colorBackgroundFloating">
<TextView
android:text="@string/su_request_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/request_title"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:layout_marginBottom="5dp"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:layout_gravity="center_horizontal">
<ImageView
android:id="@+id/app_icon"
android:layout_weight="0"
android:layout_marginEnd="10dp"
android:layout_height="50dp"
android:layout_width="50dp"
android:layout_marginStart="5dp"
android:layout_gravity="center_vertical" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_weight="1"
android:layout_gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="200dp"
android:maxWidth="300dp"
android:maxLines="1"
android:ellipsize="end"
android:textColor="?android:textColorPrimary"
android:textAppearance="?android:attr/textAppearanceMedium"
android:id="@+id/app_name" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="200dp"
android:maxWidth="300dp"
android:maxLines="1"
android:ellipsize="end"
android:textColor="?android:textColorSecondary"
android:id="@+id/package_name" />
</LinearLayout>
</LinearLayout>
<Spinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/timeout"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_su_warning"
android:textColor="?android:textColorSecondary"
android:text="@string/su_warning"
android:layout_gravity="center_horizontal"
android:layout_margin="5dp"
android:drawablePadding="10dp" />
<LinearLayout
style="?android:buttonBarStyle"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:paddingLeft="30dp"
android:paddingRight="30dp">
<Button
style="?android:buttonBarButtonStyle"
android:text="@string/deny_with_str"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/deny_btn"
android:layout_weight="1" />
<Button
android:id="@+id/grant_btn"
style="?android:buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/grant" />
<ImageView
android:id="@+id/fingerprint"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="7dp"
android:tint="?attr/colorAccent"
android:src="@drawable/ic_fingerprint" />
</LinearLayout>
</LinearLayout>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:windowBackground"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>

View File

@@ -1,69 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/message_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="12dip"
android:paddingEnd="20dip"
android:paddingStart="20dip"
android:paddingTop="12dip">
<TextView
android:id="@+id/message"
style="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dip" />
</LinearLayout>
<LinearLayout
style="?android:attr/buttonBarStyle"
android:id="@+id/button_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
android:measureWithLargestChild="true"
android:orientation="horizontal"
android:paddingEnd="2dip"
android:paddingStart="2dip"
android:paddingTop="4dip">
<Button
android:id="@+id/negative"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layout_weight="1"
android:maxLines="2" />
<Button
android:id="@+id/neutral"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:maxLines="2" />
<Button
android:id="@+id/positive"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1"
android:maxLines="2" />
</LinearLayout>
</LinearLayout>

View File

@@ -1,28 +0,0 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginTop="?attr/actionBarSize"
tools:context="com.topjohnwu.magisk.LogFragment">
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:id="@+id/tab"
app:tabPaddingEnd="20dp"
app:tabPaddingStart="20dp"
android:elevation="4dp"
android:visibility="gone">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="@+id/container"/>
</LinearLayout>

View File

@@ -1,363 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
style="?attr/cardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="4dp"
app:cardCornerRadius="@dimen/card_corner_radius"
app:cardElevation="@dimen/card_elevation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="7dp"
android:paddingTop="7dp">
<RelativeLayout
android:id="@+id/magisk_update"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp">
<ImageView
android:id="@+id/magisk_update_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/magisk_update_status"
android:visibility="gone" />
<ProgressBar
android:id="@+id/magisk_update_progress"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/magisk_update_status" />
<TextView
android:id="@+id/magisk_update_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:minWidth="225dp"
android:padding="6dp"
android:text="@string/checking_for_updates"
android:textStyle="bold" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/magisk_status_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/magisk_version" />
<TextView
android:id="@+id/magisk_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:minWidth="225dp"
android:padding="6dp"
android:textStyle="bold" />
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/safetyNet_card"
style="?attr/cardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="4dp"
app:cardCornerRadius="@dimen/card_corner_radius"
app:cardElevation="@dimen/card_elevation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/safetyNet_title"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/safetyNet_refresh"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_margin="15dp"
android:layout_toStartOf="@+id/safetyNet_status"
android:src="@drawable/ic_refresh" />
<ProgressBar
android:id="@+id/safetyNet_check_progress"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_margin="15dp"
android:layout_toStartOf="@+id/safetyNet_status"
android:visibility="gone" />
<TextView
android:id="@+id/safetyNet_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:minWidth="175dp"
android:padding="6dp"
android:text="@string/safetyNet_check_text"
android:textStyle="bold" />
</RelativeLayout>
<LinearLayout
android:id="@+id/expand_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingEnd="10dp"
android:paddingStart="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/cts_status_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginBottom="5dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp" />
<TextView
android:id="@+id/cts_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:minWidth="150dp"
android:padding="6dp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/basic_status_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_margin="10dp" />
<TextView
android:id="@+id/basic_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:minWidth="150dp"
android:padding="6dp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/install_option_card"
style="?attr/cardStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginBottom="4dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="4dp"
app:cardCornerRadius="@dimen/card_corner_radius"
app:cardElevation="@dimen/card_elevation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="15dp"
android:layout_marginTop="15dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:paddingBottom="10dp"
android:text="@string/advanced_settings_title"
android:textStyle="bold" />
<CheckBox
android:id="@+id/keep_force_enc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="50dp"
android:layout_marginStart="50dp"
android:text="@string/keep_force_encryption" />
<CheckBox
android:id="@+id/keep_verity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="50dp"
android:layout_marginStart="50dp"
android:text="@string/keep_dm_verity" />
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/install_button"
style="?attr/cardStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginBottom="4dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="4dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:visibility="gone"
app:cardCornerRadius="@dimen/card_corner_radius"
app:cardElevation="@dimen/card_elevation">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:layout_marginEnd="40dp"
android:layout_marginStart="40dp"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageView"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginEnd="5dp"
app:srcCompat="@drawable/ic_logo" />
<TextView
android:id="@+id/install_text"
android:layout_width="180dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:ems="10"
android:fontFamily="sans-serif"
android:gravity="center"
android:text="@string/install"
android:textAllCaps="false"
android:textSize="20sp"
android:textStyle="bold" />
</RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/uninstall_button"
style="?attr/cardStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginBottom="4dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="4dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="@dimen/card_corner_radius"
app:cardElevation="@dimen/card_elevation"
android:focusable="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:ems="10"
android:fontFamily="sans-serif"
android:gravity="center"
android:text="@string/uninstall"
android:textAllCaps="false"
android:textSize="20sp"
android:textStyle="bold" />
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:dividerHeight="@dimen/card_divider_space"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView android:id="@+id/svLog"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize">
<HorizontalScrollView
android:id="@+id/hsvLog"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="ScrollViewSize">
<TextView
android:id="@+id/txtLog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:padding="8dp"
android:textIsSelectable="true"
android:textSize="10sp" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</LinearLayout>
</HorizontalScrollView>
</ScrollView>

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:dividerHeight="@dimen/card_divider_space"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
<TextView
android:id="@+id/empty_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:text="@string/no_modules_found"
android:textSize="20sp"
android:textStyle="italic"
android:visibility="gone" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="@dimen/fab_padding"
android:elevation="6dp"
android:src="@drawable/ic_add"
tools:fabSize="normal"
tools:pressedTranslationZ="12dp" />
</android.support.design.widget.CoordinatorLayout>
</android.support.v4.widget.SwipeRefreshLayout>

View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_marginTop="?attr/actionBarSize"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/empty_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:text="@string/no_modules_found"
android:textSize="20sp"
android:textStyle="italic"
android:visibility="gone" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="@dimen/card_divider_space"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>

View File

@@ -1,28 +0,0 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_marginTop="?attr/actionBarSize"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/empty_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:text="@string/no_apps_found"
android:textSize="20sp"
android:textStyle="italic"
android:visibility="gone" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="@dimen/card_divider_space"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
</LinearLayout>

View File

@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 dvdandroid
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout android:id="@+id/container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<ImageView
android:id="@android:id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:tint="#757575"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:orientation="vertical"
android:paddingBottom="8dp"
android:paddingTop="8dp">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"/>
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Caption"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,78 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="@dimen/card_vertical_margin"
android:layout_marginEnd="@dimen/card_horizontal_margin"
android:layout_marginStart="@dimen/card_horizontal_margin"
android:layout_marginTop="@dimen/card_vertical_margin"
style="?attr/cardStyle"
android:minHeight="?android:attr/listPreferredItemHeight"
card_view:cardCornerRadius="@dimen/card_corner_radius"
card_view:cardElevation="@dimen/card_elevation">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/info_layout"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp">
<ImageView
android:id="@+id/app_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:gravity="end" />
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp">
<TextView
android:id="@+id/app_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="false"/>
<TextView
android:id="@+id/package_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/tertiary_text_dark"
android:textIsSelectable="false" />
</LinearLayout>
<CheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_menu_overflow_material"
android:checked="false" />
</LinearLayout>
</android.support.v7.widget.CardView>

View File

@@ -1,113 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="?attr/cardStyle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="@dimen/card_vertical_margin"
android:layout_marginEnd="@dimen/card_horizontal_margin"
android:layout_marginStart="@dimen/card_horizontal_margin"
android:layout_marginTop="@dimen/card_vertical_margin"
android:minHeight="?android:attr/listPreferredItemHeight"
card_view:cardCornerRadius="@dimen/card_corner_radius"
card_view:cardElevation="@dimen/card_elevation">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:padding="@dimen/card_layout_padding">
<TextView
android:id="@+id/title"
android:layout_width="@dimen/card_textview_width"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginTop="0dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="false"/>
<TextView
android:id="@+id/version_name"
android:layout_width="@dimen/card_textview_width"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/tertiary_text_dark"
android:textIsSelectable="false"
android:textStyle="bold|italic"/>
<TextView
android:id="@+id/author"
android:layout_width="@dimen/card_textview_width"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/version_name"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/tertiary_text_dark"
android:textIsSelectable="false"
android:textStyle="bold|italic"/>
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/author"
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textIsSelectable="false"/>
<TextView
android:id="@+id/notice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/description"
android:layout_gravity="center_vertical"
android:text="@string/remove_file_created"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/red500"
android:visibility="gone"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/title"
android:layout_alignParentEnd="true"
android:orientation="horizontal"
android:gravity="end">
<CheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:gravity="center"
android:padding="@dimen/checkbox_padding"
android:src="@drawable/ic_menu_overflow_material"
tools:ignore="ContentDescription"/>
<ImageView
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="0dp"
android:focusable="false"
android:gravity="center"
android:padding="@dimen/checkbox_padding"
android:src="@drawable/ic_delete"
android:tint="@color/icon_grey"
tools:ignore="ContentDescription"/>
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>

View File

@@ -1,172 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
style="?attr/cardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="@dimen/card_vertical_margin"
android:layout_marginEnd="@dimen/card_horizontal_margin"
android:layout_marginStart="@dimen/card_horizontal_margin"
android:layout_marginTop="@dimen/card_vertical_margin"
android:minHeight="?android:attr/listPreferredItemHeight"
card_view:cardCornerRadius="@dimen/card_corner_radius"
card_view:cardElevation="@dimen/card_elevation">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/info_layout"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp">
<ImageView
android:id="@+id/app_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:gravity="end" />
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp">
<TextView
android:id="@+id/app_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="false"/>
<TextView
android:id="@+id/package_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/tertiary_text_dark"
android:textIsSelectable="false" />
</LinearLayout>
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/master_switch"
android:layout_weight="0"
android:checked="false"
android:layout_gravity="center_vertical"
android:gravity="center_vertical" />
</LinearLayout>
<LinearLayout
android:id="@+id/expand_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
android:paddingStart="10dp"
android:paddingEnd="10dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:layout_gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_notifications"
android:layout_gravity="center_vertical"
android:tint="@color/icon_grey"
android:layout_marginEnd="10dp" />
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/notification_switch"
android:checked="false"
android:layout_gravity="center_vertical"
android:gravity="center_vertical" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:layout_gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_bug_report"
android:layout_gravity="center_vertical"
android:tint="@color/icon_grey"
android:layout_marginEnd="10dp" />
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/logging_switch"
android:checked="false"
android:layout_gravity="center_vertical"
android:gravity="center_vertical" />
</LinearLayout>
<ImageView
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:src="@drawable/ic_delete"
android:tint="@color/icon_grey"
android:layout_gravity="center" />
<ImageView
android:id="@+id/more_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:src="@drawable/ic_more"
android:tint="@color/icon_grey"
android:layout_gravity="center" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>

View File

@@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
style="?attr/cardStyle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="@dimen/card_vertical_margin"
android:layout_marginEnd="@dimen/card_horizontal_margin"
android:layout_marginStart="@dimen/card_horizontal_margin"
android:layout_marginTop="@dimen/card_vertical_margin"
android:minHeight="?android:attr/listPreferredItemHeight"
card_view:cardCornerRadius="@dimen/card_corner_radius"
card_view:cardElevation="@dimen/card_elevation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:padding="@dimen/card_layout_padding">
<LinearLayout
android:id="@+id/info_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="false" />
<TextView
android:id="@+id/version_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/no_info_provided"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/tertiary_text_dark"
android:textIsSelectable="false"
android:textStyle="bold|italic" />
<TextView
android:id="@+id/author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/no_info_provided"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/tertiary_text_dark"
android:textIsSelectable="false"
android:textStyle="bold|italic" />
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/no_info_provided"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textIsSelectable="false" />
<TextView
android:id="@+id/update_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/tertiary_text_dark"
android:textIsSelectable="false"
android:textStyle="bold|italic" />
</LinearLayout>
<ImageView
android:id="@+id/download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@drawable/ic_file_download_black"
android:backgroundTint="@color/icon_grey"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
android:focusable="false"
android:gravity="end" />
</LinearLayout>
</android.support.v7.widget.CardView>

View File

@@ -1,145 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
style="?attr/cardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="2dp"
android:layout_marginEnd="@dimen/card_horizontal_margin"
android:layout_marginStart="@dimen/card_horizontal_margin"
android:layout_marginTop="2dp"
card_view:cardCornerRadius="@dimen/card_corner_radius"
card_view:cardElevation="@dimen/card_elevation">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/info_layout"
android:padding="10dp">
<TextView
android:id="@+id/app_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:textIsSelectable="false"
android:layout_weight="2" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/action"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:gravity="center_horizontal" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/time"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:gravity="center_horizontal" />
</LinearLayout>
<LinearLayout
android:id="@+id/expand_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:gravity="center"
android:layout_gravity="center_horizontal">
<LinearLayout
android:orientation="horizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="1">
<TextView
android:text="@string/pid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fromPid"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="1">
<TextView
android:text="@string/target_uid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/toUid"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="2">
<TextView
android:text="@string/command"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/command"
android:textColor="?android:attr/textColorSecondary"
android:gravity="start"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:padding="5dp">
<ImageView
android:id="@+id/arrow"
android:layout_width="wrap_content"
android:layout_height="25dp"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_arrow" />
<TextView
android:id="@+id/date"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="2017/1/1"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar android:id="@+id/toolbar"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"/>

View File

@@ -1,6 +0,0 @@
### v5.8.3
- Update internal scripts for detecting ramdisk partition on Huawei devices
### v5.8.2
- Prevent invalid modules in the online repo crashing the app
- Update Stable and Beta channel URLs

View File

@@ -1,276 +0,0 @@
body {
font-family: Helvetica, arial, sans-serif;
font-size: 14px;
line-height: 1.6;
padding-top: 10px;
padding-bottom: 10px;
background-color: #424242;
color: white;
padding: 15px; }
body > *:first-child {
margin-top: 0 !important; }
body > *:last-child {
margin-bottom: 0 !important; }
a {
color: #4183C4; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
background: url("../../images/modules/styleguide/para.png") no-repeat 10px center;
text-decoration: none; }
h1 tt, h1 code {
font-size: inherit; }
h2 tt, h2 code {
font-size: inherit; }
h3 tt, h3 code {
font-size: inherit; }
h4 tt, h4 code {
font-size: inherit; }
h5 tt, h5 code {
font-size: inherit; }
h6 tt, h6 code {
font-size: inherit; }
h1 {
font-size: 28px; }
h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc; }
h3 {
font-size: 18px; }
h4 {
font-size: 16px; }
h5 {
font-size: 14px; }
h6 {
color: #888888;
font-size: 14px; }
p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0; }
hr {
background: transparent url("../../images/modules/pulls/dirty-shade.png") repeat-x 0 0;
border: 0 none;
color: #cccccc;
height: 4px;
padding: 0; }
body > h2:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0; }
li p.first {
display: inline-block; }
ul, ol {
padding-left: 30px; }
ul :first-child, ol :first-child {
margin-top: 0; }
ul :last-child, ol :last-child {
margin-bottom: 0; }
dl {
padding: 0; }
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
dl dt:first-child {
padding: 0; }
dl dt > :first-child {
margin-top: 0; }
dl dt > :last-child {
margin-bottom: 0; }
dl dd {
margin: 0 0 15px;
padding: 0 15px; }
dl dd > :first-child {
margin-top: 0; }
dl dd > :last-child {
margin-bottom: 0; }
blockquote {
border-left: 4px solid #404040;
padding: 0 15px;
color: #888888; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }
table {
padding: 0; }
table tr {
border-top: 1px solid #707070;
background-color: #303030;
margin: 0;
padding: 0; }
table tr:nth-child(2n) {
background-color: #505050; }
table tr th {
font-weight: bold;
border: 1px solid #707070;
text-align: left;
margin: 0;
padding: 6px 13px; }
table tr td {
border: 1px solid #707070;
text-align: left;
margin: 0;
padding: 6px 13px; }
table tr th :first-child, table tr td :first-child {
margin-top: 0; }
table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
img {
max-width: 100%; }
span.frame {
display: block;
overflow: hidden; }
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
span.frame span img {
display: block;
float: left; }
span.frame span span {
clear: both;
color: #cccccc;
display: block;
padding: 5px 0 0; }
span.align-center {
display: block;
overflow: hidden;
clear: both; }
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
span.align-center span img {
margin: 0 auto;
text-align: center; }
span.align-right {
display: block;
overflow: hidden;
clear: both; }
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
span.align-right span img {
margin: 0;
text-align: right; }
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left; }
span.float-left span {
margin: 13px 0 0; }
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right; }
span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right; }
code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #707070;
background-color: #606060;
border-radius: 3px; }
pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }
.highlight pre {
background-color: #3f3f3f;
border: 1px solid #707070;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre {
background-color: #606060;
border: 1px solid #707070;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre code, pre tt {
background-color: transparent;
border: none; }

View File

@@ -1,277 +0,0 @@
body {
font-family: Helvetica, arial, sans-serif;
font-size: 14px;
line-height: 1.6;
padding-top: 10px;
padding-bottom: 10px;
background-color: white;
padding: 15px; }
body > *:first-child {
margin-top: 0 !important; }
body > *:last-child {
margin-bottom: 0 !important; }
a {
color: #4183C4; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
background: url("../../images/modules/styleguide/para.png") no-repeat 10px center;
text-decoration: none; }
h1 tt, h1 code {
font-size: inherit; }
h2 tt, h2 code {
font-size: inherit; }
h3 tt, h3 code {
font-size: inherit; }
h4 tt, h4 code {
font-size: inherit; }
h5 tt, h5 code {
font-size: inherit; }
h6 tt, h6 code {
font-size: inherit; }
h1 {
font-size: 28px;
color: black; }
h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }
h3 {
font-size: 18px; }
h4 {
font-size: 16px; }
h5 {
font-size: 14px; }
h6 {
color: #777777;
font-size: 14px; }
p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0; }
hr {
background: transparent url("../../images/modules/pulls/dirty-shade.png") repeat-x 0 0;
border: 0 none;
color: #cccccc;
height: 4px;
padding: 0; }
body > h2:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0; }
li p.first {
display: inline-block; }
ul, ol {
padding-left: 30px; }
ul :first-child, ol :first-child {
margin-top: 0; }
ul :last-child, ol :last-child {
margin-bottom: 0; }
dl {
padding: 0; }
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
dl dt:first-child {
padding: 0; }
dl dt > :first-child {
margin-top: 0; }
dl dt > :last-child {
margin-bottom: 0; }
dl dd {
margin: 0 0 15px;
padding: 0 15px; }
dl dd > :first-child {
margin-top: 0; }
dl dd > :last-child {
margin-bottom: 0; }
blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }
table {
padding: 0; }
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
table tr:nth-child(2n) {
background-color: #f8f8f8; }
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px; }
table tr td {
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px; }
table tr th :first-child, table tr td :first-child {
margin-top: 0; }
table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
img {
max-width: 100%; }
span.frame {
display: block;
overflow: hidden; }
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
span.frame span img {
display: block;
float: left; }
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0; }
span.align-center {
display: block;
overflow: hidden;
clear: both; }
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
span.align-center span img {
margin: 0 auto;
text-align: center; }
span.align-right {
display: block;
overflow: hidden;
clear: both; }
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
span.align-right span img {
margin: 0;
text-align: right; }
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left; }
span.float-left span {
margin: 13px 0 0; }
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right; }
span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right; }
code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }
pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }
.highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre code, pre tt {
background-color: transparent;
border: none; }

View File

@@ -1,95 +0,0 @@
db_sepatch() {
magiskpolicy --live 'create magisk_file' 'attradd magisk_file mlstrustedobject' \
'allow * magisk_file file *' 'allow * magisk_file dir *' \
'allow magisk_file * filesystem associate'
}
db_clean() {
local USERID=$1
local DIR="/sbin/.core/db-${USERID}"
umount -l /data/user*/*/*/databases/su.db $DIR $DIR/*
rm -rf $DIR
[ "$USERID" = "*" ] && rm -fv /data/adb/magisk.db*
}
db_init() {
# Temporary let the folder rw by anyone
chcon u:object_r:magisk_file:s0 /data/adb
chmod 777 /data/adb
}
db_restore() {
chmod 700 /data/adb
magisk --restorecon
}
db_setup() {
local USER=$1
local USERID=$(($USER / 100000))
local DIR=/sbin/.core/db-${USERID}
mkdir -p $DIR
touch $DIR/magisk.db
mount -o bind /data/adb/magisk.db $DIR/magisk.db
rm -f /data/adb/magisk.db-*
chcon u:object_r:magisk_file:s0 $DIR $DIR/*
chmod 700 $DIR
chown $USER.$USER $DIR
chmod 666 $DIR/*
}
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
sh update-binary extract
rm -f update-binary magisk.apk
cd /
rm -rf /sbin/.core/busybox/*
/sbin/.core/mirror/bin/busybox --install -s /sbin/.core/busybox
}
direct_install() {
flash_boot_image $1 $2
rm -f $1
rm -rf /data/adb/magisk/* 2>/dev/null
mkdir -p /data/adb/magisk 2>/dev/null
chmod 700 /data/adb
cp -rf $3/* /data/adb/magisk
rm -rf $3
}
mm_patch_dtbo() {
if $KEEPVERITY; then
echo false
else
find_dtbo_image
patch_dtbo_image >/dev/null 2>&1 && echo true || echo false
fi
}
restore_imgs() {
SHA1=`cat /.backup/.sha1`
[ -z $SHA1 ] && SHA1=`grep_prop #STOCKSHA1`
[ -z $SHA1 ] && return 1
STOCKBOOT=/data/stock_boot_${SHA1}.img.gz
STOCKDTBO=/data/stock_dtbo.img.gz
[ -f $STOCKBOOT ] || return 1
find_boot_image
find_dtbo_image
magisk --unlock-blocks 2>/dev/null
if [ -b "$DTBOIMAGE" -a -f $STOCKDTBO ]; then
gzip -d < $STOCKDTBO > $DTBOIMAGE
fi
if [ -b "$BOOTIMAGE" -a -f $STOCKBOOT ]; then
gzip -d < $STOCKBOOT | cat - /dev/zero > $BOOTIMAGE 2>/dev/null
return 0
fi
return 1
}

View File

@@ -1,148 +0,0 @@
<resources>
<!--Universal-->
<!--Welcome Activity-->
<string name="modules">الإضافات</string>
<string name="downloads">التنزيلات</string>
<string name="superuser">Superuser</string>
<string name="log">السجل</string>
<string name="settings">الإعدادات</string>
<string name="install">التثبيت</string>
<!--Status Fragment-->
<string name="magisk_version_error">Magisk غير مثبت</string>
<string name="checking_for_updates">البحث عن تحديثات…</string>
<string name="magisk_update_available">Magisk v%1$s متاح!</string>
<string name="safetyNet_check_text">انقر لبدء فحص SafetyNet</string>
<string name="checking_safetyNet_status">التحقق من حالة SafetyNet…</string>
<string name="safetyNet_check_success">نجح فحص SafetyNet</string>
<string name="safetyNet_network_loss">فقدان الاتصال بالشبكة</string>
<string name="safetyNet_service_disconnected">تم إنهاء الخدمة</string>
<string name="safetyNet_res_invalid">الاستجابة غير صالحه</string>
<!--Install Fragment-->
<string name="advanced_settings_title">إعدادات متقدمة</string>
<string name="keep_force_encryption">الحفاظ علي قوه التشفير</string>
<string name="keep_dm_verity">إبقاء AVB 2.0/dm-verity</string>
<string name="current_magisk_title">نسخة Magisk المثبته: %1$s</string>
<string name="install_magisk_title">آخر نسخة Magisk: %1$s</string>
<string name="uninstall">إلغاء التثبيت</string>
<string name="uninstall_magisk_title">إلغاء تثبيت Magisk</string>
<!--Module Fragment-->
<string name="no_info_provided">(لم يتم توفير أي معلومات)</string>
<string name="no_modules_found">لم يعثر على الإضافات</string>
<string name="update_file_created">سيتم تحديث الإضافة في إعادة التشغيل التالي</string>
<string name="remove_file_created">سيتم حذف الإضافة في إعادة التشغيل التالي</string>
<string name="remove_file_deleted">لن يتم حذف الإضافة في إعادة التشغيل التالي</string>
<string name="disable_file_created">سيتم تعطيل الإضافة في إعادة التشغيل التالي</string>
<string name="disable_file_removed">سيتم تمكين الإضافة في إعادة التشغيل التالي</string>
<string name="author">انشئ بواسطة %1$s</string>
<!--Repo Fragment-->
<string name="update_available">يتوفر تحديث</string>
<string name="installed">مثبت</string>
<string name="not_installed">غير مثبت</string>
<!--Log Fragment-->
<string name="menuReload">إعادة تحميل</string>
<string name="menuClearLog">حذف السجل الآن</string>
<string name="logs_cleared">تم حذف السجل بنجاح</string>
<string name="log_is_empty">السجل فارغ</string>
<!--About Activity-->
<string name="about">حول</string>
<string name="app_changelog">تغييرات التطبيق</string>
<string name="translators">xx6600xx ,silent_6600</string>
<string name="app_version">إصدار التطبيق</string>
<string name="app_source_code">الشفرة المصدرية</string>
<string name="donation">التبرع</string>
<string name="app_translators">مترجم التطبيق</string>
<string name="support_thread">منتدى الدعم</string>
<!--Toasts, Dialogs-->
<string name="close">إغلاق</string>
<string name="repo_install_title">تثبيت %1$s</string>
<string name="repo_install_msg">هل تريد تثبيت %1$s ?</string>
<string name="download">التنزيل</string>
<string name="reboot">إعادة التشغيل</string>
<string name="zip_process_msg">معالجة الملف المضغوط …</string>
<string name="magisk_update_title">تحديث Magisk جديد متوفر!</string>
<string name="settings_reboot_toast">إعادة التشغيل لتطبيق الإعدادات</string>
<string name="release_notes">ملاحظات الإصدار</string>
<string name="repo_cache_cleared">تم مسح الذاكرة المؤقته للمستودع</string>
<string name="process_error">خطأ في العملية</string>
<string name="internal_storage">يتم تخزين الملف المضغوط في:\n[التخزين الداخلي]%1$s</string>
<string name="zip_process_title">معالجة</string>
<!--Settings Activity -->
<string name="settings_general_category">عام</string>
<string name="settings_dark_theme_title">السمة الغامقة</string>
<string name="settings_dark_theme_summary">تفعيل السمة الغامقة</string>
<string name="settings_clear_cache_title">حذف الذاكرة المؤقتة للمستودع</string>
<string name="settings_clear_cache_summary">حذف المعلومات المخزنة مؤقتا للمستودع على الانترنت، يجبر التطبيق لتحديث عبر الانترنت</string>
<string name="settings_core_only_title">Magisk الوضع الأساسي فقط</string>
<string name="settings_core_only_summary">تمكين الميزات الأساسية فقط، لن يتم تحميل جميع الإضافات. MagiskSU، MagiskHide، systemless hosts، و لا يزال ممكنا</string>
<string name="settings_magiskhide_summary">إخفاء Magisk من مختلف الاكتشافات</string>
<string name="settings_hosts_title">تمكين المضيفين(الهوست) لـ systemless</string>
<string name="settings_hosts_summary">Systemless يدعم تطبيقات حجب الإعلانات</string>
<string name="settings_su_app_adb">التطبيقات و ADB</string>
<string name="settings_su_app">التطبيقات فقط</string>
<string name="settings_su_adb">ADB فقط</string>
<string name="settings_su_disable">معطل</string>
<string name="settings_su_request_10">10 ثواني</string>
<string name="settings_su_request_20">20 ثانية</string>
<string name="settings_su_request_30">30 ثانية</string>
<string name="settings_su_request_60">60 ثانية</string>
<string name="superuser_access">Superuser صلاحيات</string>
<string name="auto_response">استجابة تلقائية</string>
<string name="request_timeout">مهلة الطلب</string>
<string name="superuser_notification">Superuser إشعارات</string>
<string name="request_timeout_summary">%1$s ثانية</string>
<string name="multiuser_mode">وضع تعدد المستخدمين</string>
<string name="settings_owner_only">مالك الجهاز فقط</string>
<string name="settings_owner_manage">إدارة مالك الجهاز</string>
<string name="settings_user_independent">مستخدم مستقل</string>
<string name="owner_only_summary">المالك فقط لديه صلاحيات الروت</string>
<string name="owner_manage_summary">يمكن للمالك فقط إدارة صلاحيات الروت وتلقي مطالبات الطلب</string>
<string name="user_indepenent_summary">كل مستخدم لديه قواعد روت منفصلة خاصة به</string>
<string name="multiuser_hint_owner_request">تم إرسال طلب إلى مالك الجهاز. يرجى التبديل إلى المالك ومنح الإذن</string>
<!--Superuser-->
<string name="su_request_title">Superuser طلبات</string>
<string name="deny_with_str">رفض%1$s</string>
<string name="deny">رفض</string>
<string name="prompt">طلب</string>
<string name="grant">سماح</string>
<string name="su_warning">منح حق الوصول الكامل إلى جهازك.\nرفض إذا كنت غير متأكد!</string>
<string name="forever">للابد</string>
<string name="once">مره</string>
<string name="tenmin">10 دقائق</string>
<string name="twentymin">20 دقائق</string>
<string name="thirtymin">30 دقائق</string>
<string name="sixtymin">60 دقائق</string>
<string name="su_allow_toast">%1$s يتم منح صلاحيات Superuser</string>
<string name="su_deny_toast">%1$s يتم رفض صلاحيات Superuser</string>
<string name="no_apps_found">لا توجد تطبيقات</string>
<string name="su_snack_grant">Superuser الصلاحيات لـ %1$s تم منحها</string>
<string name="su_snack_deny">Superuser الصلاحيات لـ %1$s تم رفضها</string>
<string name="su_snack_notif_on">الإشعارات لـ %1$s تم تفعيلها</string>
<string name="su_snack_notif_off">الإشعارات لـ %1$s تم تعطيلها</string>
<string name="su_snack_log_on">السجلات لـ %1$s تم تفعيلها</string>
<string name="su_snack_log_off">السجلات لـ %1$s تم تعطيلها</string>
<string name="su_snack_revoke">%1$s الصلاحيات سحبت</string>
<string name="su_revoke_title">سحب؟</string>
<string name="su_revoke_msg">تأكيد لسحب صلاحيات %1$s ?</string>
<string name="toast">نخب</string>
<string name="none">بدون</string>
<!--Superuser logs-->
<string name="pid">PID:\u0020</string>
<string name="target_uid">الهدف UID:\u0020</string>
<string name="command">الأمر:\u0020</string>
</resources>

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