1
mirror of https://github.com/topjohnwu/Magisk synced 2025-10-27 04:02:14 +01:00

Compare commits

..

155 Commits

Author SHA1 Message Date
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
209 changed files with 7602 additions and 4010 deletions

View File

@@ -9,11 +9,13 @@
5. (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.
1. Building is supported on macOS, Linux, and Windows using the custom NDK: [FrankeNDK](https://github.com/topjohnwu/FrankeNDK).
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.
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 `-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).
## Documentation
[Link to Documentation](docs/README.MD)
## License
@@ -31,44 +33,3 @@ 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)

View File

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

View File

@@ -1,5 +1,8 @@
apply plugin: 'com.android.application'
def configProps = new Properties()
configProps.load(new FileInputStream(rootProject.file('config.prop')))
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
@@ -8,18 +11,28 @@ android {
applicationId "com.topjohnwu.magisk"
minSdkVersion 21
targetSdkVersion rootProject.ext.compileSdkVersion
javaCompileOptions {
annotationProcessorOptions {
argument('butterknife.debuggable', 'false')
}
}
signingConfigs {
config {
storeFile rootProject.file('release-key.jks')
storePassword configProps['keyStorePass']
keyAlias configProps['keyAlias']
keyPassword configProps['keyPass']
}
}
buildTypes {
debug {
// If keystore exists, sign the APK with custom signature
if (signingConfigs.config.storeFile.exists())
signingConfig signingConfigs.config
}
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}
}
@@ -27,8 +40,13 @@ android {
productFlavors {
full {
versionCode 129
versionName "5.8.3"
versionName configProps['appVersion']
versionCode configProps['appVersionCode'] as Integer
javaCompileOptions {
annotationProcessorOptions {
argument('butterknife.debuggable', 'false')
}
}
}
stub {
versionCode 1
@@ -57,9 +75,9 @@ dependencies {
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.github.topjohnwu:libsu:2.0.1'
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'
fullAnnotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}

View File

@@ -16,8 +16,8 @@
# public *;
#}
# Keep all names, we are open source anyway :)
-keepnames class ** { *; }
# Don't obfuscate, we are open source anyway :)
-dontobfuscate
# BouncyCastle
-keep class org.bouncycastle.jcajce.provider.asymmetric.rsa.**SHA1** { *; }
@@ -26,4 +26,9 @@
-dontwarn javax.naming.**
# Gson
-keepattributes Signature
-keepattributes Signature
# Strip logging
-assumenosideeffects class com.topjohnwu.magisk.utils.Logger {
public *** debug(...);
}

View File

@@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:name=".MagiskManager"
@@ -28,8 +29,8 @@
android:name=".AboutActivity"
android:theme="@style/AppTheme.StatusBar" />
<activity
android:name=".SettingsActivity"
android:theme="@style/AppTheme.StatusBar" />
android:name=".DonationActivity"
android:theme="@style/AppTheme.StatusBar"/>
<activity
android:name=".FlashActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
@@ -66,7 +67,10 @@
</intent-filter>
</receiver>
<service android:name=".services.OnBootIntentService" />
<service
android:name=".services.OnBootService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".services.UpdateCheckService"
android:exported="true"
@@ -75,7 +79,7 @@
<!-- Hardcode GMS version -->
<meta-data
android:name="com.google.android.gms.version"
android:value="7095000" />
android:value="12451000" />
</application>

View File

@@ -1,6 +1,5 @@
package com.topjohnwu.magisk;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
@@ -11,15 +10,15 @@ 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 com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.utils.Utils;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
public class AboutActivity extends Activity {
public class AboutActivity extends BaseActivity {
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.app_version_info) AboutCardRow appVersionInfo;
@@ -27,7 +26,7 @@ public class AboutActivity extends Activity {
@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;
@BindView(R.id.follow_twitter) AboutCardRow twitter;
@Override
public int getDarkTheme() {
@@ -52,7 +51,6 @@ public class AboutActivity extends Activity {
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();
@@ -65,14 +63,9 @@ public class AboutActivity extends Activity {
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))));
appSourceCode.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.SOURCE_CODE_URL)));
supportThread.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.XDA_THREAD)));
twitter.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.TWITTER_URL)));
setFloating();
}

View File

@@ -1,11 +1,7 @@
package com.topjohnwu.magisk.utils;
package com.topjohnwu.magisk;
import android.os.Environment;
import android.os.Process;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.MagiskManager;
import java.io.File;
import java.util.Arrays;
import java.util.List;
@@ -34,21 +30,19 @@ public class Const {
public static final String BUSYBOX_PATH = "/sbin/.core/busybox";
public static final String TMP_FOLDER_PATH = "/dev/tmp";
public static final String MAGISK_LOG = "/cache/magisk.log";
public static final File EXTERNAL_PATH = new File(Environment.getExternalStorageDirectory(), "MagiskManager");
public static final String MANAGER_CONFIGS = ".tmp.magisk.config";
// Versions
public static final int UPDATE_SERVICE_VER = 1;
public static final int SNET_VER = 8;
public static int MIN_MODULE_VER() {
return MagiskManager.get().magiskVersionCode >= MAGISK_VER.REMOVE_LEGACY_LINK ? 1500 : 1400;
return Data.magiskVersionCode >= MAGISK_VER.REMOVE_LEGACY_LINK ? 1500 : 1400;
}
/* A list of apps that should not be shown as hide-able */
public static final List<String> HIDE_BLACKLIST = Arrays.asList(
"android",
MagiskManager.get().getPackageName(),
Data.MM().getPackageName(),
"com.google.android.gms"
);
@@ -59,22 +53,22 @@ public class Const {
public static final int FBE_AWARE = 1410;
public static final int RESETPROP_PERSIST = 1436;
public static final int MANAGER_HIDE = 1440;
public static final int DTBO_SUPPORT = 1446;
public static final int HIDDEN_PATH = 1460;
public static final int REMOVE_LEGACY_LINK = 1630;
public static final int SEPOL_REFACTOR = 1640;
public static final int FIX_ENV = 1650;
public static final int DBVER_SIX = 17000;
}
public static class ID {
public static final int UPDATE_SERVICE_ID = 1;
public static final int FETCH_ZIP = 2;
public static final int SELECT_BOOT = 3;
public static final int ONBOOT_SERVICE_ID = 6;
// notifications
public static final int MAGISK_UPDATE_NOTIFICATION_ID = 4;
public static final int APK_UPDATE_NOTIFICATION_ID = 5;
public static final int ONBOOT_NOTIFICATION_ID = 6;
public static final int DTBO_NOTIFICATION_ID = 7;
public static final String NOTIFICATION_CHANNEL = "magisk_notification";
}
@@ -82,11 +76,12 @@ public class Const {
public static class Url {
public static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json";
public static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/beta.json";
public static final String SNET_URL = "https://github.com/topjohnwu/magisk_files/raw/727aa3a8642bf5f0982e5ea89b3f818bd783d5a2/snet.apk";
public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&page=%d";
public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed&page=%d";
public static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s";
public static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip";
public static final String DONATION_URL = "https://www.paypal.me/topjohnwu";
public static final String PAYPAL_URL = "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=CC7FZ7526MNGG";
public static final String PATREON_URL = "https://www.patreon.com/topjohnwu";
public static final String TWITTER_URL = "https://twitter.com/topjohnwu";
public static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
public static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk";
}
@@ -108,7 +103,6 @@ public class Const {
public static final String OPEN_SECTION = "section";
public static final String INTENT_SET_FILENAME = "filename";
public static final String INTENT_SET_LINK = "link";
public static final String INTENT_PERM = "perm_dialog";
public static final String FLASH_ACTION = "action";
public static final String FLASH_SET_BOOT = "boot";
@@ -156,7 +150,7 @@ public class Const {
public static final String FLASH_ZIP = "flash";
public static final String PATCH_BOOT = "patch";
public static final String FLASH_MAGISK = "magisk";
public static final String FLASH_SECOND_SLOT = "slot";
public static final String FLASH_INACTIVE_SLOT = "slot";
public static final String UNINSTALL = "uninstall";
public static final int[] timeoutList = {0, -1, 10, 20, 30, 60};
public static final int ORDER_NAME = 0;

View File

@@ -0,0 +1,187 @@
package com.topjohnwu.magisk;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.util.Xml;
import com.topjohnwu.magisk.utils.FingerprintHelper;
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;
public class Data {
// Global app instance
public static WeakReference<MagiskManager> weakApp;
public static Handler mainHandler = new Handler(Looper.getMainLooper());
// Current status
public static String magiskVersionString;
public static int magiskVersionCode = -1;
public static boolean magiskHide;
// Update Info
public static String remoteMagiskVersionString;
public static int remoteMagiskVersionCode = -1;
public static String magiskLink;
public static String magiskNoteLink;
public static String magiskMD5;
public static String remoteManagerVersionString;
public static int remoteManagerVersionCode = -1;
public static String managerLink;
public static String managerNoteLink;
public static String uninstallerLink;
public static int snetVersionCode;
public static String snetLink;
// Install flags
public static boolean keepVerity = false;
public static boolean keepEnc = false;
// Configs
public static boolean isDarkTheme;
public static int suRequestTimeout;
public static int suLogTimeout = 14;
public static int suAccessState;
public static boolean suFingerprint;
public static int multiuserMode;
public static int suResponseType;
public static int suNotificationType;
public static int suNamespaceMode;
public static int updateChannel;
public static int repoOrder;
public static 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.isEmpty() || Integer.parseInt(s) != 0;
} catch (NumberFormatException ignored) {}
}
public static MagiskManager MM() {
return weakApp.get();
}
public static void exportPrefs() {
// Flush prefs to disk
MagiskManager mm = MM();
mm.prefs.edit().commit();
File xml = new File(mm.getFilesDir().getParent() + "/shared_prefs",
mm.getPackageName() + "_preferences.xml");
Shell.su(Utils.fmt("for usr in /data/user/*; do cat %s > ${usr}/%s; done", xml, Const.MANAGER_CONFIGS)).exec();
}
public static void importPrefs() {
MagiskManager mm = MM();
SuFile config = new SuFile(Utils.fmt("/data/user/%d/%s", Const.USER_ID, Const.MANAGER_CONFIGS));
if (config.exists()) {
SharedPreferences.Editor editor = mm.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();
}
}
public static void loadConfig() {
MagiskManager mm = MM();
// su
suRequestTimeout = Utils.getPrefsInt(mm.prefs, Const.Key.SU_REQUEST_TIMEOUT, Const.Value.timeoutList[2]);
suResponseType = Utils.getPrefsInt(mm.prefs, Const.Key.SU_AUTO_RESPONSE, Const.Value.SU_PROMPT);
suNotificationType = Utils.getPrefsInt(mm.prefs, Const.Key.SU_NOTIFICATION, Const.Value.NOTIFICATION_TOAST);
suAccessState = mm.mDB.getSettings(Const.Key.ROOT_ACCESS, Const.Value.ROOT_ACCESS_APPS_AND_ADB);
multiuserMode = mm.mDB.getSettings(Const.Key.SU_MULTIUSER_MODE, Const.Value.MULTIUSER_MODE_OWNER_ONLY);
suNamespaceMode = mm.mDB.getSettings(Const.Key.SU_MNT_NS, Const.Value.NAMESPACE_MODE_REQUESTER);
suFingerprint = mm.mDB.getSettings(Const.Key.SU_FINGERPRINT, 0) != 0;
if (suFingerprint && !FingerprintHelper.canUseFingerprint()) {
// User revoked the fingerprint
mm.mDB.setSettings(Const.Key.SU_FINGERPRINT, 0);
suFingerprint = false;
}
// config
isDarkTheme = mm.prefs.getBoolean(Const.Key.DARK_THEME, false);
updateChannel = Utils.getPrefsInt(mm.prefs, Const.Key.UPDATE_CHANNEL, Const.Value.STABLE_CHANNEL);
repoOrder = mm.prefs.getInt(Const.Key.REPO_ORDER, Const.Value.ORDER_DATE);
}
public static void writeConfig() {
MM().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())
.putBoolean(Const.Key.SU_FINGERPRINT, suFingerprint)
.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))
.putInt(Const.Key.UPDATE_SERVICE_VER, Const.UPDATE_SERVICE_VER)
.putInt(Const.Key.REPO_ORDER, repoOrder)
.apply();
}
}

View File

@@ -0,0 +1,45 @@
package com.topjohnwu.magisk;
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 com.topjohnwu.magisk.components.AboutCardRow;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.utils.Utils;
import butterknife.BindView;
import butterknife.ButterKnife;
public class DonationActivity extends BaseActivity {
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.paypal) AboutCardRow paypal;
@BindView(R.id.patreon) AboutCardRow patreon;
@Override
public int getDarkTheme() {
return R.style.AppTheme_StatusBar_Dark;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_donation);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setTitle(R.string.donation);
ab.setDisplayHomeAsUpEnabled(true);
}
paypal.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.PAYPAL_URL)));
patreon.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.PATREON_URL)));
}
}

View File

@@ -1,9 +1,9 @@
package com.topjohnwu.magisk;
import android.Manifest;
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;
@@ -16,9 +16,10 @@ 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.components.BaseActivity;
import com.topjohnwu.magisk.utils.Download;
import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.CallbackList;
import com.topjohnwu.superuser.Shell;
@@ -34,7 +35,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class FlashActivity extends Activity {
public class FlashActivity extends BaseActivity {
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.txtLog) TextView flashLogs;
@@ -51,30 +52,31 @@ public class FlashActivity extends Activity {
@OnClick(R.id.reboot)
void reboot() {
Shell.Async.su("/system/bin/reboot");
Shell.su("/system/bin/reboot").submit();
}
@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));
runWithPermission(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, () -> {
Calendar now = Calendar.getInstance();
String filename = String.format(Locale.US,
"magisk_install_log_%04d%02d%02d_%02d%02d%02d.log",
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
File logFile = new File(Const.EXTERNAL_PATH + "/logs", filename);
logFile.getParentFile().mkdirs();
try (FileWriter writer = new FileWriter(logFile)) {
for (String s : logs) {
writer.write(s);
writer.write('\n');
File logFile = new File(Download.EXTERNAL_PATH, filename);
try (FileWriter writer = new FileWriter(logFile)) {
for (String s : logs) {
writer.write(s);
writer.write('\n');
}
} catch (IOException e) {
e.printStackTrace();
return;
}
} catch (IOException e) {
e.printStackTrace();
return;
}
MagiskManager.toast(logFile.getPath(), Toast.LENGTH_LONG);
Utils.toast(logFile.getPath(), Toast.LENGTH_LONG);
});
}
@Override
@@ -99,11 +101,23 @@ public class FlashActivity extends Activity {
logs = new ArrayList<>();
CallbackList<String> console = new CallbackList<String>(new ArrayList<>()) {
private void updateUI() {
flashLogs.setText(TextUtils.join("\n", this));
sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10);
}
@Override
public void onAddElement(String s) {
logs.add(s);
flashLogs.setText(TextUtils.join("\n", this));
sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10);
updateUI();
}
@Override
public String set(int i, String s) {
String ret = super.set(i, s);
Data.mainHandler.post(this::updateUI);
return ret;
}
};
@@ -119,13 +133,13 @@ public class FlashActivity extends Activity {
new UninstallMagisk(this, uri, console, logs).exec();
break;
case Const.Value.FLASH_MAGISK:
new InstallMagisk(this, console, logs, uri, InstallMagisk.DIRECT_MODE).exec();
new InstallMagisk(this, console, logs, InstallMagisk.DIRECT_MODE).exec();
break;
case Const.Value.FLASH_SECOND_SLOT:
new InstallMagisk(this, console, logs, uri, InstallMagisk.SECOND_SLOT_MODE).exec();
case Const.Value.FLASH_INACTIVE_SLOT:
new InstallMagisk(this, console, logs, InstallMagisk.SECOND_SLOT_MODE).exec();
break;
case Const.Value.PATCH_BOOT:
new InstallMagisk(this, console, logs, uri,
new InstallMagisk(this, console, logs,
intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT)).exec();
break;
}
@@ -138,14 +152,14 @@ public class FlashActivity extends Activity {
private static class UninstallMagisk extends FlashZip {
private UninstallMagisk(Activity context, Uri uri, List<String> console, List<String> logs) {
private UninstallMagisk(BaseActivity 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(() ->
Data.mainHandler.postDelayed(() ->
RootUtils.uninstallPkg(getActivity().getPackageName()), 3000);
} else {
super.onPostExecute(result);

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@ 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;
@@ -15,24 +14,30 @@ 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.components.BaseActivity;
import com.topjohnwu.magisk.fragments.LogFragment;
import com.topjohnwu.magisk.fragments.MagiskFragment;
import com.topjohnwu.magisk.fragments.MagiskHideFragment;
import com.topjohnwu.magisk.fragments.ModulesFragment;
import com.topjohnwu.magisk.fragments.ReposFragment;
import com.topjohnwu.magisk.fragments.SettingsFragment;
import com.topjohnwu.magisk.fragments.SuperuserFragment;
import com.topjohnwu.magisk.utils.Download;
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
public class MainActivity extends BaseActivity
implements NavigationView.OnNavigationItemSelectedListener, Topic.Subscriber {
private final Handler mDrawerHandler = new Handler();
private int mDrawerItem;
private boolean fromShortcut = true;
private static boolean fromShortcut = false;
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.drawer_layout) DrawerLayout drawer;
@BindView(R.id.toolbar) public Toolbar toolbar;
@BindView(R.id.nav_view) public NavigationView navigationView;
private float toolbarElevation;
@@ -44,24 +49,11 @@ public class MainActivity extends Activity
@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);
startActivity(new Intent(this, SplashActivity.class));
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);
@@ -86,8 +78,11 @@ public class MainActivity extends Activity
drawer.addDrawerListener(toggle);
toggle.syncState();
if (savedInstanceState == null)
navigate(getIntent().getStringExtra(Const.Key.OPEN_SECTION));
if (savedInstanceState == null) {
String section = getIntent().getStringExtra(Const.Key.OPEN_SECTION);
fromShortcut = section != null;
navigate(section);
}
navigationView.setNavigationItemSelectedListener(this);
}
@@ -118,28 +113,26 @@ public class MainActivity extends Activity
}
@Override
public void onTopicPublished(Topic topic) {
recreate();
public int[] getSubscribedTopics() {
return new int[] {Topic.RELOAD_ACTIVITY};
}
@Override
public Topic[] getSubscription() {
return new Topic[] { getMagiskManager().reloadActivity };
public void onPublish(int topic, Object[] result) {
recreate();
}
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.magiskhide).setVisible(Shell.rootAccess() &&
Data.magiskVersionCode >= Const.MAGISK_VER.UNIFIED &&
mm.prefs.getBoolean(Const.Key.MAGISKHIDE, false));
menu.findItem(R.id.modules).setVisible(Shell.rootAccess() && Data.magiskVersionCode >= 0);
menu.findItem(R.id.downloads).setVisible(Download.checkNetworkStatus(this)
&& Shell.rootAccess() && Data.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));
!(Const.USER_ID > 0 && Data.multiuserMode == Const.Value.MULTIUSER_MODE_OWNER_MANAGED));
}
public void navigate(String item) {
@@ -167,6 +160,9 @@ public class MainActivity extends Activity
case "about":
itemId = R.id.app_about;
break;
case "donation":
itemId = R.id.donation;
break;
}
}
navigate(itemId);
@@ -197,13 +193,16 @@ public class MainActivity extends Activity
displayFragment(new LogFragment(), false);
break;
case R.id.settings:
startActivity(new Intent(this, SettingsActivity.class));
mDrawerItem = bak;
displayFragment(new SettingsFragment(), true);
break;
case R.id.app_about:
startActivity(new Intent(this, AboutActivity.class));
mDrawerItem = bak;
break;
case R.id.donation:
startActivity(new Intent(this, DonationActivity.class));
mDrawerItem = bak;
break;
}
}

View File

@@ -1,23 +1,10 @@
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);
}
}
import com.topjohnwu.magisk.components.BaseActivity;
public class NoUIActivity extends BaseActivity {
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);

File diff suppressed because it is too large Load Diff

View File

@@ -7,33 +7,34 @@ 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.components.BaseActivity;
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.Download;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
public class SplashActivity extends Activity {
public class SplashActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RootUtils.init();
MagiskManager mm = getMagiskManager();
// Magisk working as expected
if (Shell.rootAccess() && Data.magiskVersionCode > 0) {
// Update check service
Utils.setupUpdateCheck();
// Load modules
Utils.loadModules();
}
mm.repoDB = new RepoDatabaseHelper(this);
mm.loadMagiskInfo();
mm.getDefaultInstallFlags();
mm.loadPrefs();
Data.importPrefs();
// Dynamic detect all locales
new LoadLocale().exec();
LocaleManager.loadAvailableLocales();
// Create notification channel on Android O
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -45,44 +46,22 @@ public class SplashActivity extends Activity {
// Setup shortcuts
sendBroadcast(new Intent(this, ShortcutReceiver.class));
LoadModules loadModuleTask = new LoadModules();
if (Utils.checkNetworkStatus()) {
if (Download.checkNetworkStatus(this)) {
// 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();
CheckUpdates.check();
// Repo update check
new UpdateRepos().exec();
}
// Write back default values
mm.writeConfig();
Data.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));
intent.putExtra(BaseActivity.INTENT_PERM, getIntent().getStringExtra(BaseActivity.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,7 +1,12 @@
package com.topjohnwu.magisk.adapters;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.LayoutInflater;
@@ -12,10 +17,10 @@ import android.widget.Filter;
import android.widget.ImageView;
import android.widget.TextView;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.superuser.Shell;
import java.util.ArrayList;
@@ -33,36 +38,73 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
private PackageManager pm;
private ApplicationFilter filter;
public ApplicationAdapter() {
public ApplicationAdapter(Context context) {
fullList = showList = Collections.emptyList();
hideList = Collections.emptyList();
filter = new ApplicationFilter();
pm = MagiskManager.get().getPackageManager();
new LoadApps().exec();
pm = context.getPackageManager();
AsyncTask.THREAD_POOL_EXECUTOR.execute(this::loadApps);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_app, parent, false);
return new ViewHolder(v);
}
private String getLabel(ApplicationInfo info) {
if (info.labelRes > 0) {
try {
Resources res = pm.getResourcesForApplication(info);
Configuration config = new Configuration();
config.setLocale(LocaleManager.locale);
res.updateConfiguration(config, res.getDisplayMetrics());
return res.getString(info.labelRes);
} catch (PackageManager.NameNotFoundException ignored) { /* Impossible */ }
}
return info.loadLabel(pm).toString();
}
private void loadApps() {
fullList = pm.getInstalledApplications(0);
hideList = Shell.su("magiskhide --ls").exec().getOut();
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 getLabel(a).toLowerCase().compareTo(getLabel(b).toLowerCase());
} else if (ah) {
return -1;
} else {
return 1;
}
});
Topic.publish(false, Topic.MAGISK_HIDE_DONE);
}
@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) {
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
ApplicationInfo info = showList.get(position);
holder.appIcon.setImageDrawable(info.loadIcon(pm));
holder.appName.setText(info.loadLabel(pm));
holder.appName.setText(getLabel(info));
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);
Shell.su("magiskhide --add " + info.packageName).submit();
hideList.add(info.packageName);
} else {
Shell.Async.su("magiskhide --rm " + info.packageName);
Shell.su("magiskhide --rm " + info.packageName).submit();
hideList.remove(info.packageName);
}
});
@@ -78,7 +120,7 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
}
public void refresh() {
new LoadApps().exec();
AsyncTask.THREAD_POOL_EXECUTOR.execute(this::loadApps);
}
static class ViewHolder extends RecyclerView.ViewHolder {
@@ -108,7 +150,7 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
showList = new ArrayList<>();
String filter = constraint.toString().toLowerCase();
for (ApplicationInfo info : fullList) {
if (lowercaseContains(info.loadLabel(pm).toString(), filter)
if (lowercaseContains(getLabel(info), filter)
|| lowercaseContains(info.packageName, filter)) {
showList.add(info);
}
@@ -122,37 +164,4 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
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

@@ -12,7 +12,7 @@ import android.widget.Switch;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.CustomAlertDialog;
import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.container.Policy;
@@ -93,7 +93,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
dbHelper.updatePolicy(policy);
}
});
holder.delete.setOnClickListener(v -> new AlertDialogBuilder((Activity) v.getContext())
holder.delete.setOnClickListener(v -> new CustomAlertDialog((Activity) v.getContext())
.setTitle(R.string.su_revoke_title)
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
.setPositiveButton(R.string.yes, (dialog, which) -> {

View File

@@ -1,6 +1,5 @@
package com.topjohnwu.magisk.adapters;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
@@ -16,11 +15,11 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.components.CustomAlertDialog;
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;
@@ -98,21 +97,18 @@ public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, R
holder.updateTime.setText(context.getString(R.string.updated_on, repo.getLastUpdateString()));
holder.infoLayout.setOnClickListener(v ->
new MarkDownWindow((Activity) context, null, repo.getDetailUrl()).exec());
new MarkDownWindow((BaseActivity) context, null, repo.getDetailUrl()).exec());
holder.downloadImage.setOnClickListener(v -> {
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
new AlertDialogBuilder((Activity) context)
new CustomAlertDialog((BaseActivity) context)
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
.setMessage(context.getString(R.string.repo_install_msg, filename))
.setMessage(context.getString(R.string.repo_install_msg, repo.getDownloadFilename()))
.setCancelable(true)
.setPositiveButton(R.string.install, (d, i) ->
new ProcessRepoZip((Activity) context, repo.getZipUrl(),
Utils.getLegalFilename(filename), true).exec()
new ProcessRepoZip((BaseActivity) context, repo, true).exec()
)
.setNeutralButton(R.string.download, (d, i) ->
new ProcessRepoZip((Activity) context, repo.getZipUrl(),
Utils.getLegalFilename(filename), false).exec())
new ProcessRepoZip((BaseActivity) context, repo, false).exec())
.setNegativeButton(R.string.no_thanks, null)
.show();
});

View File

@@ -2,9 +2,9 @@ package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.Data;
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.WebService;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
@@ -19,10 +19,10 @@ import java.net.HttpURLConnection;
import dalvik.system.DexClassLoader;
public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
public class CheckSafetyNet extends ParallelTask<Void, Void, Void> {
public static final File dexPath =
new File(MagiskManager.get().getFilesDir().getParent() + "/snet", "snet.apk");
new File(Data.MM().getFilesDir().getParent() + "/snet", "snet.apk");
private ISafetyNetHelper helper;
public CheckSafetyNet(Activity activity) {
@@ -30,9 +30,9 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
}
private void dlSnet() throws Exception {
Shell.Sync.sh("rm -rf " + dexPath.getParent());
Shell.sh("rm -rf " + dexPath.getParent()).exec();
dexPath.getParentFile().mkdir();
HttpURLConnection conn = WebService.request(Const.Url.SNET_URL, null);
HttpURLConnection conn = WebService.mustRequest(Data.snetLink, null);
try (
OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath));
InputStream in = new BufferedInputStream(conn.getInputStream())) {
@@ -45,17 +45,19 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
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) {
Class<?> clazz = loader.loadClass("com.topjohnwu.snet.Snet");
helper = (ISafetyNetHelper) clazz.getMethod("newHelper",
Class.class, String.class, Activity.class, Object.class)
.invoke(null, ISafetyNetHelper.class, dexPath.getPath(), getActivity(),
(ISafetyNetHelper.Callback) code ->
Topic.publish(false, Topic.SNET_CHECK_DONE, code));
if (helper.getVersion() < Data.snetVersionCode) {
throw new Exception();
}
}
@Override
protected Exception doInBackground(Void... voids) {
protected Void doInBackground(Void... voids) {
try {
try {
dyload();
@@ -64,21 +66,12 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
dlSnet();
dyload();
}
// Run attestation
helper.attest();
} catch (Exception e) {
return e;
e.printStackTrace();
Topic.publish(false, Topic.SNET_CHECK_DONE, -1);
}
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,31 +1,50 @@
package com.topjohnwu.magisk.asyncs;
import android.os.AsyncTask;
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.Const;
import com.topjohnwu.magisk.Data;
import com.topjohnwu.magisk.utils.NotificationMgr;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.WebService;
import org.json.JSONException;
import org.json.JSONObject;
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
public class CheckUpdates {
private boolean showNotification;
public CheckUpdates() {
this(false);
private static int getInt(JSONObject json, String name, int defValue) {
if (json == null)
return defValue;
try {
return json.getInt(name);
} catch (JSONException e) {
return defValue;
}
}
public CheckUpdates(boolean b) {
showNotification = b;
private static String getString(JSONObject json, String name, String defValue) {
if (json == null)
return defValue;
try {
return json.getString(name);
} catch (JSONException e) {
return defValue;
}
}
@Override
protected Void doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
private static JSONObject getJson(JSONObject json, String name) {
try {
return json.getJSONObject(name);
} catch (JSONException e) {
return null;
}
}
public static void fetchUpdates() {
String jsonStr = "";
switch (mm.updateChannel) {
switch (Data.updateChannel) {
case Const.Value.STABLE_CHANNEL:
jsonStr = WebService.getString(Const.Url.STABLE_URL);
break;
@@ -33,38 +52,54 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
jsonStr = WebService.getString(Const.Url.BETA_URL);
break;
case Const.Value.CUSTOM_CHANNEL:
jsonStr = WebService.getString(mm.prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
jsonStr = WebService.getString(Data.MM().prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
break;
}
JSONObject json;
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;
json = new JSONObject(jsonStr);
} catch (JSONException e) {
return;
}
JSONObject magisk = getJson(json, "magisk");
Data.remoteMagiskVersionString = getString(magisk, "version", null);
Data.remoteMagiskVersionCode = getInt(magisk, "versionCode", -1);
Data.magiskLink = getString(magisk, "link", null);
Data.magiskNoteLink = getString(magisk, "note", null);
Data.magiskMD5 = getString(magisk, "md5", null);
JSONObject manager = getJson(json, "app");
Data.remoteManagerVersionString = getString(manager, "version", null);
Data.remoteManagerVersionCode = getInt(manager, "versionCode", -1);
Data.managerLink = getString(manager, "link", null);
Data.managerNoteLink = getString(manager, "note", null);
JSONObject uninstaller = getJson(json, "uninstaller");
Data.uninstallerLink = getString(uninstaller, "link", null);
JSONObject snet = getJson(json, "snet");
Data.snetVersionCode = getInt(snet, "versionCode", -1);
Data.snetLink = getString(snet, "link", 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();
public static void check(Runnable cb) {
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
fetchUpdates();
if (cb != null) {
if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) {
NotificationMgr.managerUpdate();
} else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) {
NotificationMgr.magiskUpdate();
}
cb.run();
}
}
mm.updateCheckDone.publish();
super.onPostExecute(v);
Topic.publish(Topic.UPDATE_CHECK_DONE);
});
}
public static void check() {
check(null);
}
}

View File

@@ -2,13 +2,13 @@ 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.Const;
import com.topjohnwu.magisk.Data;
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;
@@ -45,7 +45,7 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
@Override
protected Integer doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
MagiskManager mm = Data.MM();
try {
console.add("- Copying zip to temp directory");
@@ -66,12 +66,10 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
}
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!"))
if (!Shell.su("cd " + mCachedFile.getParent(),
"BOOTMODE=true sh update-binary dummy 1 " + mCachedFile)
.to(console, logs)
.exec().isSuccess())
return -1;
} catch (Exception e) {
@@ -86,10 +84,7 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
@Override
protected void onPostExecute(Integer result) {
FlashActivity activity = (FlashActivity) getActivity();
Shell.Async.su(
"rm -rf " + mCachedFile.getParent(),
"rm -rf " + Const.TMP_FOLDER_PATH
);
Shell.su("rm -rf " + mCachedFile.getParent(), "rm -rf " + Const.TMP_FOLDER_PATH).submit();
switch (result) {
case -1:
console.add("! Installation failed");
@@ -99,8 +94,8 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
console.add("! This zip is not a Magisk Module!");
break;
case 1:
// Success
new LoadModules().exec();
// Reload modules
Utils.loadModules();
break;
}
activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE);

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

@@ -4,6 +4,7 @@ import android.app.Activity;
import android.support.v7.app.AlertDialog;
import android.webkit.WebView;
import com.topjohnwu.magisk.Data;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.WebService;
@@ -38,7 +39,7 @@ public class MarkDownWindow extends ParallelTask<Void, Void, String> {
@Override
protected String doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
MagiskManager mm = Data.MM();
String md;
if (mUrl != null) {
md = WebService.getString(mUrl);
@@ -54,9 +55,9 @@ public class MarkDownWindow extends ParallelTask<Void, Void, String> {
}
String css;
try (
InputStream in = mm.getResources().openRawResource(
mm.isDarkTheme ? R.raw.dark : R.raw.light);
ByteArrayOutputStream out = new ByteArrayOutputStream()
InputStream in = mm.getResources().openRawResource(
Data.isDarkTheme ? R.raw.dark : R.raw.light);
ByteArrayOutputStream out = new ByteArrayOutputStream()
) {
ShellUtils.pump(in, out);
css = out.toString();

View File

@@ -9,8 +9,6 @@ public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<P
private WeakReference<Activity> weakActivity;
private Runnable callback = null;
public ParallelTask() {}
public ParallelTask(Activity context) {
@@ -22,18 +20,7 @@ public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<P
}
@SuppressWarnings("unchecked")
public ParallelTask<Params, Progress, Result> exec(Params... params) {
public void 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

@@ -0,0 +1,153 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.widget.Toast;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.Data;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.magisk.utils.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.security.SecureRandom;
import java.util.jar.JarEntry;
public class PatchAPK {
private static 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();
}
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;
}
private static boolean patchAndHide() {
MagiskManager mm = Data.MM();
// 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 {
JarMap apk = new JarMap(mm.getPackageCodePath());
if (!patchPackageID(apk, Const.ORIG_PKG_NAME, pkg))
return false;
SignAPK.sign(apk, new SuFileOutputStream(repack));
} catch (Exception e) {
return false;
}
// Install the application
if (!ShellUtils.fastCmdResult("pm install " + repack))
return false;
repack.delete();
mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
Data.exportPrefs();
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);
return true;
}
public static boolean patchPackageID(JarMap apk, String from, String to) {
try {
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);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public static void hideManager(Activity activity) {
ProgressDialog dialog = ProgressDialog.show(activity,
activity.getString(R.string.hide_manager_toast),
activity.getString(R.string.hide_manager_toast2));
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
boolean b = patchAndHide();
Data.mainHandler.post(() -> {
dialog.cancel();
if (!b) {
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
}
});
});
}
}

View File

@@ -1,19 +1,21 @@
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.Const;
import com.topjohnwu.magisk.Data;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.utils.Download;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.WebService;
import com.topjohnwu.magisk.utils.ZipUtils;
import com.topjohnwu.superuser.Shell;
@@ -37,17 +39,15 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
private ProgressDialog progressDialog;
private boolean mInstall;
private String mLink;
private File mFile;
private Repo mRepo;
private int progress = 0, total = -1;
private Handler mHandler;
public ProcessRepoZip(Activity context, String link, String filename, boolean install) {
public ProcessRepoZip(BaseActivity context, Repo repo, boolean install) {
super(context);
mLink = link;
mFile = new File(Const.EXTERNAL_PATH, filename);
mInstall = install;
mHandler = new Handler();
mRepo = repo;
mInstall = install && Shell.rootAccess();
mFile = new File(Download.EXTERNAL_PATH, repo.getDownloadFilename());
}
private void removeTopFolder(File input, File output) throws IOException {
@@ -74,28 +74,26 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
}
}
@Override
protected BaseActivity getActivity() {
return (BaseActivity) super.getActivity();
}
@Override
protected void onPreExecute() {
Activity activity = getActivity();
BaseActivity 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();
BaseActivity 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);
HttpURLConnection conn = WebService.mustRequest(mRepo.getZipUrl(), null);
total = conn.getContentLength();
// Temp files
File temp1 = new File(activity.getCacheDir(), "1.zip");
@@ -112,7 +110,7 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
}
conn.disconnect();
mHandler.post(() -> {
Data.mainHandler.post(() -> {
progressDialog.setTitle(R.string.zip_process_title);
progressDialog.setMessage(getActivity().getString(R.string.zip_process_msg));
});
@@ -136,12 +134,12 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
@Override
protected void onPostExecute(Boolean result) {
Activity activity = getActivity();
BaseActivity activity = getActivity();
if (activity == null) return;
progressDialog.dismiss();
if (result) {
Uri uri = Uri.fromFile(mFile);
if (Shell.rootAccess() && mInstall) {
if (mInstall) {
Intent intent = new Intent(activity, FlashActivity.class);
intent.setData(uri).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
activity.startActivity(intent);
@@ -149,17 +147,15 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
SnackbarMaker.showUri(activity, uri);
}
} else {
MagiskManager.toast(R.string.process_error, Toast.LENGTH_LONG);
Utils.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;
public void exec(Void... voids) {
getActivity().runWithPermission(
new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, super::exec);
}
private class ProgressInputStream extends FilterInputStream {
@@ -170,14 +166,15 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
private void updateDlProgress(int step) {
progress += step;
progressDialog.setMessage(getActivity().getString(R.string.zip_download_msg, (int) (100 * (double) progress / total + 0.5)));
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));
Data.mainHandler.post(() -> updateDlProgress(1));
}
return b;
}
@@ -191,7 +188,7 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
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));
Data.mainHandler.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

@@ -28,19 +28,18 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* @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;
@BindView(android.R.id.title) TextView mTitle;
@BindView(android.R.id.summary) TextView mSummary;
@BindView(android.R.id.icon) ImageView mIcon;
@BindView(R.id.container) View mView;
public AboutCardRow(Context context) {
this(context, null);
@@ -53,21 +52,17 @@ public class AboutCardRow extends LinearLayout {
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);
ButterKnife.bind(this, this);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AboutCardRow, 0, 0);
String title;
Drawable icon;
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);
}
@@ -80,10 +75,7 @@ public class AboutCardRow extends LinearLayout {
}
public void setSummary(String s) {
mSummary.setVisibility(VISIBLE);
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;
}
}

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