mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 09:57:29 +00:00
Compare commits
83 Commits
manager-v5
...
manager-v5
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ea6552615d | ||
![]() |
4bf3287fce | ||
![]() |
832c2034c2 | ||
![]() |
b0aa26e1f1 | ||
![]() |
e52baeb967 | ||
![]() |
8268eb9a83 | ||
![]() |
3cc458abd9 | ||
![]() |
337b4c4268 | ||
![]() |
001f8657f6 | ||
![]() |
ea884e7fa1 | ||
![]() |
1b1394cf5d | ||
![]() |
1eef930dbb | ||
![]() |
1e175e74ed | ||
![]() |
75a46c365e | ||
![]() |
8e7b8825f5 | ||
![]() |
2ecbca303b | ||
![]() |
8195a4d616 | ||
![]() |
7ba40f925f | ||
![]() |
345cd1795f | ||
![]() |
959aaee045 | ||
![]() |
53477f0f59 | ||
![]() |
5716218f41 | ||
![]() |
9df6b9d5c0 | ||
![]() |
ec46031d36 | ||
![]() |
55b84d166a | ||
![]() |
34ae8bacec | ||
![]() |
cb4e5ca0f7 | ||
![]() |
0ba45468c4 | ||
![]() |
710502784e | ||
![]() |
0275a8558d | ||
![]() |
58acc75cf6 | ||
![]() |
874ababb9f | ||
![]() |
3771e6b0cd | ||
![]() |
33eaefa966 | ||
![]() |
cd7e236d57 | ||
![]() |
54c0b7c7d5 | ||
![]() |
a2177daec2 | ||
![]() |
628386b453 | ||
![]() |
b222bfb3e0 | ||
![]() |
ab199d883d | ||
![]() |
356065d1ee | ||
![]() |
76e7c5623d | ||
![]() |
085fba050a | ||
![]() |
295334d3ac | ||
![]() |
36124ddca4 | ||
![]() |
bd6585765e | ||
![]() |
c325deb4ed | ||
![]() |
73bb0b10ee | ||
![]() |
72820b162c | ||
![]() |
89e5b8d057 | ||
![]() |
da4f53ebbb | ||
![]() |
8458553b74 | ||
![]() |
55ecc41d06 | ||
![]() |
28fcdf2cbb | ||
![]() |
24087679a8 | ||
![]() |
5ac6a8cb4a | ||
![]() |
668d85d14e | ||
![]() |
c11a3dc95c | ||
![]() |
56f57c20a2 | ||
![]() |
240d14779a | ||
![]() |
3550d1e61c | ||
![]() |
6513ad249c | ||
![]() |
50297b1880 | ||
![]() |
f189b78b9e | ||
![]() |
5c0250f495 | ||
![]() |
2093f726e9 | ||
![]() |
10efe3859d | ||
![]() |
6933bcf7bb | ||
![]() |
2ea046cd80 | ||
![]() |
f4097a372b | ||
![]() |
87ea2a2bef | ||
![]() |
cc14a1c361 | ||
![]() |
bcdface60d | ||
![]() |
4dc9419d2e | ||
![]() |
d2bcac813e | ||
![]() |
080c37a7f6 | ||
![]() |
f9a3838db6 | ||
![]() |
1e61db104b | ||
![]() |
30a9c7718d | ||
![]() |
34b052b5d3 | ||
![]() |
aaa12853ad | ||
![]() |
b0ab55b0bf | ||
![]() |
d2f8496f4e |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,3 +6,6 @@
|
||||
app/release
|
||||
*.hprof
|
||||
app/.externalNativeBuild/
|
||||
*.sh
|
||||
public.certificate.x509.pem
|
||||
private.key.pk8
|
||||
|
11
README.md
11
README.md
@@ -1,6 +1,7 @@
|
||||
# Magisk Manager
|
||||
You need to install CMake and NDK to build the zipadjust library for zip preprocessing
|
||||
# Magisk Manager
|
||||
This is one of the submodules used in Magisk. The project is licensed under GPL v3 (or newer).
|
||||
More info are written in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk)
|
||||
|
||||
## Pre-built Binaries
|
||||
Busybox (arm and x86) compiled by osm0sis (`libbusybox.so` under `app\src\main\jniLibs`)
|
||||
Source and more info: [osm0sis' Odds and Ends](https://forum.xda-developers.com/showthread.php?t=2239421)
|
||||
## Building Notes
|
||||
You need to install CMake and NDK to build the zipadjust library.
|
||||
There are several files required to let Magisk Manager work properly, and they can be copied by using the build script in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk). These files are: `magisk_uninstaller.sh`, `util_functions.sh`, `public.certificate.x509.pem`, and `private.key.pk8` under the `app/src/main/assets` folder.
|
||||
|
@@ -2,17 +2,22 @@ apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion "26.0.0"
|
||||
buildToolsVersion "26.0.1"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.topjohnwu.magisk"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 26
|
||||
versionCode 44
|
||||
versionName "5.0.4"
|
||||
versionCode 52
|
||||
versionName "5.2.0"
|
||||
ndk {
|
||||
moduleName 'zipadjust'
|
||||
abiFilters 'x86', 'armeabi-v7a'
|
||||
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
||||
}
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
argument('butterknife.debuggable', 'false')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,16 +53,14 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.android.support:recyclerview-v7:26.0.0-beta2'
|
||||
implementation 'com.android.support:cardview-v7:26.0.0-beta2'
|
||||
implementation 'com.android.support:design:26.0.0-beta2'
|
||||
implementation 'com.android.support:support-v4:26.0.0-beta2'
|
||||
implementation 'com.jakewharton:butterknife:8.6.0'
|
||||
implementation 'com.thoughtbot:expandablerecyclerview:1.4'
|
||||
implementation 'us.feras.mdv:markdownview:1.1.0'
|
||||
implementation 'com.madgag.spongycastle:core:1.54.0.0'
|
||||
implementation 'com.madgag.spongycastle:prov:1.54.0.0'
|
||||
implementation 'com.madgag.spongycastle:pkix:1.54.0.0'
|
||||
implementation 'com.android.support:recyclerview-v7:26.0.0'
|
||||
implementation 'com.android.support:cardview-v7:26.0.0'
|
||||
implementation 'com.android.support:design:26.0.0'
|
||||
implementation 'com.android.support:support-v4:26.0.0'
|
||||
implementation 'com.jakewharton:butterknife:8.8.1'
|
||||
implementation 'com.atlassian.commonmark:commonmark:0.9.0'
|
||||
implementation 'org.bouncycastle:bcprov-jdk15on:1.57'
|
||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.57'
|
||||
implementation 'com.google.android.gms:play-services-safetynet:9.0.1'
|
||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'
|
||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
|
||||
}
|
||||
|
4
app/proguard-rules.pro
vendored
4
app/proguard-rules.pro
vendored
@@ -16,8 +16,8 @@
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# SpongyCastle
|
||||
-keep class org.spongycastle.** { *; }
|
||||
# BouncyCastle
|
||||
-keep class org.bouncycastle.** { *; }
|
||||
-dontwarn javax.naming.**
|
||||
|
||||
-dontwarn android.content.**
|
||||
|
@@ -1,14 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
package="com.topjohnwu.magisk"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.topjohnwu.magisk">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<application
|
||||
android:name=".MagiskManager"
|
||||
@@ -21,8 +21,7 @@
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="true"/>
|
||||
|
||||
android:exported="true" />
|
||||
<activity
|
||||
android:name=".SplashActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
@@ -30,16 +29,22 @@
|
||||
android:theme="@style/SplashTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".AboutActivity"
|
||||
android:theme="@style/AppTheme.Transparent"/>
|
||||
android:theme="@style/AppTheme.Transparent" />
|
||||
<activity
|
||||
android:name=".SettingsActivity"
|
||||
android:theme="@style/AppTheme.Transparent" />
|
||||
<activity
|
||||
android:name=".FlashActivity"
|
||||
android:screenOrientation="nosensor"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:theme="@style/AppTheme.Transparent" />
|
||||
|
||||
<activity
|
||||
android:name=".superuser.RequestActivity"
|
||||
android:excludeFromRecents="true"
|
||||
@@ -53,29 +58,26 @@
|
||||
android:theme="@style/SuRequest" />
|
||||
|
||||
<receiver android:name=".superuser.SuReceiver" />
|
||||
|
||||
<receiver android:name=".receivers.BootReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".receivers.PackageReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||
<action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
|
||||
|
||||
<data android:scheme="package" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".receivers.ManagerUpdate" />
|
||||
|
||||
<service android:name=".services.OnBootIntentService" />
|
||||
|
||||
<service
|
||||
android:name=".services.UpdateCheckService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||
android:exported="true" />
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
@@ -93,4 +95,4 @@
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
@@ -1,137 +0,0 @@
|
||||
#!/system/bin/sh
|
||||
##########################################################################################
|
||||
#
|
||||
# Magisk Uninstaller
|
||||
# by topjohnwu
|
||||
#
|
||||
# This script can be placed in /cache/magisk_uninstaller.sh
|
||||
# The Magisk main binary will pick up the script, and uninstall itself, following a reboot
|
||||
# This script can also be used in flashable zip with the uninstaller_loader.sh
|
||||
#
|
||||
# This script will try to do restoration with the following:
|
||||
# 1-1. Find and restore the original stock boot image dump (OTA proof)
|
||||
# 1-2. If 1-1 fails, restore ramdisk from the internal backup
|
||||
# (ramdisk fully restored, not OTA friendly)
|
||||
# 1-3. If 1-2 fails, it will remove added files in ramdisk, however modified files
|
||||
# are remained modified, because we have no backups. By doing so, Magisk will
|
||||
# not be started at boot, but this isn't actually 100% cleaned up
|
||||
# 2. Remove all Magisk related files
|
||||
# (The list is LARGE, most likely due to bad decision in early versions
|
||||
# the latest versions has much less bloat to cleanup)
|
||||
#
|
||||
##########################################################################################
|
||||
|
||||
# Call ui_print_wrap if exists, or else simply use echo
|
||||
# Useful when wrapped in flashable zip
|
||||
ui_print_wrap() {
|
||||
type ui_print >/dev/null 2>&1 && ui_print "$1" || echo "$1"
|
||||
}
|
||||
|
||||
# Call abort if exists, or else show error message and exit
|
||||
# Essential when wrapped in flashable zip
|
||||
abort_wrap() {
|
||||
type abort >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
ui_print_wrap "$1"
|
||||
exit 1
|
||||
else
|
||||
abort "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ ! -d $MAGISKBIN -o ! -f $MAGISKBIN/magiskboot -o ! -f $MAGISKBIN/util_functions.sh ]; then
|
||||
ui_print_wrap "! Cannot find $MAGISKBIN"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -z $BOOTMODE ] && BOOTMODE=false
|
||||
|
||||
MAGISKBIN=/data/magisk
|
||||
CHROMEDIR=$MAGISKBIN/chromeos
|
||||
|
||||
# Default permissions
|
||||
umask 022
|
||||
|
||||
# Load utility functions
|
||||
. $MAGISKBIN/util_functions.sh
|
||||
|
||||
# Find the boot image
|
||||
find_boot_image
|
||||
[ -z $BOOTIMAGE ] && abort "! Unable to detect boot image"
|
||||
|
||||
ui_print_wrap "- Found Boot Image: $BOOTIMAGE"
|
||||
|
||||
cd $MAGISKBIN
|
||||
|
||||
ui_print_wrap "- Unpacking boot image"
|
||||
./magiskboot --unpack "$BOOTIMAGE"
|
||||
[ $? -ne 0 ] && abort_wrap "! Unable to unpack boot image"
|
||||
|
||||
# Update our previous backup to new format if exists
|
||||
if [ -f /data/stock_boot.img ]; then
|
||||
SHA1=`./magiskboot --sha1 /data/stock_boot.img | tail -n 1`
|
||||
STOCKDUMP=/data/stock_boot_${SHA1}.img
|
||||
mv /data/stock_boot.img $STOCKDUMP
|
||||
./magiskboot --compress $STOCKDUMP
|
||||
fi
|
||||
|
||||
# Detect boot image state
|
||||
./magiskboot --cpio-test ramdisk.cpio
|
||||
case $? in
|
||||
0 ) # Stock boot
|
||||
ui_print_wrap "- Stock boot image detected!"
|
||||
ui_print_wrap "! Magisk is not installed!"
|
||||
exit
|
||||
;;
|
||||
1 ) # Magisk patched
|
||||
ui_print_wrap "- Magisk patched image detected!"
|
||||
# Find SHA1 of stock boot image
|
||||
if [ -z $SHA1 ]; then
|
||||
./magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc.old
|
||||
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc.old`
|
||||
rm -f init.magisk.rc.old
|
||||
fi
|
||||
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
|
||||
if [ -f ${STOCKDUMP}.gz ]; then
|
||||
ui_print_wrap "- Boot image backup found!"
|
||||
./magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
|
||||
else
|
||||
ui_print_wrap "! Boot image backup unavailable"
|
||||
ui_print_wrap "- Restoring ramdisk with backup"
|
||||
./magiskboot --cpio-restore ramdisk.cpio
|
||||
./magiskboot --repack $BOOTIMAGE stock_boot.img
|
||||
fi
|
||||
;;
|
||||
2 ) # Other patched
|
||||
ui_print_wrap "! Boot image patched by other programs!"
|
||||
abort_wrap "! Cannot uninstall with this uninstaller"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Sign chromeos boot
|
||||
if [ -f chromeos ]; then
|
||||
echo > empty
|
||||
|
||||
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack stock_boot.img.signed \
|
||||
--keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk \
|
||||
--version 1 --vmlinuz stock_boot.img --config empty --arch arm --bootloader empty --flags 0x1
|
||||
|
||||
rm -f empty stock_boot.img
|
||||
mv stock_boot.img.signed stock_boot.img
|
||||
fi
|
||||
|
||||
ui_print_wrap "- Flashing stock/reverted image"
|
||||
if [ -L "$BOOTIMAGE" ]; then
|
||||
dd if=stock_boot.img of="$BOOTIMAGE" bs=4096
|
||||
else
|
||||
cat stock_boot.img /dev/zero | dd of="$BOOTIMAGE" bs=4096 >/dev/null 2>&1
|
||||
fi
|
||||
rm -f stock_boot.img
|
||||
|
||||
ui_print_wrap "- Removing Magisk files"
|
||||
rm -rf /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \
|
||||
/cache/magisk /cache/magisk_merge /cache/magisk_mount /cache/unblock /cache/magisk_uninstaller.sh \
|
||||
/data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img /data/magisk_debug.log \
|
||||
/data/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null
|
||||
|
||||
$BOOTMODE && reboot
|
Binary file not shown.
@@ -1,27 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
|
||||
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
|
||||
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
|
||||
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
|
||||
Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET
|
||||
MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
|
||||
A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
|
||||
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
|
||||
hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
|
||||
qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
|
||||
wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
|
||||
4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
|
||||
RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
|
||||
zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
|
||||
HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
|
||||
AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
|
||||
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
|
||||
QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
|
||||
CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
|
||||
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa
|
||||
J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y
|
||||
LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe
|
||||
+ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX
|
||||
31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr
|
||||
sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0=
|
||||
-----END CERTIFICATE-----
|
@@ -1,192 +0,0 @@
|
||||
##########################################################################################
|
||||
#
|
||||
# Magisk General Utility Functions
|
||||
# by topjohnwu
|
||||
#
|
||||
# Used in flash_script.sh, addon.d.sh, magisk module installers, and uninstaller
|
||||
#
|
||||
##########################################################################################
|
||||
|
||||
get_outfd() {
|
||||
readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
|
||||
if [ "$?" -eq "0" ]; then
|
||||
OUTFD=0
|
||||
|
||||
for FD in `ls /proc/$$/fd`; do
|
||||
readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
|
||||
if [ "$?" -eq "0" ]; then
|
||||
ps | grep " 3 $FD " | grep -v grep >/dev/null
|
||||
if [ "$?" -eq "0" ]; then
|
||||
OUTFD=$FD
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
ui_print() {
|
||||
if $BOOTMODE; then
|
||||
echo "$1"
|
||||
else
|
||||
echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD
|
||||
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
|
||||
fi
|
||||
}
|
||||
|
||||
getvar() {
|
||||
local VARNAME=$1
|
||||
local VALUE=$(eval echo \$"$VARNAME");
|
||||
for FILE in /dev/.magisk /data/.magisk /cache/.magisk /system/.magisk; do
|
||||
if [ -z "$VALUE" ]; then
|
||||
LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=")
|
||||
if [ ! -z "$LINE" ]; then
|
||||
VALUE=${LINE#*=}
|
||||
fi
|
||||
fi
|
||||
done
|
||||
eval $VARNAME=\$VALUE
|
||||
}
|
||||
|
||||
find_boot_image() {
|
||||
if [ -z "$BOOTIMAGE" ]; then
|
||||
for BLOCK in boot_a BOOT_A kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
|
||||
BOOTIMAGE=`ls /dev/block/by-name/$BLOCK || ls /dev/block/platform/*/by-name/$BLOCK || ls /dev/block/platform/*/*/by-name/$BLOCK` 2>/dev/null
|
||||
[ ! -z $BOOTIMAGE ] && break
|
||||
done
|
||||
fi
|
||||
# Recovery fallback
|
||||
if [ -z "$BOOTIMAGE" ]; then
|
||||
for FSTAB in /etc/*fstab*; do
|
||||
BOOTIMAGE=`grep -E '\b/boot\b' $FSTAB | grep -v "#" | grep -oE '/dev/[a-zA-Z0-9_./-]*'`
|
||||
[ ! -z $BOOTIMAGE ] && break
|
||||
done
|
||||
fi
|
||||
[ -L "$BOOTIMAGE" ] && BOOTIMAGE=`readlink $BOOTIMAGE`
|
||||
}
|
||||
|
||||
is_mounted() {
|
||||
if [ ! -z "$2" ]; then
|
||||
cat /proc/mounts | grep $1 | grep $2, >/dev/null
|
||||
else
|
||||
cat /proc/mounts | grep $1 >/dev/null
|
||||
fi
|
||||
return $?
|
||||
}
|
||||
|
||||
grep_prop() {
|
||||
REGEX="s/^$1=//p"
|
||||
shift
|
||||
FILES=$@
|
||||
if [ -z "$FILES" ]; then
|
||||
FILES='/system/build.prop'
|
||||
fi
|
||||
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
|
||||
}
|
||||
|
||||
remove_system_su() {
|
||||
if [ -f /system/bin/su -o -f /system/xbin/su ] && [ ! -f /su/bin/su ]; then
|
||||
ui_print "! System installed root detected, mount rw :("
|
||||
mount -o rw,remount /system
|
||||
# SuperSU
|
||||
if [ -e /system/bin/.ext/.su ]; then
|
||||
mv -f /system/bin/app_process32_original /system/bin/app_process32 2>/dev/null
|
||||
mv -f /system/bin/app_process64_original /system/bin/app_process64 2>/dev/null
|
||||
mv -f /system/bin/install-recovery_original.sh /system/bin/install-recovery.sh 2>/dev/null
|
||||
cd /system/bin
|
||||
if [ -e app_process64 ]; then
|
||||
ln -sf app_process64 app_process
|
||||
else
|
||||
ln -sf app_process32 app_process
|
||||
fi
|
||||
fi
|
||||
rm -rf /system/.pin /system/bin/.ext /system/etc/.installed_su_daemon /system/etc/.has_su_daemon \
|
||||
/system/xbin/daemonsu /system/xbin/su /system/xbin/sugote /system/xbin/sugote-mksh /system/xbin/supolicy \
|
||||
/system/bin/app_process_init /system/bin/su /cache/su /system/lib/libsupol.so /system/lib64/libsupol.so \
|
||||
/system/su.d /system/etc/install-recovery.sh /system/etc/init.d/99SuperSUDaemon /cache/install-recovery.sh \
|
||||
/system/.supersu /cache/.supersu /data/.supersu \
|
||||
/system/app/Superuser.apk /system/app/SuperSU /cache/Superuser.apk 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
api_level_arch_detect() {
|
||||
API=`grep_prop ro.build.version.sdk`
|
||||
ABI=`grep_prop ro.product.cpu.abi | cut -c-3`
|
||||
ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3`
|
||||
ABILONG=`grep_prop ro.product.cpu.abi`
|
||||
|
||||
ARCH=arm
|
||||
IS64BIT=false
|
||||
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
|
||||
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
|
||||
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
|
||||
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
|
||||
}
|
||||
|
||||
recovery_actions() {
|
||||
# TWRP bug fix
|
||||
mount -o bind /dev/urandom /dev/random
|
||||
# Temporarily block out all custom recovery binaries/libs
|
||||
mv /sbin /sbin_tmp
|
||||
# Add all possible library paths
|
||||
OLD_LD_PATH=$LD_LIBRARY_PATH
|
||||
$IS64BIT && export LD_LIBRARY_PATH=/system/lib64:/system/vendor/lib64 || export LD_LIBRARY_PATH=/system/lib:/system/vendor/lib
|
||||
}
|
||||
|
||||
recovery_cleanup() {
|
||||
mv /sbin_tmp /sbin
|
||||
# Clear LD_LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH=$OLD_LD_PATH
|
||||
ui_print "- Unmounting partitions"
|
||||
umount -l /system
|
||||
umount -l /vendor 2>/dev/null
|
||||
umount -l /dev/random
|
||||
}
|
||||
|
||||
abort() {
|
||||
ui_print "$1"
|
||||
mv /sbin_tmp /sbin 2>/dev/null
|
||||
exit 1
|
||||
}
|
||||
|
||||
set_perm() {
|
||||
chown $2:$3 $1 || exit 1
|
||||
chmod $4 $1 || exit 1
|
||||
if [ ! -z $5 ]; then
|
||||
chcon $5 $1 2>/dev/null
|
||||
else
|
||||
chcon 'u:object_r:system_file:s0' $1 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
set_perm_recursive() {
|
||||
find $1 -type d 2>/dev/null | while read dir; do
|
||||
set_perm $dir $2 $3 $4 $6
|
||||
done
|
||||
find $1 -type f 2>/dev/null | while read file; do
|
||||
set_perm $file $2 $3 $5 $6
|
||||
done
|
||||
}
|
||||
|
||||
mktouch() {
|
||||
mkdir -p ${1%/*}
|
||||
if [ -z "$2" ]; then
|
||||
touch $1
|
||||
else
|
||||
echo $2 > $1
|
||||
fi
|
||||
chmod 644 $1
|
||||
}
|
||||
|
||||
request_size_check() {
|
||||
reqSizeM=`du -s $1 | cut -f1`
|
||||
reqSizeM=$((reqSizeM / 1024 + 1))
|
||||
}
|
||||
|
||||
image_size_check() {
|
||||
SIZE="`$MAGISKBIN/magisk --imgsize $IMG`"
|
||||
curUsedM=`echo "$SIZE" | cut -d" " -f1`
|
||||
curSizeM=`echo "$SIZE" | cut -d" " -f2`
|
||||
curFreeM=$((curSizeM - curUsedM))
|
||||
}
|
||||
|
98
app/src/main/java/com/topjohnwu/magisk/FlashActivity.java
Normal file
98
app/src/main/java/com/topjohnwu/magisk/FlashActivity.java
Normal file
@@ -0,0 +1,98 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.FlashZip;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.utils.AdaptiveList;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
public class FlashActivity extends Activity {
|
||||
|
||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||
@BindView(R.id.flash_logs) RecyclerView flashLogs;
|
||||
@BindView(R.id.button_panel) LinearLayout buttonPanel;
|
||||
|
||||
private AdaptiveList<String> rootShellOutput;
|
||||
|
||||
@OnClick(R.id.no_thanks)
|
||||
public void dismiss() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@OnClick(R.id.reboot)
|
||||
public void reboot() {
|
||||
Shell.getShell(this).su_raw("reboot");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_flash);
|
||||
ButterKnife.bind(this);
|
||||
rootShellOutput = new AdaptiveList<>(flashLogs);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setTitle(R.string.flashing);
|
||||
}
|
||||
setFloating();
|
||||
|
||||
flashLogs.setAdapter(new FlashLogAdapter());
|
||||
|
||||
// We must receive a Uri of the target zip
|
||||
Uri uri = getIntent().getData();
|
||||
|
||||
new FlashZip(this, uri, rootShellOutput)
|
||||
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
|
||||
.exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Prevent user accidentally press back button
|
||||
}
|
||||
|
||||
private class FlashLogAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.list_item_flashlog, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
holder.text.setText(rootShellOutput.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return rootShellOutput.size();
|
||||
}
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@BindView(R.id.textView) TextView text;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
}
|
||||
}
|
@@ -29,6 +29,8 @@ public class LogFragment extends Fragment {
|
||||
View v = inflater.inflate(R.layout.fragment_log, container, false);
|
||||
unbinder = ButterKnife.bind(this, v);
|
||||
|
||||
((MainActivity) getActivity()).toolbar.setElevation(0);
|
||||
|
||||
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
|
||||
|
||||
if (getApplication().isSuClient) {
|
||||
|
@@ -2,7 +2,9 @@ package com.topjohnwu.magisk;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@@ -25,13 +27,12 @@ import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||
import com.topjohnwu.magisk.asyncs.ProcessMagiskZip;
|
||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.io.File;
|
||||
@@ -48,9 +49,10 @@ import butterknife.OnClick;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class MagiskFragment extends Fragment
|
||||
implements CallbackEvent.Listener<Void>, SwipeRefreshLayout.OnRefreshListener {
|
||||
implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener {
|
||||
|
||||
public static final String SHOW_DIALOG = "dialog";
|
||||
|
||||
private static boolean noDialog = false;
|
||||
private static int expandHeight = 0;
|
||||
private static boolean mExpanded = false;
|
||||
|
||||
@@ -104,25 +106,18 @@ public class MagiskFragment extends Fragment
|
||||
collapse();
|
||||
}
|
||||
|
||||
@OnClick(R.id.detect_bootimage)
|
||||
public void toAutoDetect() {
|
||||
if (magiskManager.bootBlock != null) {
|
||||
spinner.setSelection(0);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.install_button)
|
||||
public void install() {
|
||||
String bootImage = null;
|
||||
if (magiskManager.blockList != null) {
|
||||
int idx = spinner.getSelectedItemPosition();
|
||||
if (Shell.rootAccess()) {
|
||||
if (magiskManager.bootBlock != null) {
|
||||
bootImage = magiskManager.bootBlock;
|
||||
} else {
|
||||
int idx = spinner.getSelectedItemPosition();
|
||||
if (idx > 0) {
|
||||
bootImage = magiskManager.blockList.get(idx - 1);
|
||||
} else {
|
||||
SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG);
|
||||
SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -134,21 +129,36 @@ public class MagiskFragment extends Fragment
|
||||
.setMessage(getString(R.string.repo_install_msg, filename))
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(Shell.rootAccess() ? R.string.install : R.string.download,
|
||||
(dialogInterface, i) -> Utils.dlAndReceive(
|
||||
getActivity(),
|
||||
new DownloadReceiver() {
|
||||
private String boot = finalBootImage;
|
||||
private boolean enc = keepEncChkbox.isChecked();
|
||||
private boolean verity = keepVerityChkbox.isChecked();
|
||||
(d, i) -> {
|
||||
((NotificationManager) getActivity()
|
||||
.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll();
|
||||
Utils.dlAndReceive(
|
||||
getActivity(),
|
||||
new DownloadReceiver() {
|
||||
private String boot = finalBootImage;
|
||||
private boolean enc = keepEncChkbox.isChecked();
|
||||
private boolean verity = keepVerityChkbox.isChecked();
|
||||
|
||||
@Override
|
||||
public void onDownloadDone(Uri uri) {
|
||||
new ProcessMagiskZip(getActivity(), uri, boot, enc, verity).exec();
|
||||
@Override
|
||||
public void onDownloadDone(Uri uri) {
|
||||
if (Shell.rootAccess()) {
|
||||
Shell.getShell(getActivity()).su_raw(
|
||||
"rm -f /dev/.magisk",
|
||||
"echo \"BOOTIMAGE=" + boot + "\" >> /dev/.magisk",
|
||||
"echo \"KEEPFORCEENCRYPT=" + String.valueOf(enc) + "\" >> /dev/.magisk",
|
||||
"echo \"KEEPVERITY=" + String.valueOf(verity) + "\" >> /dev/.magisk"
|
||||
);
|
||||
startActivity(new Intent(getActivity(), FlashActivity.class).setData(uri));
|
||||
} else {
|
||||
Utils.showUriSnack(getActivity(), uri);
|
||||
}
|
||||
},
|
||||
magiskManager.magiskLink,
|
||||
Utils.getLegalFilename(filename)))
|
||||
.setNeutralButton(R.string.release_notes, (dialog, which) -> {
|
||||
}
|
||||
},
|
||||
magiskManager.magiskLink,
|
||||
Utils.getLegalFilename(filename));
|
||||
}
|
||||
)
|
||||
.setNeutralButton(R.string.release_notes, (d, i) -> {
|
||||
if (magiskManager.releaseNoteLink != null) {
|
||||
Intent openReleaseNoteLink = new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink));
|
||||
openReleaseNoteLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
@@ -196,7 +206,7 @@ public class MagiskFragment extends Fragment
|
||||
@Override
|
||||
public void onFinish() {
|
||||
progress.setMessage(getString(R.string.reboot_countdown, 0));
|
||||
Shell.su(true,
|
||||
Shell.getShell(getActivity()).su_raw(
|
||||
"mv -f " + uninstaller + " /cache/" + MagiskManager.UNINSTALLER,
|
||||
"mv -f " + utils + " /data/magisk/" + MagiskManager.UTIL_FUNCTIONS,
|
||||
"reboot"
|
||||
@@ -238,24 +248,19 @@ public class MagiskFragment extends Fragment
|
||||
|
||||
mSwipeRefreshLayout.setOnRefreshListener(this);
|
||||
|
||||
if (magiskManager.magiskVersionCode < 0 && Shell.rootAccess() && !noDialog) {
|
||||
noDialog = true;
|
||||
new AlertDialogBuilder(getActivity())
|
||||
.setTitle(R.string.no_magisk_title)
|
||||
.setMessage(R.string.no_magisk_msg)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.goto_install, (d, i) -> {})
|
||||
.setNegativeButton(R.string.no_thanks, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
updateUI();
|
||||
|
||||
if (getArguments() != null && getArguments().getBoolean(SHOW_DIALOG))
|
||||
install();
|
||||
|
||||
getActivity().setTitle(R.string.magisk);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
magiskManager.getMagiskInfo();
|
||||
updateUI();
|
||||
|
||||
magiskUpdateText.setText(R.string.checking_for_updates);
|
||||
@@ -264,12 +269,11 @@ public class MagiskFragment extends Fragment
|
||||
|
||||
safetyNetStatusText.setText(R.string.safetyNet_check_text);
|
||||
|
||||
magiskManager.safetyNetDone.isTriggered = false;
|
||||
magiskManager.updateCheckDone.isTriggered = false;
|
||||
magiskManager.safetyNetDone.hasPublished = false;
|
||||
magiskManager.updateCheckDone.hasPublished = false;
|
||||
magiskManager.remoteMagiskVersionString = null;
|
||||
magiskManager.remoteMagiskVersionCode = -1;
|
||||
collapse();
|
||||
noDialog = false;
|
||||
|
||||
// Trigger state check
|
||||
if (Utils.checkNetworkStatus(magiskManager)) {
|
||||
@@ -280,38 +284,17 @@ public class MagiskFragment extends Fragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackEvent<Void> event) {
|
||||
if (event == magiskManager.updateCheckDone) {
|
||||
public void onTopicPublished(Topic topic) {
|
||||
if (topic == magiskManager.updateCheckDone) {
|
||||
updateCheckUI();
|
||||
} else if (event == magiskManager.safetyNetDone) {
|
||||
} else if (topic == magiskManager.safetyNetDone) {
|
||||
updateSafetyNetUI();
|
||||
} else if (event == magiskManager.blockDetectionDone) {
|
||||
updateInstallUI();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
// Manual trigger if already done
|
||||
if (magiskManager.updateCheckDone.isTriggered)
|
||||
updateCheckUI();
|
||||
if (magiskManager.safetyNetDone.isTriggered)
|
||||
updateSafetyNetUI();
|
||||
if (magiskManager.blockDetectionDone.isTriggered || !Shell.rootAccess())
|
||||
updateInstallUI();
|
||||
magiskManager.updateCheckDone.register(this);
|
||||
magiskManager.safetyNetDone.register(this);
|
||||
magiskManager.blockDetectionDone.register(this);
|
||||
getActivity().setTitle(R.string.magisk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
magiskManager.updateCheckDone.unRegister(this);
|
||||
magiskManager.safetyNetDone.unRegister(this);
|
||||
magiskManager.blockDetectionDone.unRegister(this);
|
||||
super.onStop();
|
||||
public Topic[] getSubscription() {
|
||||
return new Topic[] { magiskManager.updateCheckDone, magiskManager.safetyNetDone };
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -322,6 +305,7 @@ public class MagiskFragment extends Fragment
|
||||
|
||||
private void updateUI() {
|
||||
((MainActivity) getActivity()).checkHideSection();
|
||||
|
||||
final int ROOT = 0x1, NETWORK = 0x2, UPTODATE = 0x4;
|
||||
int status = 0;
|
||||
status |= Shell.rootAccess() ? ROOT : 0;
|
||||
@@ -333,14 +317,9 @@ public class MagiskFragment extends Fragment
|
||||
installOptionCard.setVisibility(Utils.checkBits(status, NETWORK, ROOT) ? View.VISIBLE : View.GONE);
|
||||
installButton.setVisibility(Utils.checkBits(status, NETWORK) ? View.VISIBLE : View.GONE);
|
||||
uninstallButton.setVisibility(Utils.checkBits(status, UPTODATE, ROOT) ? View.VISIBLE : View.GONE);
|
||||
updateVersionUI();
|
||||
}
|
||||
|
||||
private void updateVersionUI() {
|
||||
int image, color;
|
||||
|
||||
magiskManager.updateMagiskInfo();
|
||||
|
||||
if (magiskManager.magiskVersionCode < 0) {
|
||||
color = colorBad;
|
||||
image = R.drawable.ic_cancel;
|
||||
@@ -376,6 +355,29 @@ public class MagiskFragment extends Fragment
|
||||
|
||||
rootStatusIcon.setImageResource(image);
|
||||
rootStatusIcon.setColorFilter(color);
|
||||
|
||||
if (!Shell.rootAccess()) {
|
||||
installText.setText(R.string.download);
|
||||
} else {
|
||||
if (magiskManager.remoteMagiskVersionCode > magiskManager.magiskVersionCode) {
|
||||
installText.setText(R.string.update);
|
||||
} else {
|
||||
installText.setText(R.string.reinstall);
|
||||
}
|
||||
|
||||
List<String> items = new ArrayList<>();
|
||||
if (magiskManager.bootBlock != null) {
|
||||
items.add(getString(R.string.auto_detect, magiskManager.bootBlock));
|
||||
spinner.setEnabled(false);
|
||||
} else {
|
||||
items.add(getString(R.string.cannot_auto_detect));
|
||||
items.addAll(magiskManager.blockList);
|
||||
}
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
|
||||
android.R.layout.simple_spinner_item, items);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCheckUI() {
|
||||
@@ -397,28 +399,9 @@ public class MagiskFragment extends Fragment
|
||||
|
||||
magiskUpdateProgress.setVisibility(View.GONE);
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
|
||||
private void updateInstallUI() {
|
||||
if (!Shell.rootAccess()) {
|
||||
installText.setText(R.string.download);
|
||||
} else {
|
||||
installText.setText(R.string.download_install);
|
||||
|
||||
List<String> items = new ArrayList<>();
|
||||
if (magiskManager.bootBlock != null) {
|
||||
items.add(getString(R.string.auto_detect, magiskManager.bootBlock));
|
||||
spinner.setEnabled(false);
|
||||
} else {
|
||||
items.add(getString(R.string.cannot_auto_detect));
|
||||
items.addAll(magiskManager.blockList);
|
||||
}
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
|
||||
android.R.layout.simple_spinner_item, items);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(adapter);
|
||||
toAutoDetect();
|
||||
}
|
||||
if (magiskManager.remoteMagiskVersionCode > magiskManager.magiskVersionCode)
|
||||
install();
|
||||
}
|
||||
|
||||
private void updateSafetyNetUI() {
|
||||
|
@@ -1,12 +1,9 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@@ -15,16 +12,14 @@ import android.view.ViewGroup;
|
||||
import android.widget.SearchView;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class MagiskHideFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
||||
public class MagiskHideFragment extends Fragment implements Topic.Subscriber {
|
||||
|
||||
private Unbinder unbinder;
|
||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||
@@ -46,13 +41,12 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_magisk_hide, container, false);
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
PackageManager packageManager = getActivity().getPackageManager();
|
||||
lastFilter = "";
|
||||
|
||||
mSwipeRefreshLayout.setRefreshing(true);
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> new MagiskHide(getActivity()).list());
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> appAdapter.refresh());
|
||||
|
||||
appAdapter = new ApplicationAdapter(packageManager);
|
||||
appAdapter = new ApplicationAdapter(getActivity());
|
||||
recyclerView.setAdapter(appAdapter);
|
||||
|
||||
searchListener = new SearchView.OnQueryTextListener() {
|
||||
@@ -71,9 +65,7 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen
|
||||
}
|
||||
};
|
||||
|
||||
if (getApplication().magiskHideDone.isTriggered) {
|
||||
onTrigger(getApplication().magiskHideDone);
|
||||
}
|
||||
getActivity().setTitle(R.string.magiskhide);
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -81,23 +73,10 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_magiskhide, menu);
|
||||
SearchView search = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.app_search));
|
||||
SearchView search = (SearchView) menu.findItem(R.id.app_search).getActionView();
|
||||
search.setOnQueryTextListener(searchListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getActivity().setTitle(R.string.magiskhide);
|
||||
getApplication().magiskHideDone.register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
getApplication().magiskHideDone.unRegister(this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
@@ -105,12 +84,13 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackEvent<Void> event) {
|
||||
Logger.dev("MagiskHideFragment: UI refresh");
|
||||
appAdapter.setLists(getApplication().appList, getApplication().magiskHideList);
|
||||
public void onTopicPublished(Topic topic) {
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
if (!TextUtils.isEmpty(lastFilter)) {
|
||||
appAdapter.filter(lastFilter);
|
||||
}
|
||||
appAdapter.filter(lastFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Topic[] getSubscription() {
|
||||
return new Topic[] { getApplication().magiskHideDone };
|
||||
}
|
||||
}
|
||||
|
@@ -1,16 +1,13 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -24,17 +21,15 @@ import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.RootTask;
|
||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
@@ -127,45 +122,28 @@ public class MagiskLogFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
private class LogManager extends RootTask<Object, Void, Object> {
|
||||
private class LogManager extends ParallelTask<Object, Void, Object> {
|
||||
|
||||
int mode;
|
||||
File targetFile;
|
||||
private int mode;
|
||||
private File targetFile;
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
@Override
|
||||
protected Object doInRoot(Object... params) {
|
||||
protected Object doInBackground(Object... params) {
|
||||
MagiskManager magiskManager = MagiskLogFragment.this.getApplication();
|
||||
mode = (int) params[0];
|
||||
switch (mode) {
|
||||
case 0:
|
||||
List<String> logList = Utils.readFile(MAGISK_LOG);
|
||||
|
||||
if (Utils.isValidShellResponse(logList)) {
|
||||
StringBuilder llog = new StringBuilder(15 * 10 * 1024);
|
||||
for (String s : logList) {
|
||||
llog.append(s).append("\n");
|
||||
}
|
||||
return llog.toString();
|
||||
}
|
||||
return "";
|
||||
StringBuildingList logList = new StringBuildingList();
|
||||
Shell.getShell(magiskManager).su(logList, "cat " + MAGISK_LOG);
|
||||
return logList.toString();
|
||||
|
||||
case 1:
|
||||
Shell.su("echo > " + MAGISK_LOG);
|
||||
Shell.getShell(magiskManager).su_raw("echo > " + MAGISK_LOG);
|
||||
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
||||
return "";
|
||||
|
||||
case 2:
|
||||
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
String filename = String.format(
|
||||
"magisk_%s_%04d%02d%02d_%02d%02d%02d.log", "error",
|
||||
@@ -180,19 +158,14 @@ public class MagiskLogFragment extends Fragment {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> in = Utils.readFile(MAGISK_LOG);
|
||||
|
||||
if (Utils.isValidShellResponse(in)) {
|
||||
try (FileWriter out = new FileWriter(targetFile)) {
|
||||
for (String line : in)
|
||||
out.write(line + "\n");
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
try (FileWriter out = new FileWriter(targetFile)) {
|
||||
FileWritingList fileWritingList = new FileWritingList(out);
|
||||
Shell.getShell(magiskManager).su(fileWritingList, "cat " + MAGISK_LOG);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -200,12 +173,10 @@ public class MagiskLogFragment extends Fragment {
|
||||
@Override
|
||||
protected void onPostExecute(Object o) {
|
||||
if (o == null) return;
|
||||
boolean bool;
|
||||
String llog;
|
||||
switch (mode) {
|
||||
case 0:
|
||||
case 1:
|
||||
llog = (String) o;
|
||||
String llog = (String) o;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
if (TextUtils.isEmpty(llog))
|
||||
txtLog.setText(R.string.log_is_empty);
|
||||
@@ -215,27 +186,64 @@ public class MagiskLogFragment extends Fragment {
|
||||
hsvLog.post(() -> hsvLog.scrollTo(0, 0));
|
||||
break;
|
||||
case 2:
|
||||
bool = (boolean) o;
|
||||
boolean bool = (boolean) o;
|
||||
if (bool) {
|
||||
Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG).show();
|
||||
MagiskLogFragment.this.getApplication().toast(targetFile.toString(), Toast.LENGTH_LONG);
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.logs_save_failed), Toast.LENGTH_LONG).show();
|
||||
MagiskLogFragment.this.getApplication().toast(R.string.logs_save_failed, Toast.LENGTH_LONG);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void read() {
|
||||
void read() {
|
||||
exec(0);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
void clear() {
|
||||
exec(1);
|
||||
}
|
||||
|
||||
public void save() {
|
||||
void save() {
|
||||
exec(2);
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringBuildingList extends Shell.AbstractList<String> {
|
||||
|
||||
StringBuilder builder;
|
||||
|
||||
StringBuildingList() {
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(String s) {
|
||||
builder.append(s).append("\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class FileWritingList extends Shell.AbstractList<String> {
|
||||
|
||||
private FileWriter writer;
|
||||
|
||||
FileWritingList(FileWriter out) {
|
||||
writer = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(String s) {
|
||||
try {
|
||||
writer.write(s + "\n");
|
||||
} catch (IOException ignored) {}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,24 +1,31 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.DownloadBusybox;
|
||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.SafetyNetHelper;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ValueSortedMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class MagiskManager extends Application {
|
||||
|
||||
@@ -28,18 +35,21 @@ public class MagiskManager extends Application {
|
||||
public static final String UNINSTALLER = "magisk_uninstaller.sh";
|
||||
public static final String UTIL_FUNCTIONS= "util_functions.sh";
|
||||
public static final String INTENT_SECTION = "section";
|
||||
public static final String BUSYBOX_VERSION = "1.26.2";
|
||||
public static final String INTENT_VERSION = "version";
|
||||
public static final String INTENT_LINK = "link";
|
||||
public static final String MAGISKHIDE_PROP = "persist.magisk.hide";
|
||||
public static final String DISABLE_INDICATION_PROP = "ro.magisk.disable";
|
||||
public static final String NOTIFICATION_CHANNEL = "magisk_update_notice";
|
||||
public static final String BUSYBOX_VERSION = "1.27.1";
|
||||
|
||||
// Events
|
||||
public final CallbackEvent<Void> blockDetectionDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> magiskHideDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> reloadMainActivity = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> moduleLoadDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> repoLoadDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> updateCheckDone = new CallbackEvent<>();
|
||||
public final CallbackEvent<Void> safetyNetDone = new CallbackEvent<>();
|
||||
// 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 String magiskVersionString;
|
||||
@@ -58,15 +68,15 @@ public class MagiskManager extends Application {
|
||||
public boolean disabled;
|
||||
|
||||
// Data
|
||||
public ValueSortedMap<String, Repo> repoMap;
|
||||
public ValueSortedMap<String, Module> moduleMap;
|
||||
public Map<String, Module> moduleMap;
|
||||
public List<String> blockList;
|
||||
public List<ApplicationInfo> appList;
|
||||
public List<String> magiskHideList;
|
||||
public List<Locale> locales;
|
||||
|
||||
// Configurations
|
||||
public static boolean shellLogging;
|
||||
public static boolean devLogging;
|
||||
public static Locale locale;
|
||||
public static Locale defaultLocale;
|
||||
|
||||
public boolean magiskHide;
|
||||
public boolean isDarkTheme;
|
||||
@@ -83,13 +93,76 @@ public class MagiskManager extends Application {
|
||||
// Global resources
|
||||
public SharedPreferences prefs;
|
||||
public SuDatabaseHelper suDB;
|
||||
public RepoDatabaseHelper repoDB;
|
||||
public Shell shell;
|
||||
|
||||
private static Handler mHandler = new Handler();
|
||||
|
||||
private static class LoadLocale extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
LoadLocale(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
getMagiskManager().locales = Utils.getAvailableLocale(getMagiskManager());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
getMagiskManager().localeDone.publish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
new File(getApplicationInfo().dataDir).mkdirs(); /* Create the app data directory */
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
suDB = new SuDatabaseHelper(this);
|
||||
repoDB = new RepoDatabaseHelper(this);
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
public void setLocale() {
|
||||
String localeTag = prefs.getString("locale", "");
|
||||
if (localeTag.isEmpty()) {
|
||||
locale = defaultLocale;
|
||||
} else {
|
||||
locale = Locale.forLanguageTag(localeTag);
|
||||
}
|
||||
Resources res = getBaseContext().getResources();
|
||||
Configuration config = new Configuration(res.getConfiguration());
|
||||
config.setLocale(locale);
|
||||
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
// Locale
|
||||
defaultLocale = Locale.getDefault();
|
||||
setLocale();
|
||||
|
||||
isDarkTheme = prefs.getBoolean("dark_theme", false);
|
||||
if (BuildConfig.DEBUG) {
|
||||
devLogging = prefs.getBoolean("developer_logging", false);
|
||||
shellLogging = prefs.getBoolean("shell_logging", false);
|
||||
} else {
|
||||
devLogging = false;
|
||||
shellLogging = false;
|
||||
}
|
||||
|
||||
// su
|
||||
suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
|
||||
suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
|
||||
suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
|
||||
suReauth = prefs.getBoolean("su_reauth", false);
|
||||
suAccessState = suDB.getSettings(SuDatabaseHelper.ROOT_ACCESS, 3);
|
||||
multiuserMode = suDB.getSettings(SuDatabaseHelper.MULTIUSER_MODE, 0);
|
||||
suNamespaceMode = suDB.getSettings(SuDatabaseHelper.MNT_NS, 1);
|
||||
|
||||
updateNotification = prefs.getBoolean("notification", true);
|
||||
}
|
||||
|
||||
public void toast(String msg, int duration) {
|
||||
@@ -101,37 +174,18 @@ public class MagiskManager extends Application {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
isDarkTheme = prefs.getBoolean("dark_theme", false);
|
||||
if (BuildConfig.DEBUG) {
|
||||
devLogging = prefs.getBoolean("developer_logging", false);
|
||||
shellLogging = prefs.getBoolean("shell_logging", false);
|
||||
} else {
|
||||
devLogging = false;
|
||||
shellLogging = false;
|
||||
}
|
||||
magiskHide = prefs.getBoolean("magiskhide", true);
|
||||
updateNotification = prefs.getBoolean("notification", true);
|
||||
initSU();
|
||||
// Always start a new root shell manually, just for safety
|
||||
Shell.init();
|
||||
updateMagiskInfo();
|
||||
// Initialize busybox
|
||||
File busybox = new File(getApplicationInfo().dataDir + "/busybox/busybox");
|
||||
if (!busybox.exists() || !TextUtils.equals(prefs.getString("busybox_version", ""), BUSYBOX_VERSION)) {
|
||||
busybox.getParentFile().mkdirs();
|
||||
Shell.su(
|
||||
"cp -f " + new File(getApplicationInfo().nativeLibraryDir, "libbusybox.so") + " " + busybox,
|
||||
"chmod -R 755 " + busybox.getParent(),
|
||||
busybox + " --install -s " + busybox.getParent()
|
||||
);
|
||||
}
|
||||
// Initialize prefs
|
||||
new LoadLocale(this).exec();
|
||||
new DownloadBusybox(this).exec();
|
||||
getMagiskInfo();
|
||||
updateBlockInfo();
|
||||
|
||||
// Write back default values
|
||||
prefs.edit()
|
||||
.putBoolean("dark_theme", isDarkTheme)
|
||||
.putBoolean("magiskhide", magiskHide)
|
||||
.putBoolean("notification", updateNotification)
|
||||
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
|
||||
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
|
||||
.putBoolean("disable", Utils.itemExist(shell, MAGISK_DISABLE_FILE))
|
||||
.putBoolean("su_reauth", suReauth)
|
||||
.putString("su_request_timeout", String.valueOf(suRequestTimeout))
|
||||
.putString("su_auto_response", String.valueOf(suResponseType))
|
||||
@@ -141,41 +195,30 @@ public class MagiskManager extends Application {
|
||||
.putString("mnt_ns", String.valueOf(suNamespaceMode))
|
||||
.putString("busybox_version", BUSYBOX_VERSION)
|
||||
.apply();
|
||||
|
||||
// Add busybox to PATH
|
||||
Shell.su("PATH=$PATH:" + busybox.getParent());
|
||||
shell.su_raw("PATH=" + getApplicationInfo().dataDir + "/busybox:$PATH");
|
||||
|
||||
// Create notification channel on Android O
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL,
|
||||
getString(R.string.magisk_updates), NotificationManager.IMPORTANCE_DEFAULT);
|
||||
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void initSUConfig() {
|
||||
suDB = new SuDatabaseHelper(this);
|
||||
suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
|
||||
suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
|
||||
suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
|
||||
suReauth = prefs.getBoolean("su_reauth", false);
|
||||
}
|
||||
|
||||
public void initSU() {
|
||||
// Create the app data directory, so su binary can work properly
|
||||
new File(getApplicationInfo().dataDir).mkdirs();
|
||||
|
||||
initSUConfig();
|
||||
|
||||
List<String> ret = Shell.sh("su -v");
|
||||
public void getMagiskInfo() {
|
||||
Shell.getShell(this);
|
||||
List<String> ret;
|
||||
ret = shell.sh("su -v");
|
||||
if (Utils.isValidShellResponse(ret)) {
|
||||
suVersion = ret.get(0);
|
||||
isSuClient = suVersion.toUpperCase().contains("MAGISK");
|
||||
}
|
||||
if (isSuClient) {
|
||||
suAccessState = suDB.getSettings(SuDatabaseHelper.ROOT_ACCESS, 3);
|
||||
multiuserMode = suDB.getSettings(SuDatabaseHelper.MULTIUSER_MODE, 0);
|
||||
suNamespaceMode = suDB.getSettings(SuDatabaseHelper.MNT_NS, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateMagiskInfo() {
|
||||
List<String> ret;
|
||||
ret = Shell.sh("magisk -v");
|
||||
ret = shell.sh("magisk -v");
|
||||
if (!Utils.isValidShellResponse(ret)) {
|
||||
ret = Shell.sh("getprop magisk.version");
|
||||
ret = shell.sh("getprop magisk.version");
|
||||
if (Utils.isValidShellResponse(ret)) {
|
||||
try {
|
||||
magiskVersionString = ret.get(0);
|
||||
@@ -184,24 +227,39 @@ public class MagiskManager extends Application {
|
||||
}
|
||||
} else {
|
||||
magiskVersionString = ret.get(0).split(":")[0];
|
||||
ret = Shell.sh("magisk -V");
|
||||
ret = shell.sh("magisk -V");
|
||||
try {
|
||||
magiskVersionCode = Integer.parseInt(ret.get(0));
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
ret = Shell.sh("getprop " + DISABLE_INDICATION_PROP);
|
||||
ret = shell.sh("getprop " + DISABLE_INDICATION_PROP);
|
||||
try {
|
||||
disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
|
||||
} catch (NumberFormatException e) {
|
||||
disabled = false;
|
||||
}
|
||||
ret = Shell.sh("getprop " + MAGISKHIDE_PROP);
|
||||
ret = shell.sh("getprop " + MAGISKHIDE_PROP);
|
||||
try {
|
||||
magiskHide = !Utils.isValidShellResponse(ret) || Integer.parseInt(ret.get(0)) != 0;
|
||||
} catch (NumberFormatException e) {
|
||||
magiskHide = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void updateBlockInfo() {
|
||||
List<String> res = shell.su(
|
||||
"for BLOCK in boot_a kern-a android_boot kernel boot lnx; do",
|
||||
" BOOTIMAGE=`find /dev/block -iname $BLOCK | head -n 1` 2>/dev/null",
|
||||
" [ ! -z $BOOTIMAGE ] && break",
|
||||
"done",
|
||||
"[ ! -z \"$BOOTIMAGE\" -a -L \"$BOOTIMAGE\" ] && BOOTIMAGE=`readlink $BOOTIMAGE`",
|
||||
"echo \"$BOOTIMAGE\""
|
||||
);
|
||||
if (Utils.isValidShellResponse(res)) {
|
||||
bootBlock = res.get(0);
|
||||
} else {
|
||||
blockList = shell.su("ls -d /dev/block/mmc* /dev/block/sd* 2>/dev/null");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -20,15 +20,15 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class MainActivity extends Activity
|
||||
implements NavigationView.OnNavigationItemSelectedListener, CallbackEvent.Listener<Void> {
|
||||
implements NavigationView.OnNavigationItemSelectedListener, Topic.Subscriber {
|
||||
|
||||
private final Handler mDrawerHandler = new Handler();
|
||||
private SharedPreferences prefs;
|
||||
@@ -81,7 +81,6 @@ public class MainActivity extends Activity
|
||||
navigate(getIntent().getStringExtra(MagiskManager.INTENT_SECTION));
|
||||
|
||||
navigationView.setNavigationItemSelectedListener(this);
|
||||
getApplicationContext().reloadMainActivity.register(this);
|
||||
|
||||
}
|
||||
|
||||
@@ -91,12 +90,6 @@ public class MainActivity extends Activity
|
||||
checkHideSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getApplicationContext().reloadMainActivity.unRegister(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (drawer.isDrawerOpen(navigationView)) {
|
||||
@@ -117,10 +110,15 @@ public class MainActivity extends Activity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackEvent<Void> event) {
|
||||
public void onTopicPublished(Topic topic) {
|
||||
recreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Topic[] getSubscription() {
|
||||
return new Topic[] { getApplicationContext().reloadActivity };
|
||||
}
|
||||
|
||||
public void checkHideSection() {
|
||||
Menu menu = navigationView.getMenu();
|
||||
menu.findItem(R.id.magiskhide).setVisible(
|
||||
@@ -140,9 +138,11 @@ public class MainActivity extends Activity
|
||||
if (item != null) {
|
||||
switch (item) {
|
||||
case "magisk":
|
||||
case "install":
|
||||
itemId = R.id.magisk;
|
||||
break;
|
||||
case "install":
|
||||
itemId = -1;
|
||||
break;
|
||||
case "superuser":
|
||||
itemId = R.id.superuser;
|
||||
break;
|
||||
@@ -174,6 +174,13 @@ public class MainActivity extends Activity
|
||||
mDrawerItem = itemId;
|
||||
navigationView.setCheckedItem(itemId);
|
||||
switch (itemId) {
|
||||
case -1:
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean(MagiskFragment.SHOW_DIALOG, true);
|
||||
Fragment frag = new MagiskFragment();
|
||||
frag.setArguments(args);
|
||||
displayFragment(frag, "magisk", true);
|
||||
break;
|
||||
case R.id.magisk:
|
||||
displayFragment(new MagiskFragment(), "magisk", true);
|
||||
break;
|
||||
|
@@ -2,10 +2,8 @@ package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -14,21 +12,21 @@ import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
||||
import com.topjohnwu.magisk.asyncs.FlashZip;
|
||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class ModulesFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
||||
public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
||||
|
||||
private static final int FETCH_ZIP_CODE = 2;
|
||||
|
||||
@@ -36,7 +34,12 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener<
|
||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||
@BindView(R.id.fab) FloatingActionButton fabio;
|
||||
@OnClick(R.id.fab)
|
||||
public void selectFile() {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("application/zip");
|
||||
startActivityForResult(intent, FETCH_ZIP_CODE);
|
||||
}
|
||||
|
||||
private List<Module> listModules = new ArrayList<>();
|
||||
|
||||
@@ -46,12 +49,6 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener<
|
||||
View view = inflater.inflate(R.layout.fragment_modules, container, false);
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
fabio.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("application/zip");
|
||||
startActivityForResult(intent, FETCH_ZIP_CODE);
|
||||
});
|
||||
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
new LoadModules(getActivity()).exec();
|
||||
@@ -69,40 +66,30 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener<
|
||||
}
|
||||
});
|
||||
|
||||
if (getApplication().moduleLoadDone.isTriggered) {
|
||||
updateUI();
|
||||
}
|
||||
getActivity().setTitle(R.string.modules);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackEvent<Void> event) {
|
||||
public void onTopicPublished(Topic topic) {
|
||||
Logger.dev("ModulesFragment: UI refresh triggered");
|
||||
updateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Topic[] getSubscription() {
|
||||
return new Topic[] { getApplication().moduleLoadDone };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||
// Get the URI of the selected file
|
||||
final Uri uri = data.getData();
|
||||
new FlashZip(getActivity(), uri).exec();
|
||||
Intent intent = new Intent(getActivity(), FlashActivity.class);
|
||||
intent.setData(data.getData()).putExtra("ACTION", "flash");
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getApplication().moduleLoadDone.register(this);
|
||||
getActivity().setTitle(R.string.modules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
getApplication().moduleLoadDone.unRegister(this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -14,39 +13,23 @@ import android.widget.SearchView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||
import com.topjohnwu.magisk.adapters.SimpleSectionedRecyclerViewAdapter;
|
||||
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class ReposFragment extends Fragment implements CallbackEvent.Listener<Void> {
|
||||
public class ReposFragment extends Fragment implements Topic.Subscriber {
|
||||
|
||||
private Unbinder unbinder;
|
||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||
|
||||
private List<Repo> mUpdateRepos = new ArrayList<>();
|
||||
private List<Repo> mInstalledRepos = new ArrayList<>();
|
||||
private List<Repo> mOthersRepos = new ArrayList<>();
|
||||
private List<Repo> fUpdateRepos = new ArrayList<>();
|
||||
private List<Repo> fInstalledRepos = new ArrayList<>();
|
||||
private List<Repo> fOthersRepos = new ArrayList<>();
|
||||
|
||||
private SimpleSectionedRecyclerViewAdapter mSectionedAdapter;
|
||||
|
||||
private SearchView.OnQueryTextListener searchListener;
|
||||
private ReposAdapter adapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
@@ -60,24 +43,40 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
|
||||
View view = inflater.inflate(R.layout.fragment_repos, container, false);
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
mSectionedAdapter = new SimpleSectionedRecyclerViewAdapter(R.layout.section,
|
||||
R.id.section_text, new ReposAdapter(fUpdateRepos, fInstalledRepos, fOthersRepos));
|
||||
|
||||
recyclerView.setAdapter(mSectionedAdapter);
|
||||
adapter = new ReposAdapter(getApplication().repoDB, getApplication().moduleMap);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
mSwipeRefreshLayout.setRefreshing(true);
|
||||
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
new LoadRepos(getActivity()).exec();
|
||||
new UpdateRepos(getActivity()).exec();
|
||||
});
|
||||
|
||||
if (getApplication().repoLoadDone.isTriggered) {
|
||||
reloadRepos();
|
||||
updateUI();
|
||||
}
|
||||
getActivity().setTitle(R.string.downloads);
|
||||
|
||||
searchListener = new SearchView.OnQueryTextListener() {
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTopicPublished(Topic topic) {
|
||||
Logger.dev("ReposFragment: UI refresh triggered");
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
adapter.notifyDBChanged();
|
||||
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
||||
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Topic[] getSubscription() {
|
||||
return new Topic[] { getApplication().repoLoadDone };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_repo, menu);
|
||||
SearchView search = (SearchView) menu.findItem(R.id.repo_search).getActionView();
|
||||
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
return false;
|
||||
@@ -85,39 +84,10 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
new FilterApps().exec(newText);
|
||||
adapter.filter(newText);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(CallbackEvent<Void> event) {
|
||||
Logger.dev("ReposFragment: UI refresh triggered");
|
||||
reloadRepos();
|
||||
updateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_repo, menu);
|
||||
SearchView search = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.repo_search));
|
||||
search.setOnQueryTextListener(searchListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getApplication().repoLoadDone.register(this);
|
||||
getActivity().setTitle(R.string.downloads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
getApplication().repoLoadDone.unRegister(this);
|
||||
super.onStop();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,92 +95,4 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
|
||||
super.onDestroyView();
|
||||
unbinder.unbind();
|
||||
}
|
||||
|
||||
private void reloadRepos() {
|
||||
mUpdateRepos.clear();
|
||||
mInstalledRepos.clear();
|
||||
mOthersRepos.clear();
|
||||
for (Repo repo : getApplication().repoMap.values()) {
|
||||
Module module = getApplication().moduleMap.get(repo.getId());
|
||||
if (module != null) {
|
||||
if (repo.getVersionCode() > module.getVersionCode()) {
|
||||
mUpdateRepos.add(repo);
|
||||
} else {
|
||||
mInstalledRepos.add(repo);
|
||||
}
|
||||
} else {
|
||||
mOthersRepos.add(repo);
|
||||
}
|
||||
}
|
||||
fUpdateRepos.clear();
|
||||
fInstalledRepos.clear();
|
||||
fOthersRepos.clear();
|
||||
fUpdateRepos.addAll(mUpdateRepos);
|
||||
fInstalledRepos.addAll(mInstalledRepos);
|
||||
fOthersRepos.addAll(mOthersRepos);
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
if (fUpdateRepos.size() + fInstalledRepos.size() + fOthersRepos.size() == 0) {
|
||||
emptyRv.setVisibility(View.VISIBLE);
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
} else {
|
||||
List<SimpleSectionedRecyclerViewAdapter.Section> sections = new ArrayList<>();
|
||||
if (!fUpdateRepos.isEmpty()) {
|
||||
sections.add(new SimpleSectionedRecyclerViewAdapter.Section(0, getString(R.string.update_available)));
|
||||
}
|
||||
if (!fInstalledRepos.isEmpty()) {
|
||||
sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size(), getString(R.string.installed)));
|
||||
}
|
||||
if (!fOthersRepos.isEmpty()) {
|
||||
sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size() + fInstalledRepos.size(), getString(R.string.not_installed)));
|
||||
}
|
||||
SimpleSectionedRecyclerViewAdapter.Section[] array = sections.toArray(new SimpleSectionedRecyclerViewAdapter.Section[sections.size()]);
|
||||
mSectionedAdapter.setSections(array);
|
||||
emptyRv.setVisibility(View.GONE);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
|
||||
private class FilterApps extends ParallelTask<String, Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground(String... strings) {
|
||||
String newText = strings[0];
|
||||
fUpdateRepos.clear();
|
||||
fInstalledRepos.clear();
|
||||
fOthersRepos.clear();
|
||||
for (Repo repo: mUpdateRepos) {
|
||||
if (repo.getName().toLowerCase().contains(newText.toLowerCase())
|
||||
|| repo.getAuthor().toLowerCase().contains(newText.toLowerCase())
|
||||
|| repo.getDescription().toLowerCase().contains(newText.toLowerCase())
|
||||
) {
|
||||
fUpdateRepos.add(repo);
|
||||
}
|
||||
}
|
||||
for (Repo repo: mInstalledRepos) {
|
||||
if (repo.getName().toLowerCase().contains(newText.toLowerCase())
|
||||
|| repo.getAuthor().toLowerCase().contains(newText.toLowerCase())
|
||||
|| repo.getDescription().toLowerCase().contains(newText.toLowerCase())
|
||||
) {
|
||||
fInstalledRepos.add(repo);
|
||||
}
|
||||
}
|
||||
for (Repo repo: mOthersRepos) {
|
||||
if (repo.getName().toLowerCase().contains(newText.toLowerCase())
|
||||
|| repo.getAuthor().toLowerCase().contains(newText.toLowerCase())
|
||||
|| repo.getDescription().toLowerCase().contains(newText.toLowerCase())
|
||||
) {
|
||||
fOthersRepos.add(repo);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -13,18 +13,19 @@ import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class SettingsActivity extends Activity {
|
||||
public class SettingsActivity extends Activity implements Topic.Subscriber {
|
||||
|
||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||
|
||||
@@ -56,14 +57,26 @@ public class SettingsActivity extends Activity {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTopicPublished(Topic topic) {
|
||||
recreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Topic[] getSubscription() {
|
||||
return new Topic[] { getApplicationContext().reloadActivity };
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragment
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener,
|
||||
Topic.Subscriber {
|
||||
|
||||
private SharedPreferences prefs;
|
||||
private PreferenceScreen prefScreen;
|
||||
|
||||
private ListPreference suAccess, autoRes, suNotification, requestTimeout, multiuserMode, namespaceMode;
|
||||
private MagiskManager magiskManager;
|
||||
private PreferenceCategory generalCatagory;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -73,6 +86,7 @@ public class SettingsActivity extends Activity {
|
||||
prefScreen = getPreferenceScreen();
|
||||
magiskManager = Utils.getMagiskManager(getActivity());
|
||||
|
||||
generalCatagory = (PreferenceCategory) findPreference("general");
|
||||
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
|
||||
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
|
||||
PreferenceCategory developer = (PreferenceCategory) findPreference("developer");
|
||||
@@ -120,16 +134,42 @@ public class SettingsActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private void setLocalePreference(ListPreference lp) {
|
||||
boolean isNew = lp == null;
|
||||
if (isNew) {
|
||||
lp = new ListPreference(getActivity());
|
||||
}
|
||||
CharSequence[] entries = new CharSequence[magiskManager.locales.size() + 1];
|
||||
CharSequence[] entryValues = new CharSequence[magiskManager.locales.size() + 1];
|
||||
entries[0] = getString(R.string.system_default);
|
||||
entryValues[0] = "";
|
||||
int i = 1;
|
||||
for (Locale locale : magiskManager.locales) {
|
||||
entries[i] = locale.getDisplayName(locale);
|
||||
entryValues[i++] = locale.toLanguageTag();
|
||||
}
|
||||
lp.setEntries(entries);
|
||||
lp.setEntryValues(entryValues);
|
||||
lp.setTitle(R.string.language);
|
||||
lp.setKey("locale");
|
||||
lp.setSummary(MagiskManager.locale.getDisplayName(MagiskManager.locale));
|
||||
if (isNew) {
|
||||
generalCatagory.addPreference(lp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
subscribeTopics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
prefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||
unsubscribeTopics();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,44 +182,34 @@ public class SettingsActivity extends Activity {
|
||||
enabled = prefs.getBoolean("dark_theme", false);
|
||||
if (magiskManager.isDarkTheme != enabled) {
|
||||
magiskManager.isDarkTheme = enabled;
|
||||
magiskManager.reloadMainActivity.trigger();
|
||||
getActivity().recreate();
|
||||
magiskManager.reloadActivity.publish(false);
|
||||
}
|
||||
break;
|
||||
case "disable":
|
||||
enabled = prefs.getBoolean("disable", false);
|
||||
if (enabled) {
|
||||
Utils.createFile(MagiskManager.MAGISK_DISABLE_FILE);
|
||||
Utils.createFile(Shell.getShell(magiskManager), MagiskManager.MAGISK_DISABLE_FILE);
|
||||
} else {
|
||||
Utils.removeItem(MagiskManager.MAGISK_DISABLE_FILE);
|
||||
Utils.removeItem(Shell.getShell(magiskManager), MagiskManager.MAGISK_DISABLE_FILE);
|
||||
}
|
||||
Toast.makeText(getActivity(), R.string.settings_reboot_toast, Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case "magiskhide":
|
||||
enabled = prefs.getBoolean("magiskhide", false);
|
||||
if (enabled) {
|
||||
if (!magiskManager.isSuClient) {
|
||||
new AlertDialogBuilder(getActivity())
|
||||
.setTitle(R.string.no_magisksu_title)
|
||||
.setMessage(R.string.no_magisksu_msg)
|
||||
.setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide().enable())
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
} else {
|
||||
new MagiskHide().enable();
|
||||
}
|
||||
Utils.enableMagiskHide(Shell.getShell(magiskManager));
|
||||
} else {
|
||||
new MagiskHide().disable();
|
||||
Utils.disableMagiskHide(Shell.getShell(magiskManager));
|
||||
}
|
||||
break;
|
||||
case "hosts":
|
||||
enabled = prefs.getBoolean("hosts", false);
|
||||
if (enabled) {
|
||||
Shell.su_async(null,
|
||||
Shell.getShell(magiskManager).su_raw(
|
||||
"cp -af /system/etc/hosts /magisk/.core/hosts",
|
||||
"mount -o bind /magisk/.core/hosts /system/etc/hosts");
|
||||
} else {
|
||||
Shell.su_async(null,
|
||||
Shell.getShell(magiskManager).su_raw(
|
||||
"umount -l /system/etc/hosts",
|
||||
"rm -f /magisk/.core/hosts");
|
||||
}
|
||||
@@ -211,6 +241,10 @@ public class SettingsActivity extends Activity {
|
||||
case "shell_logging":
|
||||
MagiskManager.shellLogging = prefs.getBoolean("shell_logging", false);
|
||||
break;
|
||||
case "locale":
|
||||
magiskManager.setLocale();
|
||||
magiskManager.reloadActivity.publish(false);
|
||||
break;
|
||||
}
|
||||
setSummary();
|
||||
}
|
||||
@@ -229,6 +263,16 @@ public class SettingsActivity extends Activity {
|
||||
namespaceMode.setSummary(getResources()
|
||||
.getStringArray(R.array.namespace_summary)[magiskManager.suNamespaceMode]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTopicPublished(Topic topic) {
|
||||
setLocalePreference((ListPreference) findPreference("locale"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Topic[] getSubscription() {
|
||||
return new Topic[] { magiskManager.localeDone };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -8,10 +8,8 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.GetBootBlocks;
|
||||
import com.topjohnwu.magisk.asyncs.LoadApps;
|
||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
@@ -25,13 +23,16 @@ public class SplashActivity extends Activity{
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Init the info and configs and root shell
|
||||
getApplicationContext().init();
|
||||
MagiskManager magiskManager = getApplicationContext();
|
||||
|
||||
// Now fire all async tasks
|
||||
new GetBootBlocks(this).exec();
|
||||
new LoadModules(this).setCallBack(() -> new LoadRepos(this).exec()).exec();
|
||||
new LoadApps(this).exec();
|
||||
// Init the info and configs and root sh
|
||||
magiskManager.init();
|
||||
|
||||
// Get possible additional info from intent
|
||||
magiskManager.remoteMagiskVersionString = getIntent().getStringExtra(MagiskManager.INTENT_VERSION);
|
||||
magiskManager.magiskLink = getIntent().getStringExtra(MagiskManager.INTENT_LINK);
|
||||
|
||||
LoadModules loadModuleTask = new LoadModules(this);
|
||||
|
||||
if (Utils.checkNetworkStatus(this)) {
|
||||
// Initialize the update check service, notify every 8 hours
|
||||
@@ -42,11 +43,13 @@ public class SplashActivity extends Activity{
|
||||
.setPersisted(true)
|
||||
.setPeriodic(8 * 60 * 60 * 1000)
|
||||
.build();
|
||||
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
scheduler.schedule(jobInfo);
|
||||
((JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(jobInfo);
|
||||
}
|
||||
loadModuleTask.setCallBack(() -> new UpdateRepos(getApplication()).exec());
|
||||
}
|
||||
|
||||
loadModuleTask.exec();
|
||||
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION);
|
||||
if (section != null) {
|
||||
|
@@ -13,9 +13,6 @@ import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.SuLogAdapter;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
@@ -28,6 +25,7 @@ public class SuLogFragment extends Fragment {
|
||||
|
||||
private Unbinder unbinder;
|
||||
private MagiskManager magiskManager;
|
||||
private SuLogAdapter adapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
@@ -48,6 +46,8 @@ public class SuLogFragment extends Fragment {
|
||||
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
||||
unbinder = ButterKnife.bind(this, v);
|
||||
magiskManager = getApplication();
|
||||
adapter = new SuLogAdapter(magiskManager.suDB);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
updateList();
|
||||
|
||||
@@ -55,13 +55,12 @@ public class SuLogFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
List<SuLogEntry> logs = magiskManager.suDB.getLogList();
|
||||
adapter.notifyDBChanged();
|
||||
|
||||
if (logs.size() == 0) {
|
||||
if (adapter.getSectionCount() == 0) {
|
||||
emptyRv.setVisibility(View.VISIBLE);
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
} else {
|
||||
recyclerView.setAdapter(new SuLogAdapter(logs).getAdapter());
|
||||
emptyRv.setVisibility(View.GONE);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.topjohnwu.magisk.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.design.widget.Snackbar;
|
||||
@@ -13,13 +14,16 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
@@ -40,20 +44,19 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
||||
|
||||
private List<ApplicationInfo> mOriginalList, mList;
|
||||
private List<String> mHideList;
|
||||
private PackageManager packageManager;
|
||||
private PackageManager pm;
|
||||
private ApplicationFilter filter;
|
||||
private Topic magiskHideDone;
|
||||
private Shell shell;
|
||||
|
||||
public ApplicationAdapter(PackageManager packageManager) {
|
||||
public ApplicationAdapter(Context context) {
|
||||
mOriginalList = mList = Collections.emptyList();
|
||||
mHideList = Collections.emptyList();
|
||||
this.packageManager = packageManager;
|
||||
filter = new ApplicationFilter();
|
||||
}
|
||||
|
||||
public void setLists(List<ApplicationInfo> listApps, List<String> hideList) {
|
||||
mOriginalList = mList = listApps;
|
||||
mHideList = hideList;
|
||||
notifyDataSetChanged();
|
||||
pm = context.getPackageManager();
|
||||
magiskHideDone = Utils.getMagiskManager(context).magiskHideDone;
|
||||
shell = Shell.getShell(context);
|
||||
new LoadApps().exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,8 +69,8 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
ApplicationInfo info = mList.get(position);
|
||||
|
||||
holder.appIcon.setImageDrawable(info.loadIcon(packageManager));
|
||||
holder.appName.setText(info.loadLabel(packageManager));
|
||||
holder.appIcon.setImageDrawable(info.loadIcon(pm));
|
||||
holder.appName.setText(info.loadLabel(pm));
|
||||
holder.appPackage.setText(info.packageName);
|
||||
|
||||
// Remove all listeners
|
||||
@@ -86,10 +89,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
||||
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||
if (isChecked) {
|
||||
new MagiskHide().add(info.packageName);
|
||||
Utils.addMagiskHide(shell, info.packageName);
|
||||
mHideList.add(info.packageName);
|
||||
} else {
|
||||
new MagiskHide().rm(info.packageName);
|
||||
Utils.rmMagiskHide(shell, info.packageName);
|
||||
mHideList.remove(info.packageName);
|
||||
}
|
||||
});
|
||||
@@ -105,6 +108,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
||||
filter.filter(constraint);
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
new LoadApps().exec();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@BindView(R.id.app_icon) ImageView appIcon;
|
||||
@@ -122,31 +129,47 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
||||
|
||||
@Override
|
||||
protected FilterResults performFiltering(CharSequence constraint) {
|
||||
List<ApplicationInfo> filteredApps;
|
||||
if (constraint == null || constraint.length() == 0) {
|
||||
filteredApps = mOriginalList;
|
||||
mList = mOriginalList;
|
||||
} else {
|
||||
filteredApps = new ArrayList<>();
|
||||
mList = new ArrayList<>();
|
||||
String filter = constraint.toString().toLowerCase();
|
||||
for (ApplicationInfo info : mOriginalList) {
|
||||
if (Utils.lowercaseContains(info.loadLabel(packageManager), filter)
|
||||
if (Utils.lowercaseContains(info.loadLabel(pm), filter)
|
||||
|| Utils.lowercaseContains(info.packageName, filter)) {
|
||||
filteredApps.add(info);
|
||||
mList.add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FilterResults results = new FilterResults();
|
||||
results.values = filteredApps;
|
||||
results.count = filteredApps.size();
|
||||
return results;
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void publishResults(CharSequence constraint, FilterResults results) {
|
||||
mList = (List<ApplicationInfo>) results.values;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private class LoadApps extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
mOriginalList = pm.getInstalledApplications(0);
|
||||
for (Iterator<ApplicationInfo> i = mOriginalList.iterator(); i.hasNext(); ) {
|
||||
ApplicationInfo info = i.next();
|
||||
if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
Collections.sort(mOriginalList, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
|
||||
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
|
||||
mHideList = Utils.listMagiskHide(shell);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
magiskHideDone.publish(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -38,6 +38,7 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
Context context = holder.itemView.getContext();
|
||||
Shell rootShell = Shell.getShell(context);
|
||||
final Module module = mList.get(position);
|
||||
|
||||
String version = module.getVersion();
|
||||
@@ -55,10 +56,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||
int snack;
|
||||
if (isChecked) {
|
||||
module.removeDisableFile();
|
||||
module.removeDisableFile(rootShell);
|
||||
snack = R.string.disable_file_removed;
|
||||
} else {
|
||||
module.createDisableFile();
|
||||
module.createDisableFile(rootShell);
|
||||
snack = R.string.disable_file_created;
|
||||
}
|
||||
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||
@@ -68,10 +69,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
||||
boolean removed = module.willBeRemoved();
|
||||
int snack;
|
||||
if (removed) {
|
||||
module.deleteRemoveFile();
|
||||
module.deleteRemoveFile(rootShell);
|
||||
snack = R.string.remove_file_deleted;
|
||||
} else {
|
||||
module.createRemoveFile();
|
||||
module.createRemoveFile(rootShell);
|
||||
snack = R.string.remove_file_created;
|
||||
}
|
||||
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||
|
@@ -2,9 +2,11 @@ package com.topjohnwu.magisk.adapters;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -13,72 +15,113 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
||||
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
import com.topjohnwu.magisk.components.MarkDownWindow;
|
||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> {
|
||||
public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, ReposAdapter.RepoHolder> {
|
||||
|
||||
private List<Repo> mUpdateRepos, mInstalledRepos, mOthersRepos;
|
||||
private Context mContext;
|
||||
private static final int UPDATES = 0;
|
||||
private static final int INSTALLED = 1;
|
||||
private static final int OTHERS = 2;
|
||||
|
||||
public ReposAdapter(List<Repo> update, List<Repo> installed, List<Repo> others) {
|
||||
mUpdateRepos = update;
|
||||
mInstalledRepos = installed;
|
||||
mOthersRepos = others;
|
||||
private Cursor repoCursor = null;
|
||||
private Map<String, Module> moduleMap;
|
||||
private RepoDatabaseHelper repoDB;
|
||||
private List<Pair<Integer, List<Repo>>> repoPairs;
|
||||
|
||||
public ReposAdapter(RepoDatabaseHelper db, Map<String, Module> map) {
|
||||
repoDB = db;
|
||||
moduleMap = map;
|
||||
repoPairs = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return repoPairs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
mContext = parent.getContext();
|
||||
View v = LayoutInflater.from(mContext).inflate(R.layout.list_item_repo, parent, false);
|
||||
return new ViewHolder(v);
|
||||
public int getItemCount(int section) {
|
||||
return repoPairs.get(section).second.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
Repo repo = getItem(position);
|
||||
public SectionHolder onCreateSectionViewHolder(ViewGroup parent) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.section, parent, false);
|
||||
return new SectionHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepoHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false);
|
||||
return new RepoHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindSectionViewHolder(SectionHolder holder, int section) {
|
||||
switch (repoPairs.get(section).first) {
|
||||
case UPDATES:
|
||||
holder.sectionText.setText(R.string.update_available);
|
||||
break;
|
||||
case INSTALLED:
|
||||
holder.sectionText.setText(R.string.installed);
|
||||
break;
|
||||
case OTHERS:
|
||||
holder.sectionText.setText(R.string.not_installed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindItemViewHolder(RepoHolder holder, int section, int position) {
|
||||
Repo repo = repoPairs.get(section).second.get(position);
|
||||
Context context = holder.itemView.getContext();
|
||||
|
||||
holder.title.setText(repo.getName());
|
||||
holder.versionName.setText(repo.getVersion());
|
||||
String author = repo.getAuthor();
|
||||
holder.author.setText(TextUtils.isEmpty(author) ? null : mContext.getString(R.string.author, author));
|
||||
holder.author.setText(TextUtils.isEmpty(author) ? null : context.getString(R.string.author, author));
|
||||
holder.description.setText(repo.getDescription());
|
||||
|
||||
holder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), mContext));
|
||||
holder.infoLayout.setOnClickListener(v ->
|
||||
new MarkDownWindow((Activity) context, null, repo.getDetailUrl()).exec());
|
||||
|
||||
holder.downloadImage.setOnClickListener(v -> {
|
||||
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
|
||||
new AlertDialogBuilder(mContext)
|
||||
.setTitle(mContext.getString(R.string.repo_install_title, repo.getName()))
|
||||
.setMessage(mContext.getString(R.string.repo_install_msg, filename))
|
||||
new AlertDialogBuilder(context)
|
||||
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
|
||||
.setMessage(context.getString(R.string.repo_install_msg, filename))
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive(
|
||||
mContext,
|
||||
context,
|
||||
new DownloadReceiver() {
|
||||
@Override
|
||||
public void onDownloadDone(Uri uri) {
|
||||
Activity activity = (Activity) mContext;
|
||||
new ProcessRepoZip(activity, uri, true).exec();
|
||||
new ProcessRepoZip((Activity) context, uri, true).exec();
|
||||
}
|
||||
},
|
||||
repo.getZipUrl(),
|
||||
Utils.getLegalFilename(filename)))
|
||||
.setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive(
|
||||
mContext,
|
||||
context,
|
||||
new DownloadReceiver() {
|
||||
@Override
|
||||
public void onDownloadDone(Uri uri) {
|
||||
Activity activity = (Activity) mContext;
|
||||
new ProcessRepoZip(activity, uri, false).exec();
|
||||
new ProcessRepoZip((Activity) context, uri, false).exec();
|
||||
}
|
||||
},
|
||||
repo.getZipUrl(),
|
||||
@@ -88,26 +131,62 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mUpdateRepos.size() + mInstalledRepos.size() + mOthersRepos.size();
|
||||
public void notifyDBChanged() {
|
||||
if (repoCursor != null)
|
||||
repoCursor.close();
|
||||
repoCursor = repoDB.getRepoCursor();
|
||||
filter("");
|
||||
}
|
||||
|
||||
private Repo getItem(int position) {
|
||||
if (position >= mUpdateRepos.size()) {
|
||||
position -= mUpdateRepos.size();
|
||||
if (position >= mInstalledRepos.size()) {
|
||||
position -= mInstalledRepos.size();
|
||||
return mOthersRepos.get(position);
|
||||
} else {
|
||||
return mInstalledRepos.get(position);
|
||||
public void filter(String s) {
|
||||
List<Repo> updates = new ArrayList<>();
|
||||
List<Repo> installed = new ArrayList<>();
|
||||
List<Repo> others = new ArrayList<>();
|
||||
|
||||
repoPairs.clear();
|
||||
while (repoCursor.moveToNext()) {
|
||||
Repo repo = new Repo(repoCursor);
|
||||
if (repo.getName().toLowerCase().contains(s.toLowerCase())
|
||||
|| repo.getAuthor().toLowerCase().contains(s.toLowerCase())
|
||||
|| repo.getDescription().toLowerCase().contains(s.toLowerCase())
|
||||
) {
|
||||
// Passed the repoFilter
|
||||
Module module = moduleMap.get(repo.getId());
|
||||
if (module != null) {
|
||||
if (repo.getVersionCode() > module.getVersionCode()) {
|
||||
// Updates
|
||||
updates.add(repo);
|
||||
} else {
|
||||
installed.add(repo);
|
||||
}
|
||||
} else {
|
||||
others.add(repo);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return mUpdateRepos.get(position);
|
||||
}
|
||||
repoCursor.moveToFirst();
|
||||
|
||||
if (!updates.isEmpty())
|
||||
repoPairs.add(new Pair<>(UPDATES, updates));
|
||||
if (!installed.isEmpty())
|
||||
repoPairs.add(new Pair<>(INSTALLED, installed));
|
||||
if (!others.isEmpty())
|
||||
repoPairs.add(new Pair<>(OTHERS, others));
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
static class SectionHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@BindView(R.id.section_text) TextView sectionText;
|
||||
|
||||
SectionHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
static class RepoHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@BindView(R.id.title) TextView title;
|
||||
@BindView(R.id.version_name) TextView versionName;
|
||||
@@ -116,7 +195,7 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
|
||||
@BindView(R.id.info_layout) LinearLayout infoLayout;
|
||||
@BindView(R.id.download) ImageView downloadImage;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
RepoHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
|
@@ -0,0 +1,93 @@
|
||||
package com.topjohnwu.magisk.adapters;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public abstract class SectionedAdapter<S extends RecyclerView.ViewHolder, C extends RecyclerView.ViewHolder>
|
||||
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private static final int SECTION_TYPE = Integer.MIN_VALUE;
|
||||
|
||||
@Override
|
||||
final public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
if (viewType == SECTION_TYPE)
|
||||
return onCreateSectionViewHolder(parent);
|
||||
return onCreateItemViewHolder(parent, viewType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
final public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
PositionInfo info = getPositionInfo(position);
|
||||
if (info.position == -1)
|
||||
onBindSectionViewHolder((S) holder, info.section);
|
||||
else
|
||||
onBindItemViewHolder((C) holder, info.section, info.position);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public int getItemCount() {
|
||||
int size, sec;
|
||||
size = sec = getSectionCount();
|
||||
for (int i = 0; i < sec; ++i){
|
||||
size += getItemCount(i);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
final public int getItemViewType(int position) {
|
||||
PositionInfo info = getPositionInfo(position);
|
||||
if (info.position == -1)
|
||||
return SECTION_TYPE;
|
||||
else
|
||||
return getItemViewType(info.section, info.position);
|
||||
}
|
||||
|
||||
public int getItemViewType(int section, int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int getSectionPosition(int section) {
|
||||
return getItemPosition(section, -1);
|
||||
}
|
||||
|
||||
protected int getItemPosition(int section, int position) {
|
||||
int realPosition = 0;
|
||||
// Previous sections
|
||||
for (int i = 0; i < section; ++i) {
|
||||
realPosition += getItemCount(i) + 1;
|
||||
}
|
||||
// Current section
|
||||
realPosition += position + 1;
|
||||
return realPosition;
|
||||
}
|
||||
|
||||
private PositionInfo getPositionInfo(int position) {
|
||||
int section = 0;
|
||||
while (true) {
|
||||
if (position == 0)
|
||||
return new PositionInfo(section, -1);
|
||||
position -= 1;
|
||||
if (position < getItemCount(section))
|
||||
return new PositionInfo(section, position);
|
||||
position -= getItemCount(section++);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PositionInfo {
|
||||
int section;
|
||||
int position;
|
||||
PositionInfo(int section, int position) {
|
||||
this.section = section;
|
||||
this.position = position;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract int getSectionCount();
|
||||
public abstract int getItemCount(int section);
|
||||
public abstract S onCreateSectionViewHolder(ViewGroup parent);
|
||||
public abstract C onCreateItemViewHolder(ViewGroup parent, int viewType);
|
||||
public abstract void onBindSectionViewHolder(S holder, int section);
|
||||
public abstract void onBindItemViewHolder(C holder, int section, int position);
|
||||
}
|
@@ -1,178 +0,0 @@
|
||||
package com.topjohnwu.magisk.adapters;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class SimpleSectionedRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private static final int SECTION_TYPE = 0;
|
||||
|
||||
private boolean mValid = true;
|
||||
private int mSectionResourceId;
|
||||
private int mTextResourceId;
|
||||
private RecyclerView.Adapter mBaseAdapter;
|
||||
private SparseArray<Section> mSections = new SparseArray<Section>();
|
||||
|
||||
|
||||
public SimpleSectionedRecyclerViewAdapter(int sectionResourceId, int textResourceId,
|
||||
RecyclerView.Adapter baseAdapter) {
|
||||
|
||||
mSectionResourceId = sectionResourceId;
|
||||
mTextResourceId = textResourceId;
|
||||
mBaseAdapter = baseAdapter;
|
||||
|
||||
mBaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
mValid = mBaseAdapter.getItemCount()>0;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeChanged(int positionStart, int itemCount) {
|
||||
mValid = mBaseAdapter.getItemCount()>0;
|
||||
notifyItemRangeChanged(positionStart, itemCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeInserted(int positionStart, int itemCount) {
|
||||
mValid = mBaseAdapter.getItemCount()>0;
|
||||
notifyItemRangeInserted(positionStart, itemCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeRemoved(int positionStart, int itemCount) {
|
||||
mValid = mBaseAdapter.getItemCount()>0;
|
||||
notifyItemRangeRemoved(positionStart, itemCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static class SectionViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public TextView title;
|
||||
|
||||
public SectionViewHolder(View view, int mTextResourceid) {
|
||||
super(view);
|
||||
title = (TextView) view.findViewById(mTextResourceid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int typeView) {
|
||||
if (typeView == SECTION_TYPE) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(mSectionResourceId, parent, false);
|
||||
return new SectionViewHolder(view,mTextResourceId);
|
||||
}else{
|
||||
return mBaseAdapter.onCreateViewHolder(parent, typeView -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) {
|
||||
if (isSectionHeaderPosition(position)) {
|
||||
((SectionViewHolder)sectionViewHolder).title.setText(mSections.get(position).title);
|
||||
}else{
|
||||
mBaseAdapter.onBindViewHolder(sectionViewHolder,sectionedPositionToPosition(position));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return isSectionHeaderPosition(position)
|
||||
? SECTION_TYPE
|
||||
: mBaseAdapter.getItemViewType(sectionedPositionToPosition(position)) +1 ;
|
||||
}
|
||||
|
||||
|
||||
public static class Section {
|
||||
int firstPosition;
|
||||
int sectionedPosition;
|
||||
CharSequence title;
|
||||
|
||||
public Section(int firstPosition, CharSequence title) {
|
||||
this.firstPosition = firstPosition;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public CharSequence getTitle() {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setSections(Section[] sections) {
|
||||
mSections.clear();
|
||||
|
||||
Arrays.sort(sections, new Comparator<Section>() {
|
||||
@Override
|
||||
public int compare(Section o, Section o1) {
|
||||
return (o.firstPosition == o1.firstPosition)
|
||||
? 0
|
||||
: ((o.firstPosition < o1.firstPosition) ? -1 : 1);
|
||||
}
|
||||
});
|
||||
|
||||
int offset = 0; // offset positions for the headers we're adding
|
||||
for (Section section : sections) {
|
||||
section.sectionedPosition = section.firstPosition + offset;
|
||||
mSections.append(section.sectionedPosition, section);
|
||||
++offset;
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public int positionToSectionedPosition(int position) {
|
||||
int offset = 0;
|
||||
for (int i = 0; i < mSections.size(); i++) {
|
||||
if (mSections.valueAt(i).firstPosition > position) {
|
||||
break;
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
return position + offset;
|
||||
}
|
||||
|
||||
public int sectionedPositionToPosition(int sectionedPosition) {
|
||||
if (isSectionHeaderPosition(sectionedPosition)) {
|
||||
return RecyclerView.NO_POSITION;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < mSections.size(); i++) {
|
||||
if (mSections.valueAt(i).sectionedPosition > sectionedPosition) {
|
||||
break;
|
||||
}
|
||||
--offset;
|
||||
}
|
||||
return sectionedPosition + offset;
|
||||
}
|
||||
|
||||
public boolean isSectionHeaderPosition(int position) {
|
||||
return mSections.get(position) != null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return isSectionHeaderPosition(position)
|
||||
? Integer.MAX_VALUE - mSections.indexOfKey(position)
|
||||
: mBaseAdapter.getItemId(sectionedPositionToPosition(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return (mValid ? mBaseAdapter.getItemCount() + mSections.size() : 0);
|
||||
}
|
||||
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package com.topjohnwu.magisk.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -10,147 +10,125 @@ import android.view.animation.RotateAnimation;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.thoughtbot.expandablerecyclerview.ExpandableRecyclerViewAdapter;
|
||||
import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;
|
||||
import com.thoughtbot.expandablerecyclerview.viewholders.ChildViewHolder;
|
||||
import com.thoughtbot.expandablerecyclerview.viewholders.GroupViewHolder;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.components.ExpandableViewHolder;
|
||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class SuLogAdapter {
|
||||
public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, SuLogAdapter.LogViewHolder> {
|
||||
|
||||
private ExpandableAdapter adapter;
|
||||
private Set<SuLogEntry> expandList = new HashSet<>();
|
||||
private List<List<Integer>> logEntryList;
|
||||
private Set<Integer> itemExpanded, sectionExpanded;
|
||||
private SuDatabaseHelper suDB;
|
||||
private Cursor suLogCursor = null;
|
||||
|
||||
public SuLogAdapter(List<SuLogEntry> list) {
|
||||
public SuLogAdapter(SuDatabaseHelper db) {
|
||||
suDB = db;
|
||||
logEntryList = Collections.emptyList();
|
||||
sectionExpanded = new HashSet<>();
|
||||
itemExpanded = new HashSet<>();
|
||||
}
|
||||
|
||||
// Separate the logs with date
|
||||
Map<String, List<SuLogEntry>> logEntryMap = new LinkedHashMap<>();
|
||||
List<SuLogEntry> group;
|
||||
for (SuLogEntry log : list) {
|
||||
String date = log.getDateString();
|
||||
group = logEntryMap.get(date);
|
||||
if (group == null) {
|
||||
group = new ArrayList<>();
|
||||
logEntryMap.put(date, group);
|
||||
@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());
|
||||
}
|
||||
group.add(log);
|
||||
}
|
||||
|
||||
// Then format them into expandable groups
|
||||
List<LogGroup> logEntryGroups = new ArrayList<>();
|
||||
for (Map.Entry<String, List<SuLogEntry>> entry : logEntryMap.entrySet()) {
|
||||
logEntryGroups.add(new LogGroup(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
adapter = new ExpandableAdapter(logEntryGroups);
|
||||
|
||||
rotate.setDuration(300);
|
||||
rotate.setFillAfter(true);
|
||||
holder.arrow.setAnimation(rotate);
|
||||
});
|
||||
holder.date.setText(entry.getDateString());
|
||||
}
|
||||
|
||||
public RecyclerView.Adapter getAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
private class ExpandableAdapter
|
||||
extends ExpandableRecyclerViewAdapter<LogGroupViewHolder, LogViewHolder> {
|
||||
|
||||
ExpandableAdapter(List<? extends ExpandableGroup> groups) {
|
||||
super(groups);
|
||||
expandableList.expandedGroupIndexes[0] = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogGroupViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_sulog_group, parent, false);
|
||||
return new LogGroupViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogViewHolder onCreateChildViewHolder(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 onBindChildViewHolder(LogViewHolder holder, int flatPosition, ExpandableGroup group, int childIndex) {
|
||||
Context context = holder.itemView.getContext();
|
||||
SuLogEntry logEntry = (SuLogEntry) group.getItems().get(childIndex);
|
||||
holder.setExpanded(expandList.contains(logEntry));
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
if (holder.getExpanded()) {
|
||||
holder.collapse();
|
||||
expandList.remove(logEntry);
|
||||
} else {
|
||||
holder.expand();
|
||||
expandList.add(logEntry);
|
||||
}
|
||||
});
|
||||
holder.appName.setText(logEntry.appName);
|
||||
holder.action.setText(context.getString(logEntry.action ? R.string.grant : R.string.deny));
|
||||
holder.command.setText(logEntry.command);
|
||||
holder.fromPid.setText(String.valueOf(logEntry.fromPid));
|
||||
holder.toUid.setText(String.valueOf(logEntry.toUid));
|
||||
holder.time.setText(logEntry.getTimeString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindGroupViewHolder(LogGroupViewHolder holder, int flatPosition, ExpandableGroup group) {
|
||||
holder.date.setText(group.getTitle());
|
||||
if (isGroupExpanded(flatPosition)) {
|
||||
@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.mExpanded) {
|
||||
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());
|
||||
}
|
||||
|
||||
private class LogGroup extends ExpandableGroup<SuLogEntry> {
|
||||
LogGroup(String title, List<SuLogEntry> items) {
|
||||
super(title, items);
|
||||
}
|
||||
public void notifyDBChanged() {
|
||||
if (suLogCursor != null)
|
||||
suLogCursor.close();
|
||||
suLogCursor = suDB.getLogCursor();
|
||||
logEntryList = suDB.getLogStructure();
|
||||
itemExpanded.clear();
|
||||
sectionExpanded.clear();
|
||||
sectionExpanded.add(0);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
static class LogGroupViewHolder extends GroupViewHolder {
|
||||
static class SectionHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@BindView(R.id.date) TextView date;
|
||||
@BindView(R.id.arrow) ImageView arrow;
|
||||
|
||||
public LogGroupViewHolder(View itemView) {
|
||||
SectionHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expand() {
|
||||
RotateAnimation rotate =
|
||||
new RotateAnimation(360, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
|
||||
rotate.setDuration(300);
|
||||
rotate.setFillAfter(true);
|
||||
arrow.setAnimation(rotate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collapse() {
|
||||
RotateAnimation rotate =
|
||||
new RotateAnimation(180, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
|
||||
rotate.setDuration(300);
|
||||
rotate.setFillAfter(true);
|
||||
arrow.setAnimation(rotate);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper class
|
||||
static class LogViewHolder extends ChildViewHolder {
|
||||
|
||||
private InternalViewHolder expandableViewHolder;
|
||||
static class LogViewHolder extends ExpandableViewHolder {
|
||||
|
||||
@BindView(R.id.app_name) TextView appName;
|
||||
@BindView(R.id.action) TextView action;
|
||||
@@ -162,36 +140,11 @@ public class SuLogAdapter {
|
||||
LogViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
expandableViewHolder = new InternalViewHolder(itemView);
|
||||
}
|
||||
|
||||
private class InternalViewHolder extends ExpandableViewHolder {
|
||||
|
||||
InternalViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpandLayout(View itemView) {
|
||||
expandLayout = itemView.findViewById(R.id.expand_layout);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getExpanded() {
|
||||
return expandableViewHolder.mExpanded;
|
||||
}
|
||||
|
||||
private void setExpanded(boolean expanded) {
|
||||
expandableViewHolder.setExpanded(expanded);
|
||||
}
|
||||
|
||||
private void expand() {
|
||||
expandableViewHolder.expand();
|
||||
}
|
||||
|
||||
private void collapse() {
|
||||
expandableViewHolder.collapse();
|
||||
@Override
|
||||
public void setExpandLayout(View itemView) {
|
||||
expandLayout = itemView.findViewById(R.id.expand_layout);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.asyncs;
|
||||
import android.content.Context;
|
||||
|
||||
import com.topjohnwu.magisk.BuildConfig;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
@@ -13,21 +14,22 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
private static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/magisk_update.json";
|
||||
|
||||
|
||||
private boolean showNotification = false;
|
||||
|
||||
public CheckUpdates(Context context, boolean b) {
|
||||
this(context);
|
||||
showNotification = b;
|
||||
public CheckUpdates(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public CheckUpdates(Context context) {
|
||||
magiskManager = Utils.getMagiskManager(context);
|
||||
public CheckUpdates(Context context, boolean b) {
|
||||
super(context);
|
||||
showNotification = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
String jsonStr = WebService.request(UPDATE_JSON, WebService.GET);
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return null;
|
||||
String jsonStr = WebService.getString(UPDATE_JSON);
|
||||
try {
|
||||
JSONObject json = new JSONObject(jsonStr);
|
||||
JSONObject magisk = json.getJSONObject("magisk");
|
||||
@@ -45,15 +47,16 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return;
|
||||
if (showNotification && magiskManager.updateNotification) {
|
||||
if (magiskManager.magiskVersionCode < magiskManager.remoteMagiskVersionCode) {
|
||||
Utils.showMagiskUpdate(magiskManager);
|
||||
}
|
||||
if (BuildConfig.VERSION_CODE < magiskManager.remoteManagerVersionCode) {
|
||||
Utils.showManagerUpdate(magiskManager);
|
||||
} else if (magiskManager.magiskVersionCode < magiskManager.remoteMagiskVersionCode) {
|
||||
Utils.showMagiskUpdate(magiskManager);
|
||||
}
|
||||
}
|
||||
magiskManager.updateCheckDone.trigger();
|
||||
magiskManager.updateCheckDone.publish();
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,71 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
private static final String BUSYBOX_ARM = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.1/busybox-arm";
|
||||
private static final String BUSYBOX_X86 = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.1/busybox-x86";
|
||||
private static final String BUSYBOXPATH = "/dev/magisk/bin";
|
||||
|
||||
private File busybox;
|
||||
|
||||
public DownloadBusybox(Context context) {
|
||||
super(context);
|
||||
busybox = new File(context.getCacheDir(), "busybox");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
getShell().su_raw("export PATH=" + BUSYBOXPATH + ":$PATH");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
Context context = getMagiskManager();
|
||||
if (!Utils.itemExist(getShell(), BUSYBOXPATH + "/busybox")) {
|
||||
if (!busybox.exists() && Utils.checkNetworkStatus(context)) {
|
||||
Utils.removeItem(getShell(), context.getApplicationInfo().dataDir + "/busybox");
|
||||
try {
|
||||
FileOutputStream out = new FileOutputStream(busybox);
|
||||
InputStream in = WebService.request(WebService.GET,
|
||||
Build.SUPPORTED_32_BIT_ABIS[0].contains("x86") ?
|
||||
BUSYBOX_X86 :
|
||||
BUSYBOX_ARM,
|
||||
null
|
||||
);
|
||||
if (in == null) throw new IOException();
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
out.close();
|
||||
in.close();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (busybox.exists()) {
|
||||
getShell().su_raw(
|
||||
"rm -rf " + BUSYBOXPATH,
|
||||
"mkdir -p " + BUSYBOXPATH,
|
||||
"cp " + busybox + " " + BUSYBOXPATH,
|
||||
"chmod -R 755 " + BUSYBOXPATH,
|
||||
BUSYBOXPATH + "/busybox --install -s " + BUSYBOXPATH
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,15 +1,12 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.net.Uri;
|
||||
import android.widget.Toast;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.AdaptiveList;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||
|
||||
@@ -21,134 +18,104 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class FlashZip extends RootTask<Void, String, Integer> {
|
||||
public class FlashZip extends ParallelTask<Void, String, Integer> {
|
||||
|
||||
private Uri mUri;
|
||||
private File mCachedFile, mScriptFile, mCheckFile;
|
||||
|
||||
private String mFilename;
|
||||
private ProgressDialog progress;
|
||||
private AdaptiveList<String> mList;
|
||||
|
||||
public FlashZip(Activity context, Uri uri) {
|
||||
public FlashZip(Activity context, Uri uri, AdaptiveList<String> list) {
|
||||
super(context);
|
||||
mUri = uri;
|
||||
mList = list;
|
||||
|
||||
mCachedFile = new File(magiskManager.getCacheDir(), "install.zip");
|
||||
mScriptFile = new File(magiskManager.getCacheDir(), "/META-INF/com/google/android/update-binary");
|
||||
mCachedFile = new File(context.getCacheDir(), "install.zip");
|
||||
mScriptFile = new File(context.getCacheDir(), "/META-INF/com/google/android/update-binary");
|
||||
mCheckFile = new File(mScriptFile.getParent(), "updater-script");
|
||||
|
||||
// Try to get the filename ourselves
|
||||
mFilename = Utils.getNameFromUri(magiskManager, mUri);
|
||||
}
|
||||
|
||||
private void copyToCache() throws Throwable {
|
||||
publishProgress(magiskManager.getString(R.string.copying_msg));
|
||||
|
||||
if (mCachedFile.exists() && !mCachedFile.delete()) {
|
||||
Logger.error("FlashZip: Error while deleting already existing file");
|
||||
throw new IOException();
|
||||
}
|
||||
try (
|
||||
InputStream in = magiskManager.getContentResolver().openInputStream(mUri);
|
||||
OutputStream outputStream = new FileOutputStream(mCachedFile)
|
||||
) {
|
||||
byte buffer[] = new byte[1024];
|
||||
int length;
|
||||
if (in == null) throw new FileNotFoundException();
|
||||
while ((length = in.read(buffer)) > 0)
|
||||
outputStream.write(buffer, 0, length);
|
||||
|
||||
Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath());
|
||||
} catch (FileNotFoundException e) {
|
||||
Logger.error("FlashZip: Invalid Uri");
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
Logger.error("FlashZip: Error in creating file");
|
||||
throw e;
|
||||
}
|
||||
mFilename = Utils.getNameFromUri(context, mUri);
|
||||
}
|
||||
|
||||
private boolean unzipAndCheck() throws Exception {
|
||||
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android");
|
||||
List<String> ret;
|
||||
ret = Utils.readFile(mCheckFile.getPath());
|
||||
List<String> ret = Utils.readFile(getShell(), mCheckFile.getPath());
|
||||
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
|
||||
}
|
||||
|
||||
private int cleanup(int ret) {
|
||||
Shell.su(
|
||||
"rm -rf " + mCachedFile.getParent() + "/*",
|
||||
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
progress = new ProgressDialog(activity);
|
||||
progress.setTitle(R.string.zip_install_progress_title);
|
||||
progress.show();
|
||||
// UI updates must run in the UI thread
|
||||
mList.setCallback(this::publishProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(String... values) {
|
||||
progress.setMessage(values[0]);
|
||||
mList.updateView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInRoot(Void... voids) {
|
||||
Logger.dev("FlashZip Running... " + mFilename);
|
||||
List<String> ret;
|
||||
protected Integer doInBackground(Void... voids) {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return -1;
|
||||
try {
|
||||
copyToCache();
|
||||
if (!unzipAndCheck()) return cleanup(0);
|
||||
publishProgress(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
|
||||
ret = Shell.su(
|
||||
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile,
|
||||
"if [ $? -eq 0 ]; then echo true; else echo false; fi"
|
||||
);
|
||||
if (!Utils.isValidShellResponse(ret)) return -1;
|
||||
Logger.dev("FlashZip: Console log:");
|
||||
for (String line : ret) {
|
||||
Logger.dev(line);
|
||||
}
|
||||
if (Boolean.parseBoolean(ret.get(ret.size() - 1)))
|
||||
return cleanup(1);
|
||||
mList.add(magiskManager.getString(R.string.copying_msg));
|
||||
|
||||
} catch (Throwable e) {
|
||||
mCachedFile.delete();
|
||||
try (
|
||||
InputStream in = magiskManager.getContentResolver().openInputStream(mUri);
|
||||
OutputStream outputStream = new FileOutputStream(mCachedFile)
|
||||
) {
|
||||
if (in == null) throw new FileNotFoundException();
|
||||
byte buffer[] = new byte[1024];
|
||||
int length;
|
||||
while ((length = in.read(buffer)) > 0)
|
||||
outputStream.write(buffer, 0, length);
|
||||
} catch (FileNotFoundException e) {
|
||||
mList.add("! Invalid Uri");
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
mList.add("! Cannot copy to cache");
|
||||
throw e;
|
||||
}
|
||||
if (!unzipAndCheck()) return 0;
|
||||
mList.add(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
|
||||
getShell().su(mList,
|
||||
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile +
|
||||
" && echo 'Success!' || echo 'Failed!'"
|
||||
);
|
||||
if (TextUtils.equals(mList.get(mList.size() - 1), "Success!"))
|
||||
return 1;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return cleanup(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
progress.dismiss();
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return;
|
||||
getShell().su_raw(
|
||||
"rm -rf " + mCachedFile.getParent(),
|
||||
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
|
||||
);
|
||||
switch (result) {
|
||||
case -1:
|
||||
Toast.makeText(magiskManager, magiskManager.getString(R.string.install_error), Toast.LENGTH_LONG).show();
|
||||
Utils.showUriSnack(activity, mUri);
|
||||
mList.add(magiskManager.getString(R.string.install_error));
|
||||
Utils.showUriSnack(getActivity(), mUri);
|
||||
break;
|
||||
case 0:
|
||||
Toast.makeText(magiskManager, magiskManager.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show();
|
||||
mList.add(magiskManager.getString(R.string.invalid_zip));
|
||||
break;
|
||||
case 1:
|
||||
onSuccess();
|
||||
// Success
|
||||
new LoadModules(magiskManager).exec();
|
||||
break;
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
protected void onSuccess() {
|
||||
magiskManager.updateCheckDone.trigger();
|
||||
new LoadModules(activity).exec();
|
||||
|
||||
new AlertDialogBuilder(activity)
|
||||
.setTitle(R.string.reboot_title)
|
||||
.setMessage(R.string.reboot_msg)
|
||||
.setPositiveButton(R.string.reboot, (dialogInterface, i) -> Shell.su(true, "reboot"))
|
||||
.setNegativeButton(R.string.no_thanks, null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
@@ -1,30 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
public class GetBootBlocks extends RootTask<Void, Void, Void> {
|
||||
|
||||
public GetBootBlocks(Activity context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInRoot(Void... params) {
|
||||
magiskManager.blockList = Shell.su(
|
||||
"find /dev/block -type b -maxdepth 1 | grep -v -E \"loop|ram|dm-0\""
|
||||
);
|
||||
if (magiskManager.bootBlock == null) {
|
||||
magiskManager.bootBlock = Utils.detectBootImage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
magiskManager.blockDetectionDone.trigger();
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class LoadApps extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
public LoadApps(Activity context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
PackageManager pm = magiskManager.getPackageManager();
|
||||
List<ApplicationInfo> list = pm.getInstalledApplications(0);
|
||||
for (Iterator<ApplicationInfo> i = list.iterator(); i.hasNext(); ) {
|
||||
ApplicationInfo info = i.next();
|
||||
if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
Collections.sort(list, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
|
||||
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
|
||||
magiskManager.appList = Collections.unmodifiableList(list);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
new MagiskHide(activity).list();
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.module.BaseModule;
|
||||
@@ -9,23 +9,24 @@ import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ValueSortedMap;
|
||||
|
||||
public class LoadModules extends RootTask<Void, Void, Void> {
|
||||
public class LoadModules extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
public LoadModules(Activity context) {
|
||||
public LoadModules(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInRoot(Void... voids) {
|
||||
protected Void doInBackground(Void... voids) {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return null;
|
||||
Logger.dev("LoadModules: Loading modules");
|
||||
|
||||
magiskManager.moduleMap = new ValueSortedMap<>();
|
||||
|
||||
for (String path : Utils.getModList(MagiskManager.MAGISK_PATH)) {
|
||||
for (String path : Utils.getModList(getShell(), MagiskManager.MAGISK_PATH)) {
|
||||
Logger.dev("LoadModules: Adding modules from " + path);
|
||||
Module module;
|
||||
try {
|
||||
module = new Module(path);
|
||||
Module module = new Module(getShell(), path);
|
||||
magiskManager.moduleMap.put(module.getId(), module);
|
||||
} catch (BaseModule.CacheModException ignored) {}
|
||||
}
|
||||
@@ -36,7 +37,9 @@ public class LoadModules extends RootTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
magiskManager.moduleLoadDone.trigger();
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return;
|
||||
magiskManager.moduleLoadDone.publish();
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
}
|
||||
|
@@ -1,59 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MagiskHide extends RootTask<Object, Void, Void> {
|
||||
|
||||
private boolean isList = false;
|
||||
|
||||
public MagiskHide() {}
|
||||
|
||||
public MagiskHide(Activity context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInRoot(Object... params) {
|
||||
String command = (String) params[0];
|
||||
List<String> ret = Shell.su("magiskhide --" + command);
|
||||
if (isList) {
|
||||
magiskManager.magiskHideList = ret;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
if (isList) {
|
||||
magiskManager.magiskHideDone.trigger();
|
||||
}
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
|
||||
public void add(CharSequence packageName) {
|
||||
exec("add " + packageName);
|
||||
}
|
||||
|
||||
public void rm(CharSequence packageName) {
|
||||
exec("rm " + packageName);
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
exec("enable");
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
exec("disable");
|
||||
}
|
||||
|
||||
public void list() {
|
||||
isList = true;
|
||||
if (magiskManager == null) return;
|
||||
exec("ls");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.parser.Parser;
|
||||
import org.commonmark.renderer.html.HtmlRenderer;
|
||||
|
||||
public class MarkDownWindow extends ParallelTask<Void, Void, String> {
|
||||
|
||||
private String mTitle, mUrl;
|
||||
|
||||
public MarkDownWindow(Activity context, String title, String url) {
|
||||
super(context);
|
||||
mTitle = title;
|
||||
mUrl = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... voids) {
|
||||
String md = WebService.getString(mUrl);
|
||||
Parser parser = Parser.builder().build();
|
||||
HtmlRenderer renderer = HtmlRenderer.builder().build();
|
||||
Node doc = parser.parse(md);
|
||||
return renderer.render(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String html) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
||||
alert.setTitle(mTitle);
|
||||
|
||||
WebView wv = new WebView(getActivity());
|
||||
|
||||
html = String.format(
|
||||
"<link rel='stylesheet' type='text/css' href='file:///android_asset/%s.css'/> %s",
|
||||
getMagiskManager().isDarkTheme ? "dark" : "light", html);
|
||||
|
||||
wv.loadDataWithBaseURL("fake://", html, "text/html", "UTF-8", null);
|
||||
|
||||
alert.setView(wv);
|
||||
alert.setNegativeButton(R.string.close, (dialog, id) -> dialog.dismiss());
|
||||
alert.show();
|
||||
}
|
||||
}
|
@@ -1,23 +1,44 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
|
||||
|
||||
protected Activity activity;
|
||||
protected MagiskManager magiskManager;
|
||||
private WeakReference<Activity> weakActivity;
|
||||
private WeakReference<MagiskManager> weakMagiskManager;
|
||||
|
||||
private Runnable callback = null;
|
||||
|
||||
public ParallelTask() {}
|
||||
|
||||
public ParallelTask(Context context) {
|
||||
weakMagiskManager = new WeakReference<>(Utils.getMagiskManager(context));
|
||||
}
|
||||
|
||||
public ParallelTask(Activity context) {
|
||||
activity = context;
|
||||
magiskManager = Utils.getMagiskManager(context);
|
||||
this((Context) context);
|
||||
weakActivity = new WeakReference<>(context);
|
||||
}
|
||||
|
||||
protected Activity getActivity() {
|
||||
return weakActivity.get();
|
||||
}
|
||||
|
||||
protected MagiskManager getMagiskManager() {
|
||||
return weakMagiskManager.get();
|
||||
}
|
||||
|
||||
protected Shell getShell() {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
return magiskManager == null ? null : Shell.getShell(magiskManager);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@@ -1,58 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
public class ProcessMagiskZip extends ParallelTask<Void, Void, Boolean> {
|
||||
|
||||
private Uri mUri;
|
||||
private ProgressDialog progressDialog;
|
||||
private String mBoot;
|
||||
private boolean mEnc, mVerity;
|
||||
|
||||
public ProcessMagiskZip(Activity context, Uri uri, String boot, boolean enc, boolean verity) {
|
||||
super(context);
|
||||
mUri = uri;
|
||||
mBoot = boot;
|
||||
mEnc = enc;
|
||||
mVerity = verity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
progressDialog = ProgressDialog.show(activity,
|
||||
activity.getString(R.string.zip_process_title),
|
||||
activity.getString(R.string.zip_unzip_msg));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
if (Shell.rootAccess()) {
|
||||
synchronized (Shell.lock) {
|
||||
Shell.su("rm -f /dev/.magisk",
|
||||
(mBoot != null) ? "echo \"BOOTIMAGE=" + mBoot + "\" >> /dev/.magisk" : "",
|
||||
"echo \"KEEPFORCEENCRYPT=" + String.valueOf(mEnc) + "\" >> /dev/.magisk",
|
||||
"echo \"KEEPVERITY=" + String.valueOf(mVerity) + "\" >> /dev/.magisk"
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
progressDialog.dismiss();
|
||||
if (result) {
|
||||
new FlashZip(activity, mUri).exec();
|
||||
} else {
|
||||
Utils.showUriSnack(activity, mUri);
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
}
|
@@ -2,9 +2,11 @@ package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.FlashActivity;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
@@ -30,6 +32,8 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
progressDialog = ProgressDialog.show(activity,
|
||||
activity.getString(R.string.zip_process_title),
|
||||
activity.getString(R.string.zip_process_msg));
|
||||
@@ -37,12 +41,14 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) return null;
|
||||
try {
|
||||
|
||||
// Create temp file
|
||||
File temp1 = new File(magiskManager.getCacheDir(), "1.zip");
|
||||
File temp2 = new File(magiskManager.getCacheDir(), "2.zip");
|
||||
magiskManager.getCacheDir().mkdirs();
|
||||
File temp1 = new File(activity.getCacheDir(), "1.zip");
|
||||
File temp2 = new File(activity.getCacheDir(), "2.zip");
|
||||
activity.getCacheDir().mkdirs();
|
||||
temp1.createNewFile();
|
||||
temp2.createNewFile();
|
||||
|
||||
@@ -59,13 +65,14 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
||||
ZipUtils.signZip(activity, temp1, temp2, true);
|
||||
|
||||
// Write it back to the downloaded zip, temp2 -> Uri
|
||||
FileInputStream in = new FileInputStream(temp2);
|
||||
try (OutputStream target = activity.getContentResolver().openOutputStream(mUri)) {
|
||||
try (OutputStream out = activity.getContentResolver().openOutputStream(mUri);
|
||||
FileInputStream in = new FileInputStream(temp2)
|
||||
) {
|
||||
byte[] buffer = new byte[4096];
|
||||
int length;
|
||||
if (target == null) throw new FileNotFoundException();
|
||||
if (out == null) throw new FileNotFoundException();
|
||||
while ((length = in.read(buffer)) > 0)
|
||||
target.write(buffer, 0, length);
|
||||
out.write(buffer, 0, length);
|
||||
}
|
||||
|
||||
// Delete the temp file
|
||||
@@ -82,16 +89,17 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
progressDialog.dismiss();
|
||||
if (result) {
|
||||
if (Shell.rootAccess() && mInstall) {
|
||||
new FlashZip(activity, mUri).exec();
|
||||
activity.startActivity(new Intent(activity, FlashActivity.class).setData(mUri));
|
||||
} else {
|
||||
Utils.showUriSnack(activity, mUri);
|
||||
}
|
||||
|
||||
} else {
|
||||
Toast.makeText(activity, R.string.process_error, Toast.LENGTH_LONG).show();
|
||||
Utils.getMagiskManager(activity).toast(R.string.process_error, Toast.LENGTH_LONG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,33 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
|
||||
public abstract class RootTask <Params, Progress, Result> extends ParallelTask<Params, Progress, Result> {
|
||||
|
||||
public RootTask() {}
|
||||
|
||||
public RootTask(Activity context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@Override
|
||||
final protected Result doInBackground(Params... params) {
|
||||
synchronized (Shell.lock) {
|
||||
return doInRoot(params);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
abstract protected Result doInRoot(Params... params);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void exec(Params... params) {
|
||||
if (Shell.rootAccess()) {
|
||||
super.exec(params);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +1,14 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||
import com.topjohnwu.magisk.module.BaseModule;
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.ValueSortedMap;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
import org.json.JSONArray;
|
||||
@@ -24,7 +24,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class LoadRepos extends ParallelTask<Void, Void, Void> {
|
||||
public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
public static final String ETAG_KEY = "ETag";
|
||||
|
||||
@@ -37,15 +37,15 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
|
||||
private static final int LOAD_PREV = 2;
|
||||
|
||||
private List<String> etags;
|
||||
private ValueSortedMap<String, Repo> cached, fetched;
|
||||
private List<String> cached;
|
||||
private RepoDatabaseHelper repoDB;
|
||||
private SharedPreferences prefs;
|
||||
|
||||
public LoadRepos(Activity context) {
|
||||
public UpdateRepos(Context context) {
|
||||
super(context);
|
||||
prefs = magiskManager.prefs;
|
||||
prefs = getMagiskManager().prefs;
|
||||
repoDB = getMagiskManager().repoDB;
|
||||
String prefsPath = context.getApplicationInfo().dataDir + "/shared_prefs";
|
||||
repoDB = new RepoDatabaseHelper(magiskManager);
|
||||
// Legacy data cleanup
|
||||
File old = new File(prefsPath, "RepoMap.xml");
|
||||
if (old.exists() || !prefs.getString("repomap", "empty").equals("empty")) {
|
||||
@@ -54,7 +54,7 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
|
||||
repoDB.clearRepo();
|
||||
}
|
||||
etags = new ArrayList<>(
|
||||
Arrays.asList(magiskManager.prefs.getString(ETAG_KEY, "").split(",")));
|
||||
Arrays.asList(prefs.getString(ETAG_KEY, "").split(",")));
|
||||
}
|
||||
|
||||
private void loadJSON(String jsonString) throws Exception {
|
||||
@@ -67,25 +67,27 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
|
||||
String lastUpdate = jsonobject.getString("pushed_at");
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
Date updatedDate = format.parse(lastUpdate);
|
||||
Repo repo = cached.get(id);
|
||||
Repo repo = repoDB.getRepo(id);
|
||||
try {
|
||||
Boolean updated;
|
||||
if (repo == null) {
|
||||
Logger.dev("LoadRepos: Create new repo " + id);
|
||||
Logger.dev("UpdateRepos: Create new repo " + id);
|
||||
repo = new Repo(name, updatedDate);
|
||||
updated = true;
|
||||
} else {
|
||||
// Popout from cached
|
||||
cached.remove(id);
|
||||
repo.update(updatedDate);
|
||||
updated = repo.update(updatedDate);
|
||||
}
|
||||
if (repo.getId() != null) {
|
||||
fetched.put(id, repo);
|
||||
if (updated) {
|
||||
repoDB.addRepo(repo);
|
||||
}
|
||||
} catch (BaseModule.CacheModException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean loadPage(int page, String url, int mode) {
|
||||
Logger.dev("LoadRepos: Loading page: " + (page + 1));
|
||||
Logger.dev("UpdateRepos: Loading page: " + (page + 1));
|
||||
Map<String, String> header = new HashMap<>();
|
||||
if (mode == CHECK_ETAG && page < etags.size() && !TextUtils.isEmpty(etags.get(page))) {
|
||||
Logger.dev("ETAG: " + etags.get(page));
|
||||
@@ -94,13 +96,13 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
|
||||
if (url == null) {
|
||||
url = String.format(Locale.US, REPO_URL, page + 1);
|
||||
}
|
||||
String jsonString = WebService.request(url, WebService.GET, header, true);
|
||||
String jsonString = WebService.getString(url, header);
|
||||
if (TextUtils.isEmpty(jsonString)) {
|
||||
// At least check the pages we know
|
||||
return page + 1 < etags.size() && loadPage(page + 1, null, CHECK_ETAG);
|
||||
}
|
||||
|
||||
// The request succeed, parse the new stuffs
|
||||
// The getString succeed, parse the new stuffs
|
||||
try {
|
||||
loadJSON(jsonString);
|
||||
} catch (Exception e) {
|
||||
@@ -154,18 +156,18 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
Logger.dev("LoadRepos: Loading repos");
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return null;
|
||||
Logger.dev("UpdateRepos: Loading repos");
|
||||
|
||||
cached = repoDB.getRepoMap(false);
|
||||
fetched = new ValueSortedMap<>();
|
||||
cached = repoDB.getRepoIDList();
|
||||
|
||||
if (!loadPage(0, null, CHECK_ETAG)) {
|
||||
magiskManager.repoMap = repoDB.getRepoMap();
|
||||
Logger.dev("LoadRepos: No updates, use DB");
|
||||
Logger.dev("UpdateRepos: No updates, use DB");
|
||||
return null;
|
||||
}
|
||||
|
||||
repoDB.addRepoMap(fetched);
|
||||
// The leftover cached means they are removed from online repo
|
||||
repoDB.removeRepo(cached);
|
||||
|
||||
// Update ETag
|
||||
@@ -176,14 +178,15 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
|
||||
}
|
||||
prefs.edit().putString(ETAG_KEY, etagBuilder.toString()).apply();
|
||||
|
||||
magiskManager.repoMap = repoDB.getRepoMap();
|
||||
Logger.dev("LoadRepos: Done");
|
||||
Logger.dev("UpdateRepos: Done");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
magiskManager.repoLoadDone.trigger();
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return;
|
||||
magiskManager.repoLoadDone.publish();
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
}
|
@@ -1,13 +1,40 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
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 class Activity extends AppCompatActivity {
|
||||
|
||||
public Activity() {
|
||||
super();
|
||||
Configuration configuration = new Configuration();
|
||||
configuration.setLocale(MagiskManager.locale);
|
||||
applyOverrideConfiguration(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (this instanceof Topic.Subscriber) {
|
||||
((Topic.Subscriber) this).subscribeTopics();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (this instanceof Topic.Subscriber) {
|
||||
((Topic.Subscriber) this).unsubscribeTopics();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MagiskManager getApplicationContext() {
|
||||
return (MagiskManager) super.getApplicationContext();
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
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 {
|
||||
@@ -9,4 +10,19 @@ public class Fragment extends android.support.v4.app.Fragment {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@@ -1,31 +0,0 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import us.feras.mdv.MarkdownView;
|
||||
|
||||
public class MarkDownWindow {
|
||||
|
||||
public MarkDownWindow(String title, String url, Context context) {
|
||||
MagiskManager magiskManager = Utils.getMagiskManager(context);
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(context);
|
||||
alert.setTitle(title);
|
||||
|
||||
Logger.dev("WebView: URL = " + url);
|
||||
|
||||
MarkdownView md = new MarkdownView(context);
|
||||
md.loadMarkdownFile(url, "file:///android_asset/" +
|
||||
(magiskManager.isDarkTheme ? "dark" : "light") + ".css");
|
||||
|
||||
alert.setView(md);
|
||||
alert.setNegativeButton(R.string.close, (dialog, id) -> dialog.dismiss());
|
||||
alert.show();
|
||||
}
|
||||
|
||||
}
|
@@ -7,9 +7,9 @@ import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.ValueSortedMap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class RepoDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
@@ -17,8 +17,11 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
|
||||
private static final String TABLE_NAME = "repos";
|
||||
private static final int MIN_TEMPLATE_VER = 3;
|
||||
|
||||
private SQLiteDatabase mDb;
|
||||
|
||||
public RepoDatabaseHelper(Context context) {
|
||||
super(context, "repo.db", null, DATABASE_VER);
|
||||
mDb = getWritableDatabase();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,52 +45,41 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public void addRepoMap(ValueSortedMap<String, Repo> map) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
Collection<Repo> list = map.values();
|
||||
for (Repo repo : list) {
|
||||
Logger.dev("Add to DB: " + repo.getId());
|
||||
db.replace(TABLE_NAME, null, repo.getContentValues());
|
||||
}
|
||||
db.close();
|
||||
}
|
||||
|
||||
public void clearRepo() {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.delete(TABLE_NAME, null, null);
|
||||
db.close();
|
||||
mDb.delete(TABLE_NAME, null, null);
|
||||
}
|
||||
|
||||
public void removeRepo(ValueSortedMap<String, Repo> map) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
Collection<Repo> list = map.values();
|
||||
for (Repo repo : list) {
|
||||
Logger.dev("Remove from DB: " + repo.getId());
|
||||
db.delete(TABLE_NAME, "id=?", new String[] { repo.getId() });
|
||||
public void removeRepo(List<String> list) {
|
||||
for (String id : list) {
|
||||
Logger.dev("Remove from DB: " + id);
|
||||
mDb.delete(TABLE_NAME, "id=?", new String[] { id });
|
||||
}
|
||||
db.close();
|
||||
}
|
||||
|
||||
public ValueSortedMap<String, Repo> getRepoMap() {
|
||||
return getRepoMap(true);
|
||||
public void addRepo(Repo repo) {
|
||||
mDb.replace(TABLE_NAME, null, repo.getContentValues());
|
||||
}
|
||||
|
||||
public ValueSortedMap<String, Repo> getRepoMap(boolean filtered) {
|
||||
ValueSortedMap<String, Repo> ret = new ValueSortedMap<>();
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
Repo repo;
|
||||
try (Cursor c = db.query(TABLE_NAME, null, null, null, null, null, null)) {
|
||||
while (c.moveToNext()) {
|
||||
repo = new Repo(c);
|
||||
if (repo.getTemplateVersion() < MIN_TEMPLATE_VER && filtered) {
|
||||
Logger.dev("Outdated repo: " + repo.getId());
|
||||
} else {
|
||||
// Logger.dev("Load from DB: " + repo.getId());
|
||||
ret.put(repo.getId(), repo);
|
||||
}
|
||||
public Repo getRepo(String id) {
|
||||
try (Cursor c = mDb.query(TABLE_NAME, null, "id=?", new String[] { id }, null, null, null)) {
|
||||
if (c.moveToNext()) {
|
||||
return new Repo(c);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Cursor getRepoCursor() {
|
||||
return mDb.query(TABLE_NAME, null, "template>=?", new String[] { String.valueOf(MIN_TEMPLATE_VER) }, null, null, "name COLLATE NOCASE");
|
||||
}
|
||||
|
||||
public List<String> getRepoIDList() {
|
||||
LinkedList<String> ret = new LinkedList<>();
|
||||
try (Cursor c = mDb.query(TABLE_NAME, null, null, null, null, null, null)) {
|
||||
while (c.moveToNext()) {
|
||||
ret.add(c.getString(c.getColumnIndex("id")));
|
||||
}
|
||||
}
|
||||
db.close();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@@ -4,8 +4,10 @@ import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.superuser.Policy;
|
||||
@@ -13,8 +15,10 @@ import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
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 SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
@@ -23,18 +27,20 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
public static final String MULTIUSER_MODE = "multiuser_mode";
|
||||
public static final String MNT_NS = "mnt_ns";
|
||||
|
||||
private static final int DATABASE_VER = 2;
|
||||
private static final int DATABASE_VER = 3;
|
||||
private static final String POLICY_TABLE = "policies";
|
||||
private static final String LOG_TABLE = "logs";
|
||||
private static final String SETTINGS_TABLE = "settings";
|
||||
|
||||
private MagiskManager magiskManager;
|
||||
private PackageManager pm;
|
||||
private SQLiteDatabase mDb;
|
||||
|
||||
public SuDatabaseHelper(Context context) {
|
||||
super(context, "su.db", null, DATABASE_VER);
|
||||
magiskManager = Utils.getMagiskManager(context);
|
||||
pm = context.getPackageManager();
|
||||
mDb = getWritableDatabase();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@@ -70,6 +76,10 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
++oldVersion;
|
||||
}
|
||||
if (oldVersion == 2) {
|
||||
db.execSQL("UPDATE " + LOG_TABLE + " SET time=time*1000");
|
||||
++oldVersion;
|
||||
}
|
||||
}
|
||||
|
||||
private void createTables(SQLiteDatabase db) {
|
||||
@@ -93,13 +103,12 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
// Clear outdated policies
|
||||
db.delete(POLICY_TABLE, "until > 0 AND until < ?",
|
||||
mDb.delete(POLICY_TABLE, "until > 0 AND until < ?",
|
||||
new String[] { String.valueOf(System.currentTimeMillis() / 1000) });
|
||||
// Clear outdated logs
|
||||
db.delete(LOG_TABLE, "time < ?", new String[] { String.valueOf(
|
||||
System.currentTimeMillis() / 1000 - magiskManager.suLogTimeout * 86400) });
|
||||
mDb.delete(LOG_TABLE, "time < ?", new String[] { String.valueOf(
|
||||
System.currentTimeMillis() - magiskManager.suLogTimeout * 86400000) });
|
||||
}
|
||||
|
||||
public void deletePolicy(Policy policy) {
|
||||
@@ -107,25 +116,16 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
|
||||
public void deletePolicy(String pkg) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.delete(POLICY_TABLE, "package_name=?", new String[] { pkg });
|
||||
db.close();
|
||||
mDb.delete(POLICY_TABLE, "package_name=?", new String[] { pkg });
|
||||
}
|
||||
|
||||
public void deletePolicy(int uid) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
deletePolicy(db, uid);
|
||||
db.close();
|
||||
}
|
||||
|
||||
private void deletePolicy(SQLiteDatabase db, int uid) {
|
||||
db.delete(POLICY_TABLE, "uid=?", new String[]{String.valueOf(uid)});
|
||||
mDb.delete(POLICY_TABLE, "uid=?", new String[]{String.valueOf(uid)});
|
||||
}
|
||||
|
||||
public Policy getPolicy(int uid) {
|
||||
Policy policy = null;
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
try (Cursor c = db.query(POLICY_TABLE, null, "uid=?", new String[] { String.valueOf(uid) }, null, null, null)) {
|
||||
try (Cursor c = mDb.query(POLICY_TABLE, null, "uid=?", new String[] { String.valueOf(uid) }, null, null, null)) {
|
||||
if (c.moveToNext()) {
|
||||
policy = new Policy(c, pm);
|
||||
}
|
||||
@@ -133,14 +133,12 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
deletePolicy(uid);
|
||||
return null;
|
||||
}
|
||||
db.close();
|
||||
return policy;
|
||||
}
|
||||
|
||||
public Policy getPolicy(String pkg) {
|
||||
Policy policy = null;
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
try (Cursor c = db.query(POLICY_TABLE, null, "package_name=?", new String[] { pkg }, null, null, null)) {
|
||||
try (Cursor c = mDb.query(POLICY_TABLE, null, "package_name=?", new String[] { pkg }, null, null, null)) {
|
||||
if (c.moveToNext()) {
|
||||
policy = new Policy(c, pm);
|
||||
}
|
||||
@@ -148,116 +146,107 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
deletePolicy(pkg);
|
||||
return null;
|
||||
}
|
||||
db.close();
|
||||
return policy;
|
||||
}
|
||||
|
||||
public void addPolicy(Policy policy) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.replace(POLICY_TABLE, null, policy.getContentValues());
|
||||
db.close();
|
||||
mDb.replace(POLICY_TABLE, null, policy.getContentValues());
|
||||
}
|
||||
|
||||
public void updatePolicy(Policy policy) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
updatePolicy(db, policy);
|
||||
db.close();
|
||||
}
|
||||
|
||||
private void updatePolicy(SQLiteDatabase db, Policy policy) {
|
||||
db.update(POLICY_TABLE, policy.getContentValues(), "package_name=?",
|
||||
mDb.update(POLICY_TABLE, policy.getContentValues(), "package_name=?",
|
||||
new String[] { policy.packageName });
|
||||
}
|
||||
|
||||
public List<Policy> getPolicyList(PackageManager pm) {
|
||||
List<Policy> ret = new ArrayList<>();
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
Policy policy;
|
||||
try (Cursor c = db.query(POLICY_TABLE, null, null, null, null, null, null)) {
|
||||
try (Cursor c = mDb.query(POLICY_TABLE, null, null, null, null, null, null)) {
|
||||
List<Policy> ret = new ArrayList<>(c.getCount());
|
||||
while (c.moveToNext()) {
|
||||
try {
|
||||
policy = new Policy(c, pm);
|
||||
Policy policy = new Policy(c, pm);
|
||||
// The application changed UID for some reason, check user config
|
||||
if (policy.info.uid != policy.uid) {
|
||||
if (magiskManager.suReauth) {
|
||||
// Reauth required, remove from DB
|
||||
deletePolicy(db, policy.uid);
|
||||
deletePolicy(policy);
|
||||
continue;
|
||||
} else {
|
||||
// No reauth, update to use the new UID
|
||||
policy.uid = policy.info.uid;
|
||||
updatePolicy(db, policy);
|
||||
updatePolicy(policy);
|
||||
}
|
||||
}
|
||||
ret.add(policy);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// The app no longer exist, remove from DB
|
||||
deletePolicy(db, c.getInt(c.getColumnIndex("uid")));
|
||||
deletePolicy(c.getInt(c.getColumnIndex("uid")));
|
||||
}
|
||||
}
|
||||
Collections.sort(ret);
|
||||
return ret;
|
||||
}
|
||||
db.close();
|
||||
Collections.sort(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private List<SuLogEntry> getLogList(SQLiteDatabase db, String selection) {
|
||||
List<SuLogEntry> ret = new ArrayList<>();
|
||||
try (Cursor c = db.query(LOG_TABLE, null, selection, null, null, null, "time DESC")) {
|
||||
public List<List<Integer>> getLogStructure() {
|
||||
try (Cursor c = mDb.query(LOG_TABLE, new String[] { "time" }, null, null, null, null, "time DESC")) {
|
||||
List<List<Integer>> ret = new ArrayList<>();
|
||||
List<Integer> list = null;
|
||||
String dateString = null, newString;
|
||||
while (c.moveToNext()) {
|
||||
ret.add(new SuLogEntry(c));
|
||||
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;
|
||||
}
|
||||
db.close();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Cursor getLogCursor() {
|
||||
return getLogCursor(mDb);
|
||||
}
|
||||
|
||||
public Cursor getLogCursor(SQLiteDatabase db) {
|
||||
return db.query(LOG_TABLE, null, null, null, null, null, "time DESC");
|
||||
}
|
||||
|
||||
private void migrateLegacyLogList(File oldDB, SQLiteDatabase newDB) {
|
||||
SQLiteDatabase db = SQLiteDatabase.openDatabase(oldDB.getPath(), null, SQLiteDatabase.OPEN_READWRITE);
|
||||
List<SuLogEntry> logs = getLogList(db, null);
|
||||
for (SuLogEntry log : logs) {
|
||||
newDB.insert(LOG_TABLE, null, log.getContentValues());
|
||||
try (SQLiteDatabase oldDb = SQLiteDatabase.openDatabase(oldDB.getPath(), null, SQLiteDatabase.OPEN_READWRITE);
|
||||
Cursor c = getLogCursor(oldDb)) {
|
||||
while (c.moveToNext()) {
|
||||
ContentValues values = new ContentValues();
|
||||
DatabaseUtils.cursorRowToContentValues(c, values);
|
||||
newDB.insert(LOG_TABLE, null, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<SuLogEntry> getLogList() {
|
||||
return getLogList(null);
|
||||
}
|
||||
|
||||
public List<SuLogEntry> getLogList(String selection) {
|
||||
return getLogList(getReadableDatabase(), selection);
|
||||
}
|
||||
|
||||
public void addLog(SuLogEntry log) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.insert(LOG_TABLE, null, log.getContentValues());
|
||||
db.close();
|
||||
mDb.insert(LOG_TABLE, null, log.getContentValues());
|
||||
}
|
||||
|
||||
public void clearLogs() {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.delete(LOG_TABLE, null, null);
|
||||
db.close();
|
||||
mDb.delete(LOG_TABLE, null, null);
|
||||
}
|
||||
|
||||
public void setSettings(String key, int value) {
|
||||
ContentValues data = new ContentValues();
|
||||
data.put("key", key);
|
||||
data.put("value", value);
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.replace(SETTINGS_TABLE, null, data);
|
||||
db.close();
|
||||
mDb.replace(SETTINGS_TABLE, null, data);
|
||||
}
|
||||
|
||||
public int getSettings(String key, int defaultValue) {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
int value = defaultValue;
|
||||
try (Cursor c = db.query(SETTINGS_TABLE, null, "key=?", new String[] { key }, null, null, null)) {
|
||||
while (c.moveToNext()) {
|
||||
try (Cursor c = mDb.query(SETTINGS_TABLE, null, "key=?",new String[] { key }, null, null, null)) {
|
||||
if (c.moveToNext()) {
|
||||
value = c.getInt(c.getColumnIndex("value"));
|
||||
}
|
||||
}
|
||||
db.close();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package com.topjohnwu.magisk.module;
|
||||
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
public class Module extends BaseModule {
|
||||
@@ -8,9 +9,9 @@ public class Module extends BaseModule {
|
||||
private String mRemoveFile, mDisableFile, mUpdateFile;
|
||||
private boolean mEnable, mRemove, mUpdated;
|
||||
|
||||
public Module(String path) throws CacheModException {
|
||||
public Module(Shell shell, String path) throws CacheModException {
|
||||
|
||||
parseProps(Utils.readFile(path + "/module.prop"));
|
||||
parseProps(Utils.readFile(shell, path + "/module.prop"));
|
||||
|
||||
mRemoveFile = path + "/remove";
|
||||
mDisableFile = path + "/disable";
|
||||
@@ -27,33 +28,33 @@ public class Module extends BaseModule {
|
||||
|
||||
Logger.dev("Creating Module, id: " + getId());
|
||||
|
||||
mEnable = !Utils.itemExist(mDisableFile);
|
||||
mRemove = Utils.itemExist(mRemoveFile);
|
||||
mUpdated = Utils.itemExist(mUpdateFile);
|
||||
mEnable = !Utils.itemExist(shell, mDisableFile);
|
||||
mRemove = Utils.itemExist(shell, mRemoveFile);
|
||||
mUpdated = Utils.itemExist(shell, mUpdateFile);
|
||||
}
|
||||
|
||||
public void createDisableFile() {
|
||||
public void createDisableFile(Shell shell) {
|
||||
mEnable = false;
|
||||
Utils.createFile(mDisableFile);
|
||||
Utils.createFile(shell, mDisableFile);
|
||||
}
|
||||
|
||||
public void removeDisableFile() {
|
||||
public void removeDisableFile(Shell shell) {
|
||||
mEnable = true;
|
||||
Utils.removeItem(mDisableFile);
|
||||
Utils.removeItem(shell, mDisableFile);
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return mEnable;
|
||||
}
|
||||
|
||||
public void createRemoveFile() {
|
||||
public void createRemoveFile(Shell shell) {
|
||||
mRemove = true;
|
||||
Utils.createFile(mRemoveFile);
|
||||
Utils.createFile(shell, mRemoveFile);
|
||||
}
|
||||
|
||||
public void deleteRemoveFile() {
|
||||
public void deleteRemoveFile(Shell shell) {
|
||||
mRemove = false;
|
||||
Utils.removeItem(mRemoveFile);
|
||||
Utils.removeItem(shell, mRemoveFile);
|
||||
}
|
||||
|
||||
public boolean willBeRemoved() {
|
||||
|
@@ -29,17 +29,19 @@ public class Repo extends BaseModule {
|
||||
}
|
||||
|
||||
public void update() throws CacheModException {
|
||||
String props = WebService.request(getManifestUrl(), WebService.GET);
|
||||
String props = WebService.getString(getManifestUrl());
|
||||
String lines[] = props.split("\\n");
|
||||
parseProps(lines);
|
||||
Logger.dev("Repo: Fetching prop: " + getId());
|
||||
}
|
||||
|
||||
public void update(Date lastUpdate) throws CacheModException {
|
||||
public boolean update(Date lastUpdate) throws CacheModException {
|
||||
if (lastUpdate.after(mLastUpdate)) {
|
||||
mLastUpdate = lastUpdate;
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public ContentValues getContentValues() {
|
||||
|
@@ -6,7 +6,6 @@ import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import com.topjohnwu.magisk.services.OnBootIntentService;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
|
||||
@@ -21,7 +20,6 @@ public class BootReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
|
||||
Utils.getMagiskManager(context).initSU();
|
||||
// There is currently no need to start an IntentService onBoot
|
||||
// startIntentService(context);
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
public abstract class DownloadReceiver extends BroadcastReceiver {
|
||||
public Context mContext;
|
||||
public String mFilename;
|
||||
long downloadID;
|
||||
|
||||
@@ -20,7 +19,6 @@ public abstract class DownloadReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mContext = context;
|
||||
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
String action = intent.getAction();
|
||||
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
|
||||
|
@@ -7,6 +7,7 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.support.v4.content.FileProvider;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.io.File;
|
||||
@@ -22,20 +23,20 @@ public class ManagerUpdate extends BroadcastReceiver {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE);
|
||||
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
Uri content = FileProvider.getUriForFile(mContext,
|
||||
Uri content = FileProvider.getUriForFile(context,
|
||||
"com.topjohnwu.magisk.provider", new File(uri.getPath()));
|
||||
install.setData(content);
|
||||
mContext.startActivity(install);
|
||||
context.startActivity(install);
|
||||
} else {
|
||||
Intent install = new Intent(Intent.ACTION_VIEW);
|
||||
install.setDataAndType(uri, "application/vnd.android.package-archive");
|
||||
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(install);
|
||||
context.startActivity(install);
|
||||
}
|
||||
}
|
||||
},
|
||||
intent.getStringExtra("link"),
|
||||
intent.getStringExtra(MagiskManager.INTENT_LINK),
|
||||
Utils.getLegalFilename("MagiskManager-v" +
|
||||
intent.getStringExtra("version") + ".apk"));
|
||||
intent.getStringExtra(MagiskManager.INTENT_VERSION) + ".apk"));
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ public class PackageReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
MagiskManager magiskManager = Utils.getMagiskManager(context);
|
||||
magiskManager.initSUConfig();
|
||||
|
||||
String pkg = intent.getData().getEncodedSchemeSpecificPart();
|
||||
Policy policy = magiskManager.suDB.getPolicy(pkg);
|
||||
|
@@ -4,24 +4,15 @@ 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) {
|
||||
new CheckUpdates(this, true){
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
magiskManager.updateMagiskInfo();
|
||||
magiskManager.updateNotification = magiskManager.prefs.getBoolean("notification", true);
|
||||
return super.doInBackground(voids);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
jobFinished(params, false);
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
}.exec();
|
||||
Utils.getMagiskManager(this).getMagiskInfo();
|
||||
new CheckUpdates(this, true)
|
||||
.setCallBack(() -> jobFinished(params, false)).exec();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -17,7 +17,6 @@ public class RequestActivity extends Activity {
|
||||
return;
|
||||
}
|
||||
|
||||
getApplicationContext().initSUConfig();
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setClass(this, SuRequestActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
|
@@ -2,15 +2,14 @@ package com.topjohnwu.magisk.superuser;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class SuLogEntry implements Parcelable {
|
||||
public class SuLogEntry {
|
||||
|
||||
public int fromUid, toUid, fromPid;
|
||||
public String packageName, appName, command;
|
||||
@@ -31,7 +30,7 @@ public class SuLogEntry implements Parcelable {
|
||||
appName = c.getString(c.getColumnIndex("app_name"));
|
||||
command = c.getString(c.getColumnIndex("command"));
|
||||
action = c.getInt(c.getColumnIndex("action")) != 0;
|
||||
date = new Date(c.getLong(c.getColumnIndex("time")) * 1000);
|
||||
date = new Date(c.getLong(c.getColumnIndex("time")));
|
||||
}
|
||||
|
||||
public ContentValues getContentValues() {
|
||||
@@ -43,56 +42,15 @@ public class SuLogEntry implements Parcelable {
|
||||
values.put("command", command);
|
||||
values.put("to_uid", toUid);
|
||||
values.put("action", action ? 1 : 0);
|
||||
values.put("time", date.getTime() / 1000);
|
||||
values.put("time", date.getTime());
|
||||
return values;
|
||||
}
|
||||
|
||||
public String getDateString() {
|
||||
return DateFormat.getDateInstance(DateFormat.MEDIUM).format(date);
|
||||
return DateFormat.getDateInstance(DateFormat.MEDIUM, MagiskManager.locale).format(date);
|
||||
}
|
||||
|
||||
public String getTimeString() {
|
||||
return new SimpleDateFormat("h:mm a", Locale.US).format(date);
|
||||
}
|
||||
|
||||
|
||||
public static final Creator<SuLogEntry> CREATOR = new Creator<SuLogEntry>() {
|
||||
@Override
|
||||
public SuLogEntry createFromParcel(Parcel in) {
|
||||
return new SuLogEntry(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuLogEntry[] newArray(int size) {
|
||||
return new SuLogEntry[size];
|
||||
}
|
||||
};
|
||||
|
||||
protected SuLogEntry(Parcel in) {
|
||||
fromUid = in.readInt();
|
||||
toUid = in.readInt();
|
||||
fromPid = in.readInt();
|
||||
packageName = in.readString();
|
||||
appName = in.readString();
|
||||
command = in.readString();
|
||||
action = in.readByte() != 0;
|
||||
date = new Date(in.readLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(fromUid);
|
||||
dest.writeInt(toUid);
|
||||
dest.writeInt(fromPid);
|
||||
dest.writeString(packageName);
|
||||
dest.writeString(appName);
|
||||
dest.writeString(command);
|
||||
dest.writeByte((byte) (action ? 1 : 0));
|
||||
dest.writeLong(date.getTime());
|
||||
return new SimpleDateFormat("h:mm a", MagiskManager.locale).format(date);
|
||||
}
|
||||
}
|
||||
|
@@ -27,7 +27,6 @@ public class SuReceiver extends BroadcastReceiver {
|
||||
Policy policy;
|
||||
|
||||
MagiskManager magiskManager = (MagiskManager) context.getApplicationContext();
|
||||
magiskManager.initSUConfig();
|
||||
|
||||
if (intent == null) return;
|
||||
|
||||
|
@@ -0,0 +1,36 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class AdaptiveList<E> extends ArrayList<E> {
|
||||
|
||||
private Runnable callback;
|
||||
private RecyclerView mView;
|
||||
|
||||
public AdaptiveList(RecyclerView v) {
|
||||
mView = v;
|
||||
}
|
||||
|
||||
public void updateView() {
|
||||
mView.getAdapter().notifyDataSetChanged();
|
||||
mView.scrollToPosition(mView.getAdapter().getItemCount() - 1);
|
||||
}
|
||||
|
||||
public void setCallback(Runnable cb) {
|
||||
callback = cb;
|
||||
}
|
||||
|
||||
public boolean add(E e) {
|
||||
boolean ret = super.add(e);
|
||||
if (ret) {
|
||||
if (callback == null) {
|
||||
updateView();
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class CallbackEvent<Result> {
|
||||
|
||||
public boolean isTriggered = false;
|
||||
private Result result;
|
||||
private Set<Listener<Result>> listeners;
|
||||
|
||||
public void register(Listener<Result> l) {
|
||||
if (listeners == null) {
|
||||
listeners = new HashSet<>();
|
||||
}
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
public void unRegister() {
|
||||
listeners = null;
|
||||
}
|
||||
|
||||
public void unRegister(Listener<Result> l) {
|
||||
if (listeners != null) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
}
|
||||
|
||||
public void trigger() {
|
||||
trigger(null);
|
||||
}
|
||||
|
||||
public void trigger(Result r) {
|
||||
result = r;
|
||||
isTriggered = true;
|
||||
if (listeners != null) {
|
||||
for (Listener<Result> listener : listeners) {
|
||||
listener.onTrigger(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Result getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public interface Listener<R> {
|
||||
void onTrigger(CallbackEvent<R> event);
|
||||
}
|
||||
}
|
@@ -11,23 +11,39 @@ public class Logger {
|
||||
public static final String MAIN_TAG = "Magisk";
|
||||
public static final String DEBUG_TAG = "MagiskManager";
|
||||
|
||||
public static void debug(String line) {
|
||||
Log.d(DEBUG_TAG, "DEBUG: " + line);
|
||||
}
|
||||
|
||||
public static void debug(String fmt, Object... args) {
|
||||
Log.d(DEBUG_TAG, "DEBUG: " + String.format(Locale.US, fmt, args));
|
||||
debug(String.format(Locale.US, fmt, args));
|
||||
}
|
||||
|
||||
public static void error(String line) {
|
||||
Log.e(MAIN_TAG, "MANAGERERROR: " + line);
|
||||
}
|
||||
|
||||
public static void error(String fmt, Object... args) {
|
||||
Log.e(MAIN_TAG, "MANAGERERROR: " + String.format(Locale.US, fmt, args));
|
||||
error(String.format(Locale.US, fmt, args));
|
||||
}
|
||||
|
||||
public static void dev(String line) {
|
||||
if (MagiskManager.devLogging) {
|
||||
Log.d(DEBUG_TAG, line);
|
||||
}
|
||||
}
|
||||
|
||||
public static void dev(String fmt, Object... args) {
|
||||
if (MagiskManager.devLogging) {
|
||||
Log.d(DEBUG_TAG, String.format(Locale.US, fmt, args));
|
||||
dev(String.format(Locale.US, fmt, args));
|
||||
}
|
||||
|
||||
public static void shell(String line) {
|
||||
if (MagiskManager.shellLogging) {
|
||||
Log.d(DEBUG_TAG, "SHELL: " + line);
|
||||
}
|
||||
}
|
||||
|
||||
public static void shell(boolean root, String fmt, Object... args) {
|
||||
if (MagiskManager.shellLogging) {
|
||||
Log.d(DEBUG_TAG, (root ? "MANAGERSU: " : "MANAGERSH: ") + String.format(Locale.US, fmt, args));
|
||||
}
|
||||
public static void shell(String fmt, Object... args) {
|
||||
shell(String.format(Locale.US, fmt, args));
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,8 @@ import java.security.SecureRandom;
|
||||
public abstract class SafetyNetHelper
|
||||
implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
|
||||
|
||||
private static boolean isRunning = false;
|
||||
|
||||
private GoogleApiClient mGoogleApiClient;
|
||||
private Result ret;
|
||||
protected FragmentActivity mActivity;
|
||||
@@ -27,17 +29,20 @@ public abstract class SafetyNetHelper
|
||||
public SafetyNetHelper(FragmentActivity activity) {
|
||||
ret = new Result();
|
||||
mActivity = activity;
|
||||
mGoogleApiClient = new GoogleApiClient.Builder(activity)
|
||||
.enableAutoManage(activity, this)
|
||||
.addApi(SafetyNet.API)
|
||||
.addConnectionCallbacks(this)
|
||||
.build();
|
||||
}
|
||||
|
||||
// Entry point to start test
|
||||
public void requestTest() {
|
||||
if (isRunning)
|
||||
return;
|
||||
// Connect Google Service
|
||||
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
|
||||
.enableAutoManage(mActivity, this)
|
||||
.addApi(SafetyNet.API)
|
||||
.addConnectionCallbacks(this)
|
||||
.build();
|
||||
mGoogleApiClient.connect();
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,6 +97,7 @@ public abstract class SafetyNetHelper
|
||||
// Disconnect
|
||||
mGoogleApiClient.stopAutoManage(mActivity);
|
||||
mGoogleApiClient.disconnect();
|
||||
isRunning = false;
|
||||
handleResults(ret);
|
||||
});
|
||||
}
|
||||
|
@@ -1,11 +1,17 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.RootTask;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -16,214 +22,162 @@ public class Shell {
|
||||
|
||||
// -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted
|
||||
public static int rootStatus;
|
||||
public static final Object lock = new Object();
|
||||
|
||||
private static boolean isInit = false;
|
||||
private static Process rootShell;
|
||||
private static DataOutputStream rootSTDIN;
|
||||
private static StreamGobbler rootSTDOUT;
|
||||
private static List<String> rootOutList = Collections.synchronizedList(new ArrayList<String>());
|
||||
private final Process shellProcess;
|
||||
private final DataOutputStream STDIN;
|
||||
private final DataInputStream STDOUT;
|
||||
|
||||
public static void init() {
|
||||
private boolean isValid;
|
||||
|
||||
isInit = true;
|
||||
private void testRootShell(DataOutputStream in, DataInputStream out) throws IOException {
|
||||
in.write(("id\n").getBytes("UTF-8"));
|
||||
in.flush();
|
||||
String s = new BufferedReader(new InputStreamReader(out)).readLine();
|
||||
if (TextUtils.isEmpty(s) || !s.contains("uid=0")) {
|
||||
in.close();
|
||||
out.close();
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
private Shell() {
|
||||
rootStatus = 1;
|
||||
Process process = null;
|
||||
DataOutputStream in = null;
|
||||
DataInputStream out = null;
|
||||
|
||||
try {
|
||||
rootShell = Runtime.getRuntime().exec("su");
|
||||
rootStatus = 1;
|
||||
} catch (IOException err) {
|
||||
// No root
|
||||
rootStatus = 0;
|
||||
return;
|
||||
// Try getting global namespace
|
||||
process = Runtime.getRuntime().exec("su --mount-master");
|
||||
in = new DataOutputStream(process.getOutputStream());
|
||||
out = new DataInputStream(process.getInputStream());
|
||||
testRootShell(in, out);
|
||||
} catch (IOException e) {
|
||||
// Feature not implemented, normal root shell
|
||||
try {
|
||||
process = Runtime.getRuntime().exec("su");
|
||||
in = new DataOutputStream(process.getOutputStream());
|
||||
out = new DataInputStream(process.getInputStream());
|
||||
testRootShell(in, out);
|
||||
} catch (IOException e1) {
|
||||
rootStatus = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rootSTDIN = new DataOutputStream(rootShell.getOutputStream());
|
||||
rootSTDOUT = new StreamGobbler(rootShell.getInputStream(), rootOutList, true);
|
||||
rootSTDOUT.start();
|
||||
|
||||
// Setup umask and PATH
|
||||
su("umask 022");
|
||||
|
||||
List<String> ret = su("echo -BOC-", "id");
|
||||
|
||||
if (ret == null) {
|
||||
// Something wrong with root, not allowed?
|
||||
rootStatus = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
for (String line : ret) {
|
||||
if (line.contains("uid=")) {
|
||||
// id command is working, let's see if we are actually root
|
||||
rootStatus = line.contains("uid=0") ? rootStatus : -1;
|
||||
return;
|
||||
} else if (!line.contains("-BOC-")) {
|
||||
rootStatus = -1;
|
||||
if (!rootAccess()) {
|
||||
// Try to gain non-root sh
|
||||
try {
|
||||
process = Runtime.getRuntime().exec("sh");
|
||||
in = new DataOutputStream(process.getOutputStream());
|
||||
out = new DataInputStream(process.getInputStream());
|
||||
} catch (IOException e) {
|
||||
// Nothing works....
|
||||
shellProcess = null;
|
||||
STDIN = null;
|
||||
STDOUT = null;
|
||||
isValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
isValid = true;
|
||||
shellProcess = process;
|
||||
STDIN = in;
|
||||
STDOUT = out;
|
||||
sh_raw("umask 022");
|
||||
}
|
||||
|
||||
public static Shell getShell() {
|
||||
return new Shell();
|
||||
}
|
||||
|
||||
public static Shell getShell(Context context) {
|
||||
MagiskManager magiskManager = Utils.getMagiskManager(context);
|
||||
if (magiskManager.shell == null || !magiskManager.shell.isValid) {
|
||||
// Get new shell if needed
|
||||
magiskManager.shell = getShell();
|
||||
}
|
||||
return magiskManager.shell;
|
||||
}
|
||||
|
||||
public static boolean rootAccess() {
|
||||
return isInit && rootStatus > 0;
|
||||
return rootStatus > 0;
|
||||
}
|
||||
|
||||
public static List<String> sh(String... commands) {
|
||||
List<String> res = Collections.synchronizedList(new ArrayList<String>());
|
||||
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec("sh");
|
||||
DataOutputStream STDIN = new DataOutputStream(process.getOutputStream());
|
||||
StreamGobbler STDOUT = new StreamGobbler(process.getInputStream(), res);
|
||||
|
||||
STDOUT.start();
|
||||
|
||||
try {
|
||||
for (String write : commands) {
|
||||
STDIN.write((write + "\n").getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
Logger.shell(false, write);
|
||||
}
|
||||
STDIN.write("exit\n".getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
} catch (IOException e) {
|
||||
if (!e.getMessage().contains("EPIPE")) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
process.waitFor();
|
||||
|
||||
try {
|
||||
STDIN.close();
|
||||
} catch (IOException e) {
|
||||
// might be closed already
|
||||
}
|
||||
STDOUT.join();
|
||||
process.destroy();
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
// shell probably not found
|
||||
res = null;
|
||||
}
|
||||
|
||||
public List<String> sh(String... commands) {
|
||||
List<String> res = new ArrayList<>();
|
||||
if (!isValid) return res;
|
||||
sh(res, commands);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Run with the same shell by default
|
||||
public static List<String> su(String... commands) {
|
||||
return su(false, commands);
|
||||
public void sh_raw(String... commands) {
|
||||
sh_raw(false, commands);
|
||||
}
|
||||
|
||||
public static List<String> su(boolean newShell, String... commands) {
|
||||
List<String> res;
|
||||
Process process;
|
||||
DataOutputStream STDIN;
|
||||
StreamGobbler STDOUT;
|
||||
|
||||
// Create the default shell if not init
|
||||
if (!newShell && !isInit) {
|
||||
init();
|
||||
}
|
||||
|
||||
if (!newShell && !rootAccess()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (newShell) {
|
||||
res = Collections.synchronizedList(new ArrayList<String>());
|
||||
public void sh_raw(boolean stdout, String... commands) {
|
||||
if (!isValid) return;
|
||||
synchronized (shellProcess) {
|
||||
try {
|
||||
process = Runtime.getRuntime().exec("su");
|
||||
STDIN = new DataOutputStream(process.getOutputStream());
|
||||
STDOUT = new StreamGobbler(process.getInputStream(), res);
|
||||
|
||||
// Run the new shell with busybox and proper umask
|
||||
STDIN.write(("umask 022\n").getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
} catch (IOException err) {
|
||||
return null;
|
||||
for (String command : commands) {
|
||||
Logger.shell(command);
|
||||
STDIN.write((command + (stdout ? "\n" : " >/dev/null\n")).getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
shellProcess.destroy();
|
||||
isValid = false;
|
||||
}
|
||||
STDOUT.start();
|
||||
} else {
|
||||
process = rootShell;
|
||||
STDIN = rootSTDIN;
|
||||
STDOUT = rootSTDOUT;
|
||||
res = rootOutList;
|
||||
res.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void sh(Collection<String> output, String... commands) {
|
||||
if (!isValid) return;
|
||||
try {
|
||||
for (String write : commands) {
|
||||
STDIN.write((write + "\n").getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
Logger.shell(true, write);
|
||||
}
|
||||
if (newShell) {
|
||||
STDIN.write("exit\n".getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
process.waitFor();
|
||||
shellProcess.exitValue();
|
||||
isValid = false;
|
||||
return; // The process is dead, return
|
||||
} catch (IllegalThreadStateException ignored) {
|
||||
// This should be the expected result
|
||||
}
|
||||
synchronized (shellProcess) {
|
||||
StreamGobbler out = new StreamGobbler(STDOUT, output);
|
||||
out.start();
|
||||
sh_raw(true, commands);
|
||||
sh_raw(true, "echo \'-shell-done-\'");
|
||||
try { out.join(); } catch (InterruptedException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
STDIN.close();
|
||||
} catch (IOException ignore) {
|
||||
// might be closed already
|
||||
}
|
||||
public List<String> su(String... commands) {
|
||||
if (!rootAccess()) return sh();
|
||||
return sh(commands);
|
||||
}
|
||||
|
||||
STDOUT.join();
|
||||
process.destroy();
|
||||
} else {
|
||||
STDIN.write(("echo\n").getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
STDIN.write(("echo \'-root-done-\'\n").getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
while (true) {
|
||||
try {
|
||||
// Process terminated, it means the interactive shell has some issues
|
||||
process.exitValue();
|
||||
rootStatus = -1;
|
||||
return null;
|
||||
} catch (IllegalThreadStateException e) {
|
||||
// Process still running, gobble output until done
|
||||
int end = res.size() - 1;
|
||||
if (end > 0) {
|
||||
if (res.get(end).equals("-root-done-")) {
|
||||
res.remove(end);
|
||||
if (res.get(end -1).isEmpty()) {
|
||||
res.remove(end -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
try { STDOUT.join(100); } catch (InterruptedException err) {
|
||||
rootStatus = -1;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (!e.getMessage().contains("EPIPE")) {
|
||||
Logger.dev("Shell: Root shell error...");
|
||||
rootStatus = -1;
|
||||
return null;
|
||||
}
|
||||
} catch(InterruptedException e) {
|
||||
Logger.dev("Shell: Root shell error...");
|
||||
rootStatus = -1;
|
||||
public void su_raw(String... commands) {
|
||||
if (!rootAccess()) return;
|
||||
sh_raw(commands);
|
||||
}
|
||||
|
||||
public void su(Collection<String> output, String... commands) {
|
||||
if (!rootAccess()) return;
|
||||
sh(output, commands);
|
||||
}
|
||||
|
||||
public static abstract class AbstractList<E> extends java.util.AbstractList<E> {
|
||||
|
||||
@Override
|
||||
public abstract boolean add(E e);
|
||||
|
||||
@Override
|
||||
public E get(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ArrayList<>(res);
|
||||
}
|
||||
|
||||
public static void su_async(List<String> result, String... commands) {
|
||||
new RootTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInRoot(Void... params) {
|
||||
List<String> ret = Shell.su(commands);
|
||||
if (result != null) result.addAll(ret);
|
||||
return null;
|
||||
}
|
||||
}.exec();
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,12 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Modified by topjohnwu, based on Chainfire's libsuperuser
|
||||
@@ -13,40 +15,38 @@ import java.util.List;
|
||||
public class StreamGobbler extends Thread {
|
||||
|
||||
private BufferedReader reader = null;
|
||||
private List<String> writer = null;
|
||||
private boolean isRoot = false;
|
||||
private Collection<String> writer = null;
|
||||
|
||||
/**
|
||||
* <p>StreamGobbler constructor</p>
|
||||
*
|
||||
* <p>We use this class because shell STDOUT and STDERR should be read as quickly as
|
||||
* <p>We use this class because sh STDOUT and STDERR should be read as quickly as
|
||||
* possible to prevent a deadlock from occurring, or Process.waitFor() never
|
||||
* returning (as the buffer is full, pausing the native process)</p>
|
||||
*
|
||||
* @param inputStream InputStream to read from
|
||||
* @param outputList {@literal List<String>} to write to, or null
|
||||
*/
|
||||
public StreamGobbler(InputStream inputStream, List<String> outputList) {
|
||||
public StreamGobbler(InputStream inputStream, Collection<String> outputList) {
|
||||
try {
|
||||
while (inputStream.available() != 0) {
|
||||
inputStream.skip(inputStream.available());
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
writer = outputList;
|
||||
}
|
||||
|
||||
public StreamGobbler(InputStream inputStream, List<String> outputList, boolean root) {
|
||||
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
writer = outputList;
|
||||
isRoot = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// keep reading the InputStream until it ends (or an error occurs)
|
||||
try {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (TextUtils.equals(line, "-shell-done-"))
|
||||
return;
|
||||
writer.add(line);
|
||||
if (!line.equals("-root-done-") && !line.isEmpty()) {
|
||||
Logger.shell(isRoot, "OUT: " + line);
|
||||
}
|
||||
Logger.shell(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// reader probably closed, expected exit condition
|
||||
|
68
app/src/main/java/com/topjohnwu/magisk/utils/Topic.java
Normal file
68
app/src/main/java/com/topjohnwu/magisk/utils/Topic.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class Topic {
|
||||
|
||||
public boolean hasPublished = false;
|
||||
private List<WeakReference<Subscriber>> subscribers;
|
||||
|
||||
public void subscribe(Subscriber sub) {
|
||||
if (subscribers == null) {
|
||||
subscribers = new LinkedList<>();
|
||||
}
|
||||
subscribers.add(new WeakReference<>(sub));
|
||||
}
|
||||
|
||||
public void unsubscribe() {
|
||||
subscribers = null;
|
||||
}
|
||||
|
||||
public void unsubscribe(Subscriber sub) {
|
||||
for (Iterator<WeakReference<Subscriber>> i = subscribers.iterator(); i.hasNext();) {
|
||||
WeakReference<Subscriber> subscriber = i.next();
|
||||
if (subscriber.get() == null || subscriber.get() == sub) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void publish() {
|
||||
publish(true);
|
||||
}
|
||||
|
||||
public void publish(boolean b) {
|
||||
hasPublished = b;
|
||||
if (subscribers != null) {
|
||||
for (WeakReference<Subscriber> subscriber : subscribers) {
|
||||
if (subscriber.get() != null)
|
||||
subscriber.get().onTopicPublished(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface Subscriber {
|
||||
default void subscribeTopics() {
|
||||
for (Topic topic : getSubscription()) {
|
||||
if (topic.hasPublished) {
|
||||
onTopicPublished(topic);
|
||||
}
|
||||
topic.subscribe(this);
|
||||
}
|
||||
}
|
||||
default void unsubscribeTopics() {
|
||||
for (Topic event : getSubscription()) {
|
||||
event.unsubscribe(this);
|
||||
}
|
||||
}
|
||||
default void onTopicPublished() {
|
||||
onTopicPublished(null);
|
||||
}
|
||||
void onTopicPublished(Topic topic);
|
||||
Topic[] getSubscription();
|
||||
}
|
||||
}
|
@@ -10,12 +10,14 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
@@ -27,14 +29,17 @@ import android.widget.Toast;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.SplashActivity;
|
||||
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||
import com.topjohnwu.magisk.receivers.ManagerUpdate;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Utils {
|
||||
|
||||
@@ -43,37 +48,31 @@ public class Utils {
|
||||
private static final int MAGISK_UPDATE_NOTIFICATION_ID = 1;
|
||||
private static final int APK_UPDATE_NOTIFICATION_ID = 2;
|
||||
|
||||
public static boolean itemExist(String path) {
|
||||
String command = "if [ -e " + path + " ]; then echo true; else echo false; fi";
|
||||
List<String> ret = Shell.su(command);
|
||||
public static boolean itemExist(Shell shell, String path) {
|
||||
String command = "[ -e " + path + " ] && echo true || echo false";
|
||||
List<String> ret = shell.su(command);
|
||||
return isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(0));
|
||||
}
|
||||
|
||||
public static void createFile(String path) {
|
||||
public static void createFile(Shell shell, String path) {
|
||||
String folder = path.substring(0, path.lastIndexOf('/'));
|
||||
String command = "mkdir -p " + folder + " 2>/dev/null; touch " + path + " 2>/dev/null; if [ -f \"" + path + "\" ]; then echo true; else echo false; fi";
|
||||
Shell.su_async(null, command);
|
||||
String command = "mkdir -p " + folder + " 2>/dev/null; touch " + path + " 2>/dev/null;";
|
||||
shell.su_raw(command);
|
||||
}
|
||||
|
||||
public static void removeItem(String path) {
|
||||
String command = "rm -rf " + path + " 2>/dev/null; if [ -e " + path + " ]; then echo false; else echo true; fi";
|
||||
Shell.su_async(null, command);
|
||||
public static void removeItem(Shell shell, String path) {
|
||||
String command = "rm -rf " + path + " 2>/dev/null";
|
||||
shell.su_raw(command);
|
||||
}
|
||||
|
||||
public static List<String> getModList(String path) {
|
||||
String command = "find " + path + " -type d -maxdepth 1 ! -name \"*.core\" ! -name \"*lost+found\" ! -name \"*magisk\"";
|
||||
return Shell.su(command);
|
||||
public static List<String> getModList(Shell shell, String path) {
|
||||
String command = "ls -d " + path + "/* | grep -v lost+found";
|
||||
return shell.su(command);
|
||||
}
|
||||
|
||||
public static List<String> readFile(String path) {
|
||||
List<String> ret;
|
||||
String command = "cat " + path;
|
||||
if (Shell.rootAccess()) {
|
||||
ret = Shell.su(command);
|
||||
} else {
|
||||
ret = Shell.sh(command);
|
||||
}
|
||||
return ret;
|
||||
public static List<String> readFile(Shell shell, String path) {
|
||||
String command = "cat " + path + " | sed '$a\\ ' | sed '$d'";
|
||||
return shell.su(command);
|
||||
}
|
||||
|
||||
public static void dlAndReceive(Context context, DownloadReceiver receiver, String link, String filename) {
|
||||
@@ -105,7 +104,7 @@ public class Utils {
|
||||
receiver.setDownloadID(downloadManager.enqueue(request));
|
||||
}
|
||||
receiver.setFilename(filename);
|
||||
context.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||
context.getApplicationContext().registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||
}
|
||||
|
||||
public static String getLegalFilename(CharSequence filename) {
|
||||
@@ -114,23 +113,6 @@ public class Utils {
|
||||
.replace("#", "").replace("@", "").replace("*", "");
|
||||
}
|
||||
|
||||
public static String detectBootImage() {
|
||||
String[] commands = {
|
||||
"for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do",
|
||||
"BOOTIMAGE=`readlink /dev/block/by-name/$PARTITION || " +
|
||||
"readlink /dev/block/platform/*/by-name/$PARTITION || " +
|
||||
"readlink /dev/block/platform/*/*/by-name/$PARTITION`",
|
||||
"if [ ! -z \"$BOOTIMAGE\" ]; then break; fi",
|
||||
"done",
|
||||
"echo \"$BOOTIMAGE\""
|
||||
};
|
||||
List<String> ret = Shell.su(commands);
|
||||
if (isValidShellResponse(ret)) {
|
||||
return ret.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean lowercaseContains(CharSequence string, CharSequence nonNullLowercaseSearch) {
|
||||
return !TextUtils.isEmpty(string) && string.toString().toLowerCase().contains(nonNullLowercaseSearch);
|
||||
}
|
||||
@@ -158,16 +140,16 @@ public class Utils {
|
||||
@Override
|
||||
public void handleResults(Result result) {
|
||||
getMagiskManager(mActivity).SNCheckResult = result;
|
||||
getMagiskManager(mActivity).safetyNetDone.trigger();
|
||||
getMagiskManager(mActivity).safetyNetDone.publish();
|
||||
}
|
||||
}.requestTest();
|
||||
}
|
||||
|
||||
public static void clearRepoCache(Activity activity) {
|
||||
MagiskManager magiskManager = getMagiskManager(activity);
|
||||
magiskManager.prefs.edit().remove(LoadRepos.ETAG_KEY).apply();
|
||||
new RepoDatabaseHelper(activity).clearRepo();
|
||||
Toast.makeText(activity, R.string.repo_cache_cleared, Toast.LENGTH_SHORT).show();
|
||||
public static void clearRepoCache(Context context) {
|
||||
MagiskManager magiskManager = getMagiskManager(context);
|
||||
magiskManager.prefs.edit().remove(UpdateRepos.ETAG_KEY).apply();
|
||||
magiskManager.repoDB.clearRepo();
|
||||
magiskManager.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT);
|
||||
}
|
||||
|
||||
public static String getNameFromUri(Context context, Uri uri) {
|
||||
@@ -214,10 +196,13 @@ public class Utils {
|
||||
builder.setSmallIcon(R.drawable.ic_magisk)
|
||||
.setContentTitle(magiskManager.getString(R.string.magisk_update_title))
|
||||
.setContentText(magiskManager.getString(R.string.magisk_update_available, magiskManager.remoteMagiskVersionString))
|
||||
.setChannelId(MagiskManager.NOTIFICATION_CHANNEL)
|
||||
.setVibrate(new long[]{0, 100, 100, 100})
|
||||
.setAutoCancel(true);
|
||||
Intent intent = new Intent(magiskManager, SplashActivity.class);
|
||||
intent.putExtra(MagiskManager.INTENT_SECTION, "install");
|
||||
intent.putExtra(MagiskManager.INTENT_VERSION, magiskManager.remoteMagiskVersionString);
|
||||
intent.putExtra(MagiskManager.INTENT_LINK, magiskManager.magiskLink);
|
||||
TaskStackBuilder stackBuilder = TaskStackBuilder.create(magiskManager);
|
||||
stackBuilder.addParentStack(SplashActivity.class);
|
||||
stackBuilder.addNextIntent(intent);
|
||||
@@ -234,11 +219,12 @@ public class Utils {
|
||||
builder.setSmallIcon(R.drawable.ic_magisk)
|
||||
.setContentTitle(magiskManager.getString(R.string.manager_update_title))
|
||||
.setContentText(magiskManager.getString(R.string.manager_download_install))
|
||||
.setChannelId(MagiskManager.NOTIFICATION_CHANNEL)
|
||||
.setVibrate(new long[]{0, 100, 100, 100})
|
||||
.setAutoCancel(true);
|
||||
Intent intent = new Intent(magiskManager, ManagerUpdate.class);
|
||||
intent.putExtra("link", magiskManager.managerLink);
|
||||
intent.putExtra("version", magiskManager.remoteManagerVersionString);
|
||||
intent.putExtra(MagiskManager.INTENT_LINK, magiskManager.managerLink);
|
||||
intent.putExtra(MagiskManager.INTENT_VERSION, magiskManager.remoteManagerVersionString);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(magiskManager,
|
||||
APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
@@ -246,4 +232,60 @@ public class Utils {
|
||||
(NotificationManager) magiskManager.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(APK_UPDATE_NOTIFICATION_ID, builder.build());
|
||||
}
|
||||
|
||||
public static void enableMagiskHide(Shell shell) {
|
||||
shell.su_raw("magiskhide --enable");
|
||||
}
|
||||
|
||||
public static void disableMagiskHide(Shell shell) {
|
||||
shell.su_raw("magiskhide --disable");
|
||||
}
|
||||
|
||||
public static List<String> listMagiskHide(Shell shell) {
|
||||
return shell.su("magiskhide --ls");
|
||||
}
|
||||
|
||||
public static void addMagiskHide(Shell shell, String pkg) {
|
||||
shell.su_raw("magiskhide --add " + pkg);
|
||||
}
|
||||
|
||||
public static void rmMagiskHide(Shell shell, String pkg) {
|
||||
shell.su_raw("magiskhide --rm " + pkg);
|
||||
}
|
||||
|
||||
public static String getLocaleString(Context context, Locale locale, @StringRes int id) {
|
||||
Configuration config = context.getResources().getConfiguration();
|
||||
config.setLocale(locale);
|
||||
Context localizedContext = context.createConfigurationContext(config);
|
||||
return localizedContext.getString(id);
|
||||
}
|
||||
|
||||
public static List<Locale> getAvailableLocale(Context context) {
|
||||
List<Locale> locales = new ArrayList<>();
|
||||
HashSet<String> set = new HashSet<>();
|
||||
Locale locale;
|
||||
|
||||
// Add default locale
|
||||
locales.add(Locale.ENGLISH);
|
||||
set.add(getLocaleString(context, Locale.ENGLISH, R.string.download));
|
||||
|
||||
// Add some special locales
|
||||
locales.add(Locale.TAIWAN);
|
||||
set.add(getLocaleString(context, Locale.TAIWAN, R.string.download));
|
||||
locale = new Locale("pt", "BR");
|
||||
locales.add(locale);
|
||||
set.add(getLocaleString(context, locale, R.string.download));
|
||||
|
||||
// Other locales
|
||||
for (String s : context.getAssets().getLocales()) {
|
||||
locale = Locale.forLanguageTag(s);
|
||||
if (set.add(getLocaleString(context, locale, R.string.download))) {
|
||||
locales.add(locale);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(locales, (l1, l2) -> l1.getDisplayName(l1).compareTo(l2.getDisplayName(l2)));
|
||||
|
||||
return locales;
|
||||
}
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
@@ -14,36 +16,31 @@ public class WebService {
|
||||
public final static int GET = 1;
|
||||
public final static int POST = 2;
|
||||
|
||||
/**
|
||||
* Making web service call
|
||||
*
|
||||
* @url - url to make request
|
||||
* @requestmethod - http request method
|
||||
*/
|
||||
public static String request(String url, int method) {
|
||||
return request(url, method, null, true);
|
||||
public static String getString(String url) {
|
||||
return getString(url, null);
|
||||
}
|
||||
|
||||
public static String request(String url, int method, boolean newline) {
|
||||
return request(url, method, null, newline);
|
||||
}
|
||||
|
||||
/**
|
||||
* Making service call
|
||||
*
|
||||
* @url - url to make request
|
||||
* @requestmethod - http request method
|
||||
* @params - http request params
|
||||
* @header - http request header
|
||||
* @newline - true to append a newline each line
|
||||
*/
|
||||
public static String request(String urlAddress, int method,
|
||||
Map<String, String> header, boolean newline) {
|
||||
Logger.dev("WebService: Service call " + urlAddress);
|
||||
URL url;
|
||||
StringBuilder response = new StringBuilder();
|
||||
public static String getString(String url, Map<String, String> header) {
|
||||
InputStream in = request(GET, url, header);
|
||||
if (in == null) return "";
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
||||
String line;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try {
|
||||
url = new URL(urlAddress);
|
||||
while ((line = br.readLine()) != null) {
|
||||
builder.append(line).append("\n");
|
||||
}
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static InputStream request(int method, String address, Map<String, String> header) {
|
||||
Logger.dev("WebService: Service call " + address);
|
||||
try {
|
||||
URL url = new URL(address);
|
||||
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setReadTimeout(15000);
|
||||
@@ -62,18 +59,7 @@ public class WebService {
|
||||
}
|
||||
}
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
|
||||
if (responseCode == HttpsURLConnection.HTTP_OK) {
|
||||
String line;
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (newline) {
|
||||
response.append(line).append("\n");
|
||||
} else {
|
||||
response.append(line);
|
||||
}
|
||||
}
|
||||
if (conn.getResponseCode() == HttpsURLConnection.HTTP_OK) {
|
||||
if (header != null) {
|
||||
header.clear();
|
||||
for (Map.Entry<String, List<String>> entry : conn.getHeaderFields().entrySet()) {
|
||||
@@ -81,12 +67,12 @@ public class WebService {
|
||||
header.put(entry.getKey(), l.get(l.size() - 1));
|
||||
}
|
||||
}
|
||||
return conn.getInputStream();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return response.toString();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -2,24 +2,24 @@ package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.spongycastle.asn1.ASN1InputStream;
|
||||
import org.spongycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.spongycastle.asn1.DEROutputStream;
|
||||
import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
|
||||
import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
|
||||
import org.spongycastle.cert.jcajce.JcaCertStore;
|
||||
import org.spongycastle.cms.CMSException;
|
||||
import org.spongycastle.cms.CMSProcessableByteArray;
|
||||
import org.spongycastle.cms.CMSSignedData;
|
||||
import org.spongycastle.cms.CMSSignedDataGenerator;
|
||||
import org.spongycastle.cms.CMSTypedData;
|
||||
import org.spongycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
|
||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.spongycastle.operator.ContentSigner;
|
||||
import org.spongycastle.operator.OperatorCreationException;
|
||||
import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
||||
import org.spongycastle.util.encoders.Base64;
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.DEROutputStream;
|
||||
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
||||
import org.bouncycastle.cms.CMSException;
|
||||
import org.bouncycastle.cms.CMSProcessableByteArray;
|
||||
import org.bouncycastle.cms.CMSSignedData;
|
||||
import org.bouncycastle.cms.CMSSignedDataGenerator;
|
||||
import org.bouncycastle.cms.CMSTypedData;
|
||||
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
Binary file not shown.
Binary file not shown.
56
app/src/main/res/layout/activity_flash.xml
Normal file
56
app/src/main/res/layout/activity_flash.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<?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"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:background="@android:color/black"
|
||||
tools:context="com.topjohnwu.magisk.FlashActivity">
|
||||
|
||||
<include layout="@layout/toolbar"/>
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_weight="1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/flash_logs"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
app:layoutManager="android.support.v7.widget.LinearLayoutManager">
|
||||
|
||||
</android.support.v7.widget.RecyclerView>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_panel"
|
||||
style="?android:buttonStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
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/reboot"
|
||||
style="?android:borderlessButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/reboot" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
9
app/src/main/res/layout/list_item_flashlog.xml
Normal file
9
app/src/main/res/layout/list_item_flashlog.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="10sp" />
|
@@ -1,23 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
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:src="@drawable/ic_arrow"
|
||||
android:id="@+id/arrow"
|
||||
android:layout_marginEnd="10dp" />
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@drawable/ic_arrow" />
|
||||
|
||||
<TextView
|
||||
android:text="2017/1/1"
|
||||
android:id="@+id/date"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/date"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:gravity="center_vertical"
|
||||
android:text="2017/1/1"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:gravity="center_vertical" />
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
</LinearLayout>
|
@@ -138,7 +138,7 @@
|
||||
<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، و busybox لا يزال ممكنا</string>
|
||||
<string name="settings_core_only_summary">تمكين الميزات الأساسية فقط، لن يتم تحميل جميع الإضافات. MagiskSU، MagiskHide، systemless hosts، و لا يزال ممكنا</string>
|
||||
<string name="settings_magiskhide_summary">إخفاء Magisk من مختلف الاكتشافات</string>
|
||||
<string name="settings_busybox_title">تفعيل BusyBox</string>
|
||||
<string name="settings_busybox_summary">ربط تحميل Magisk\'s المدمج في busybox إلى xbin</string>
|
||||
|
@@ -143,7 +143,7 @@
|
||||
<string name="settings_clear_cache_summary">Löscht die zwischengespeicherten Informationen der Online-Repos. Erzwingt eine Aktualisierung</string>
|
||||
|
||||
<string name="settings_core_only_title">Nur Kernfunktionen</string>
|
||||
<string name="settings_core_only_summary">Aktiviert lediglich die Kernfunktionen, Module werden nicht geladen. MagiskSU, Magisk Hide, Systemless hosts und Busybox bleiben weiterhin aktiv</string>
|
||||
<string name="settings_core_only_summary">Aktiviert lediglich die Kernfunktionen, Module werden nicht geladen. MagiskSU, Magisk Hide und Systemless hosts bleiben weiterhin aktiv</string>
|
||||
<string name="settings_magiskhide_summary">Versteckt Magisk vor diversen Entdeckungsmethoden</string>
|
||||
<string name="settings_busybox_title">BusyBox aktivieren</string>
|
||||
<string name="settings_busybox_summary">Magisk\'s integriertes BusyBox nach xbin mounten</string>
|
||||
|
226
app/src/main/res/values-el/strings.xml
Normal file
226
app/src/main/res/values-el/strings.xml
Normal file
@@ -0,0 +1,226 @@
|
||||
<resources>
|
||||
<!--Welcome Activity-->
|
||||
<string name="navigation_drawer_open">Άνοιγμα συρταριού πλοήγησης</string>
|
||||
<string name="navigation_drawer_close">Κλείσιμο συρταριού πλοήγησης</string>
|
||||
<string name="modules">Ενότητες</string>
|
||||
<string name="downloads">Λήψεις</string>
|
||||
<string name="superuser">Υπερχρήστης</string>
|
||||
<string name="log">Aρχείο Kαταγραφής</string>
|
||||
<string name="settings">Ρυθμίσεις</string>
|
||||
<string name="status">Κατάσταση</string>
|
||||
<string name="install">Εγκατάσταση</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version">Εγκατεστημένο Magisk v%1$s</string>
|
||||
<string name="magisk_version_core_only">Εγκατεστημένο Magisk v%1$s (Λειτουργία Πυρήνα Μόνο)</string>
|
||||
<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="cannot_check_updates">Αδυναμία ελέγχου για ενημερώσεις, δεν έχει Internet;</string>
|
||||
<string name="up_to_date">Τελευταία έκδοση του %1$s εγκατεστημένη</string>
|
||||
<string name="root_error">Υπάρχει root αλλά όχι άδεια για root, δεν επιτρέπεται;</string>
|
||||
<string name="not_rooted">Δεν υπάρχει root</string>
|
||||
<string name="proper_root">Rooted κανονικά</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_connection_failed">Αδυναμία σύνδεσης στο Google API</string>
|
||||
<string name="safetyNet_connection_suspended">Η σύνδεση στο Google API διακόπηκε</string>
|
||||
<string name="safetyNet_no_response">Αδυναμία ελέγχου SafetyNet, δεν έχει Internet;</string>
|
||||
<string name="safetyNet_fail">Αποτυχία SafetyNet: CTS profile mismatch</string>
|
||||
<string name="safetyNet_pass">Το SafetyNet Πέρασε</string>
|
||||
<string name="safetyNet_network_loss">Χάθηκε η σύνδεση στο δίκτυο</string>
|
||||
<string name="safetyNet_service_disconnected">Η υπηρεσία τερματίστηκε</string>
|
||||
<string name="safetyNet_res_invalid">Η απόκριση είναι άκυρη</string>
|
||||
<string name="root_info_warning">Η λειτουργία είναι πολύ περιορισμένη</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="auto_detect">(Αυτόματα) %1$s</string>
|
||||
<string name="cannot_auto_detect">(Αδυναμία αυτόματης εύρεσης)</string>
|
||||
<string name="boot_image_title">Τοποθεσία Εικόνας Boot</string>
|
||||
<string name="detect_button">Εύρεση</string>
|
||||
<string name="advanced_settings_title">Προηγμένες ρυθμίσεις</string>
|
||||
<string name="keep_force_encryption">Διατήρηση επιβεβλημένης κρυπτογράφησης</string>
|
||||
<string name="keep_dm_verity">Διατήρηση 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="reboot_countdown">Επανεκκίνηση σε %1$d</string>
|
||||
<string name="uninstall_magisk_title">Απεγκατάσταση Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Αυτό θα αφαιρέσει όλες τις ενότητες, το MagiskSU και πιθανόν να κρυπτογραφήσει τα δεδομένα σας αν δεν είναι κρυπτογραφυμένα\nΕίστε σίγουρος/η ότι θέλετε να συνεχίσετε;</string>
|
||||
<string name="version_none">(Καμία)</string>
|
||||
<string name="reinstall">Επανεγκατάσταση</string>
|
||||
<string name="update">Ενημέρωση</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>
|
||||
<string name="fab_flash_zip">Flash Zip Ενότητας</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Διαθέσιμη Ενημέρωση</string>
|
||||
<string name="installed">Εγκαταστάθηκε</string>
|
||||
<string name="not_installed">Μη εγκατεστημένη</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveToSd">Αποθήκευση σε SD</string>
|
||||
<string name="menuReload">Επαναφόρτωση</string>
|
||||
<string name="menuClearLog">Εκκαθάριση αρχείου καταγραφής τώρα</string>
|
||||
<string name="logs_cleared">Το αρχείο καταγραφής εκκαθαρίστηκε επιτυχώς</string>
|
||||
<string name="log_is_empty">Το αρχείο καταγραφής είναι κενό</string>
|
||||
<string name="logs_save_failed">Αποτυχία αποθήκευσης αρχείου καταγραφής στην κάρτα SD:</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">Περί</string>
|
||||
<string name="app_developers">Κύριοι προγραμματιστές</string>
|
||||
<string name="app_developers_"><![CDATA[Η εφαρμογή δημιουργήθηκε από τον <a href="https://github.com/topjohnwu">topjohnwu</a> σε συνεργασία με <a href="https://github.com/d8ahazard">Digitalhigh</a> και <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
|
||||
<string name="app_changelog">Καταγραφή αλλαγών εφαρμογής</string>
|
||||
<string name="translators">JpegXguy</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="permissionNotGranted">Η λειτουργία αυτή δεν θα δουλέψει χωρίς την άδεια εγγραφής στον εξωτερικό χώρο αποθηκεύσης.</string>
|
||||
<string name="no_thanks">Όχι ευχαριστώ</string>
|
||||
<string name="yes">Ναι</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="close">Κλείσιμο</string>
|
||||
<string name="repo_install_title">Εγκατάσταση %1$s</string>
|
||||
<string name="repo_install_msg">Θέλετε να εγκαταστήσετε το %1$s τώρα;</string>
|
||||
<string name="download_install">Λήψη & Εγκατάσταση</string>
|
||||
<string name="download">Λήψη</string>
|
||||
<string name="goto_install">Μεταφορά στο τμήμα \"Εγκατάσταση\"</string>
|
||||
<string name="download_file_error">Σφάλμα στη λήψη του αρχείου</string>
|
||||
<string name="install_error">Σφάλμα εγκατάστασης!</string>
|
||||
<string name="invalid_zip">Αυτό το zip δεν είναι Ενότητα Magisk!!</string>
|
||||
<string name="reboot_title">Η εγκατάσταση πέτυχε!</string>
|
||||
<string name="reboot_msg">Θέλετε να κάνετε επανεκκίνηση τώρα;</string>
|
||||
<string name="reboot">Επανεκκίνηση</string>
|
||||
<string name="copying_msg">Αντιγραφή zip στον προσωρινό κατάλογο</string>
|
||||
<string name="zip_install_progress_title">Εγκατάσταση</string>
|
||||
<string name="zip_unzip_msg">Αποσυμπίεση αρχείου zip …</string>
|
||||
<string name="zip_process_msg">Επεξεργασία αρχείου zip …</string>
|
||||
<string name="zip_install_progress_msg">Εγκατάσταση %1$s …</string>
|
||||
<string name="no_magisk_title">Το Magisk δεν είναι εγκατεστημένο!</string>
|
||||
<string name="no_magisk_msg">Θέλετε να κατεβάσετε και να εγκαταστήσετε το Magisk;</string>
|
||||
<string name="downloading_toast">Κατέβασμα %1$s</string>
|
||||
<string name="magisk_update_title">Νέα Ενημέρωση Magisk Διαθέσιμη!</string>
|
||||
<string name="settings_reboot_toast">Επανεκκίνηση για εφαρμογή ρυθμίσεων</string>
|
||||
<string name="release_notes">Σημειώσεις έκδοσης</string>
|
||||
<string name="repo_cache_cleared">Η Repo cache καθαρίστηκε</string>
|
||||
<string name="safetyNet_hide_notice">Αυτή η εφαρμογή χρησιμοποιεί SafetyNet\nΉδη διαχειρίζεται από το MagiskHide από προεπιλογή</string>
|
||||
<string name="start_magiskhide">Εκκίνηση MagiskHide …</string>
|
||||
<string name="no_magisksu_title">Δεν χρησιμοποιείται το MagiskSU!</string>
|
||||
<string name="no_magisksu_msg">Δεν είστε rooted με το MagiskSU, η χρήση του MagiskHide μόνο μπορεί να μην είναι αρκετή!\nΔεν υποτηρίζεται επισήμως, και θα χρειαζόσασταν πρόσθετα εργαλεία (π.χ. suhide) για να περάσετε το Safety Net.</string>
|
||||
<string name="understand">Καταλαβαίνω</string>
|
||||
<string name="process_error">Σφάλμα διαδικασίας</string>
|
||||
<string name="internal_storage">Το zip είναι αποθηκευμένο σε:\n[Εσωτερική μνήμη]%1$s</string>
|
||||
<string name="zip_process_title">Επεξεργασία</string>
|
||||
<string name="manual_boot_image">Παρακαλώ επιλέξτε χειροκίνητα μια εικόνα boot!</string>
|
||||
<string name="manager_update_title">Νέα Ενημέρωση Magisk Manager Διαθέσιμη!</string>
|
||||
<string name="manager_download_install">Πιέστε για λήψη και εγκατάσταση</string>
|
||||
<string name="magisk_updates">Ενημερώσεις Magisk</string>
|
||||
<string name="flashing">Γίνεται Flash</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_notification_title">Ειδοποίηση Ενημέρωσης</string>
|
||||
<string name="settings_notification_summary">Εμφάνιση ειδοποιήσεων ενημέρωσης όταν είναι διαθέσιμη νέα έκδοση</string>
|
||||
<string name="settings_clear_cache_title">Εκκαθάριση προσωρινής μνήμης αποθετηρίων</string>
|
||||
<string name="settings_clear_cache_summary">Καθαρίζει τις κρυφές πληροφορίες για απευθείας συνδεδεμένα αποθετήρια, αναγκάζει την εφαρμογή να κάνει ανανέωση σε απευθείας σύνδεση</string>
|
||||
<string name="language">Γλώσσα</string>
|
||||
<string name="system_default">(Προεπιλογή Συστήματος)</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_busybox_title">Ενεργοποίηση BusyBox</string>
|
||||
<string name="settings_busybox_summary">Υποχρεωτική προσάρτηση του ενσωματωμένου busybox του Magisk στο xbin</string>
|
||||
<string name="settings_hosts_title">Systemless hosts</string>
|
||||
<string name="settings_hosts_summary">Υποστήριξη Systemless hosts για εφαρμογές Adblock</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">Πρόσβαση Υπερχρήστη</string>
|
||||
<string name="auto_response">Αυτόματη Απόκριση</string>
|
||||
<string name="request_timeout">Χρονικό όριο Αιτήματος</string>
|
||||
<string name="superuser_notification">Ειδοποίηση Υπερχρήστη</string>
|
||||
<string name="request_timeout_summary">%1$s δευτερόλεπτα</string>
|
||||
<string name="settings_su_reauth_title">Επαναπιστοποίηση μετά από αναβάθμιση</string>
|
||||
<string name="settings_su_reauth_summary">Επαναπιστοποίηση αδειών υπερχρήστη μετά την αναβάθμιση μίας εφαρμογής</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">Μόνο ο ιδιοκτήτης έχει πρόσβαση root</string>
|
||||
<string name="owner_manage_summary">Μόνο ο ιδιοκτήτης μπορεί να διαχειριστεί την πρόσβαση root και να δεχτεί προτροπές αίτημάτων</string>
|
||||
<string name="user_indepenent_summary">Κάθε χρήστης έχει τους δικούς του ξεχωριστούς κανόνες root</string>
|
||||
<string name="multiuser_hint_owner_request">Ένα αίτημα έχει σταλεί στον ιδιοκτήτη της συσκευής. Παρακαλώ αλλάξτε σε ιδιοκτήτη και δώστε την άδεια</string>
|
||||
|
||||
<string name="mount_namespace_mode">Λειτουργία προσάρτησης χώρου ονομάτων</string>
|
||||
<string name="settings_ns_global">Καθολικός Χώρος Ονομάτων</string>
|
||||
<string name="settings_ns_requester">Κληρονόμησε Χώρο Ονομάτων</string>
|
||||
<string name="settings_ns_isolate">Απομονωμένος Χώρος Ονομάτων</string>
|
||||
<string name="global_summary">Όλες οι συνεδρίες root χρησιμοποιούν τον καθολικό χώρο oνομάτων προσάρτησης</string>
|
||||
<string name="requester_summary">Οι συνεδρίες root θα κληρονομούν το χώρο ονομάτων του αιτούντα τους</string>
|
||||
<string name="isolate_summary">Κάθε συνεδρία root θα έχει το δικό της απομονωμένο χώρο ονομάτων</string>
|
||||
|
||||
<string name="settings_development_category">Ανάπτυξη Εφαρμογής</string>
|
||||
<string name="settings_developer_logging_title">Ενεργοποίηση προηγμένης καταγραφής ελέγχου σφαλμάτων</string>
|
||||
<string name="settings_developer_logging_summary">Επιλέξτε αυτό για να ενεργοποιήσετε τη verbose καταγραφή</string>
|
||||
<string name="settings_shell_logging_title">Ενεργοποίηση καταγραφής ελέγχου σφαλμάτων εντολών κελύφους</string>
|
||||
<string name="settings_shell_logging_summary">Επιλέξτε αυτό για να ενεργοποιήσετε την καταγραφή όλων των εντολών κελύφους και την έξοδο τους</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Αίτημα υπερχρήστη</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</string>
|
||||
<string name="su_deny_toast">Δεν παραχορούνται δικαιώματα υπερχρήστη στο %1$s</string>
|
||||
<string name="no_apps_found">Δεν βρέθηκαν εφαρμογές</string>
|
||||
<string name="su_snack_grant">Παραχορούνται δικαιώματα υπερχρήστη στο %1$s</string>
|
||||
<string name="su_snack_deny">Δεν παραχορούνται δικαιώματα υπερχρήστη στο %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">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>
|
@@ -14,6 +14,7 @@
|
||||
|
||||
<!--Magisk Fragment-->
|
||||
<string name="magisk_version">Instalado Magisk v%1$s</string>
|
||||
<string name="magisk_version_core_only">Instalado Magisk v%1$s (Core Only Mode)</string>
|
||||
<string name="magisk_version_error">Magisk no está instalado</string>
|
||||
|
||||
<string name="checking_for_updates">Comprobando actualizaciones…</string>
|
||||
@@ -30,10 +31,14 @@
|
||||
<string name="safetyNet_no_response">No puede comprobar SafetyNet, ¿No tiene internet?</string>
|
||||
<string name="safetyNet_fail">SafetyNet: Error, no coincide el perfil CTS</string>
|
||||
<string name="safetyNet_pass">SafetyNet: Correcto</string>
|
||||
<string name="safetyNet_network_loss">Conexión de red perdida</string>
|
||||
<string name="safetyNet_service_disconnected">Se ha detenido el servicio</string>
|
||||
<string name="safetyNet_res_invalid">La respuesta no es válida</string>
|
||||
<string name="root_info_warning">Funcionalidad enormemente limitada</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="auto_detect">(Auto) %1$s</string>
|
||||
<string name="cannot_auto_detect">(No se puede detectar automáticamente)</string>
|
||||
<string name="boot_image_title">Ubicación de la imagen boot</string>
|
||||
<string name="detect_button">Detectar</string>
|
||||
<string name="advanced_settings_title">Ajustes avanzados</string>
|
||||
@@ -43,7 +48,12 @@
|
||||
<string name="install_magisk_title">Última versión de Magisk: %1$s</string>
|
||||
<string name="uninstall">Desinstalar</string>
|
||||
<string name="reboot_countdown">Reiniciando en %1$d</string>
|
||||
|
||||
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Esto eliminará todos los módulos, MagiskSU, y potencialmente puede cifrar sus datos si no está encriptada\nEstas seguro de continuar?</string>
|
||||
<string name="version_none">(Ninguno)</string>
|
||||
<string name="reinstall">Re-Instalar</string>
|
||||
<string name="update">Actualización</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(No hay información)</string>
|
||||
<string name="no_modules_found">No se han encontrado módulos</string>
|
||||
@@ -73,7 +83,7 @@
|
||||
<string name="app_developers">Desarroladores principales</string>
|
||||
<string name="app_developers_"><![CDATA[Aplicación creada por <a href="https://github.com/topjohnwu">topjohnwu</a> en colaboración con <a href="https://github.com/d8ahazard">Digitalhigh</a> y <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
|
||||
<string name="app_changelog">Registro de cambios de la aplicación</string>
|
||||
<string name="translators">Gawenda, netizen, Deiki, Nosi></string>
|
||||
<string name="translators">Gawenda, netizen, Deiki, Nosi>, dark-basic</string>
|
||||
<string name="app_version">Versión de la aplicación</string>
|
||||
<string name="app_source_code">Código fuente</string>
|
||||
<string name="donation">Donar</string>
|
||||
@@ -87,7 +97,7 @@
|
||||
<string name="ok">Aceptar</string>
|
||||
<string name="close">Cerrar</string>
|
||||
<string name="repo_install_title">Instalar %1$s</string>
|
||||
<string name="repo_install_msg">¿ Quieres instalar %1$s ?</string>
|
||||
<string name="repo_install_msg">¿Quieres instalar %1$s ahora?</string>
|
||||
<string name="download_install">Descargar e instalar</string>
|
||||
<string name="download">Descargar</string>
|
||||
<string name="goto_install">Ir a la sección \"Instalar\"</string>
|
||||
@@ -117,17 +127,25 @@
|
||||
<string name="process_error">Error de proceso</string>
|
||||
<string name="internal_storage">El zip es almacenado en:\n[Internal Storage]%1$s</string>
|
||||
<string name="zip_process_title">Procesando</string>
|
||||
<string name="manual_boot_image">¡Selecciona manualmente una imagen de arranque!</string>
|
||||
<string name="manager_update_title">Nueva actualización de Magisk Manager disponible!</string>
|
||||
<string name="manager_download_install">Pulse para descargar e instalar</string>
|
||||
<string name="magisk_updates">Actualización de Magisk</string>
|
||||
<string name="flashing">Flasheando</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">General</string>
|
||||
<string name="settings_dark_theme_title">Tema oscuro</string>
|
||||
<string name="settings_dark_theme_summary">Habilita el tema oscuro</string>
|
||||
<string name="settings_notification_title">Notificar Actualización</string>
|
||||
<string name="settings_notification_summary">Notificar cuando una nueva versión esté disponible</string>
|
||||
<string name="settings_clear_cache_title">Limpiar caché del repositorio</string>
|
||||
<string name="settings_clear_cache_summary">Limpiar la información en caché para los repositorios en línea, fuerza a la aplicación a actualizar en línea</string>
|
||||
|
||||
<string name="language">Idioma</string>
|
||||
<string name="system_default">(Idioma del sistema)</string>
|
||||
|
||||
<string name="settings_core_only_summary">Habilitar sólo funciones principales, no se cargarán todos los módulos. MagiskSU, MagiskHide, y archivo hosts fuera de la partición de sistema seguirán habilitados</string>
|
||||
<string name="settings_magiskhide_summary">Ocultar Magisk de varias detecciones</string>
|
||||
<string name="settings_busybox_title">Habilitar BusyBox</string>
|
||||
<string name="settings_busybox_summary">Montar el busybox interno de Magisk en xbin</string>
|
||||
<string name="settings_hosts_title">Habilitar archivo hosts fuera de la partición de sistema</string>
|
||||
<string name="settings_hosts_summary">Soporte para aplicaciones de bloqueo de publicidad fuera de la partición de sistema</string>
|
||||
|
||||
@@ -144,7 +162,26 @@
|
||||
<string name="request_timeout">Tiempo de petición</string>
|
||||
<string name="superuser_notification">Notificación de superusuario</string>
|
||||
<string name="request_timeout_summary">%1$s segundos</string>
|
||||
<string name="settings_su_reauth_title">Re-autenticación</string>
|
||||
<string name="settings_su_reauth_summary">Pedir permisos de superusuario nuevamente si una aplicación es actualizada o reinstalada</string>
|
||||
|
||||
<string name="multiuser_mode">Modo MultiUsuario</string>
|
||||
<string name="settings_owner_only">Sólo Administrador del Dispositivo</string>
|
||||
<string name="settings_owner_manage">Administrador del Dispositivo</string>
|
||||
<string name="settings_user_independent">Usuario Independiente</string>
|
||||
<string name="owner_only_summary">Sólo el administrador tiene acceso root</string>
|
||||
<string name="owner_manage_summary">Sólo el administrador puede supervisar el acceso root y recibir solicitudes de otros usuarios</string>
|
||||
<string name="user_indepenent_summary">Cada usuario tiene separadas sus propias reglas de root </string>
|
||||
<string name="multiuser_hint_owner_request">Se ha enviado una solicitud al administrador del dispositivo. Por favor, cambie a la cuenta del administrador y conceda el permiso</string>
|
||||
|
||||
<string name="mount_namespace_mode">Montar Namespace </string>
|
||||
<string name="settings_ns_global">Global Namespace</string>
|
||||
<string name="settings_ns_requester">Heredar Namespace</string>
|
||||
<string name="settings_ns_isolate">Aislar Namespace</string>
|
||||
<string name="global_summary">Todas las sesiones de root utilizan el soporte Global Namespace</string>
|
||||
<string name="requester_summary">Las sesiones de root heredarán las peticiones Namespace</string>
|
||||
<string name="isolate_summary">Cada sesión root tendrá su propia Namespace</string>
|
||||
|
||||
<string name="settings_development_category">Desarrollo de la aplicación</string>
|
||||
<string name="settings_developer_logging_title">Habilitar información avanzada de depuración en el registro</string>
|
||||
<string name="settings_developer_logging_summary">Activar esto para grabar más información en el registro</string>
|
||||
|
@@ -123,7 +123,7 @@
|
||||
<string name="settings_clear_cache_title">Effacer le cache du dépôt</string>
|
||||
<string name="settings_clear_cache_summary">Effacer les informations en cache des dépôts en ligne, pour forcer une actualisation de l\'application</string>
|
||||
<string name="settings_core_only_title">Mode Magisk Core uniquement</string>
|
||||
<string name="settings_core_only_summary">Activer uniquement les fonctionnalités de base, tous les modules ne seront pas chargés. MagiskSU, MagiskHide, les hosts systemless et busybox restent activés</string>
|
||||
<string name="settings_core_only_summary">Activer uniquement les fonctionnalités de base, tous les modules ne seront pas chargés. MagiskSU, MagiskHide et les hosts systemless restent activés</string>
|
||||
<string name="settings_magiskhide_summary">Masquer Magisk de diverses détections</string>
|
||||
<string name="settings_busybox_title">Activer BusyBox</string>
|
||||
<string name="settings_busybox_summary">Monter le busybox de Magisk sur xbin</string>
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<!--Welcome Activity-->
|
||||
<string name="navigation_drawer_open">Apri drawer navigazione</string>
|
||||
<string name="navigation_drawer_close">Chiudi drawer navigazione</string>
|
||||
<string name="modules">Moduli</string>
|
||||
<string name="modules">Moduli</string>
|
||||
<string name="downloads">Download</string>
|
||||
<string name="superuser">Superuser</string>
|
||||
<string name="log">Registro eventi</string>
|
||||
@@ -12,7 +12,7 @@
|
||||
<string name="status">Stato</string>
|
||||
<string name="install">Installa</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version">Versione Magisk: v%1$s</string>
|
||||
<string name="magisk_version_core_only">Versione Magisk v%1$s (modo core)</string>
|
||||
<string name="magisk_version_error">Magisk non installato</string>
|
||||
@@ -52,6 +52,8 @@
|
||||
<string name="uninstall_magisk_title">Disinstalla Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Questo rimuoverà tutti i moduli, MagiskSU, e potenzialmente crittograferà i dati, se non crittografati/nVuoi continuare?</string>
|
||||
<string name="version_none">(nessuna)</string>
|
||||
<string name="reinstall">Reinstalla</string>
|
||||
<string name="update">Aggiorna</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(nessuna informazione)</string>
|
||||
@@ -127,6 +129,10 @@
|
||||
<string name="internal_storage">Lo ZIP si trova in:\n[memoria interna]%1$s</string>
|
||||
<string name="zip_process_title">Elaborazione</string>
|
||||
<string name="manual_boot_image">Seleziona manualmente l\'immagine di boot!</string>
|
||||
<string name="manager_update_title">Nuovo aggiornamento di Magisk Manager disponibile!</string>
|
||||
<string name="manager_download_install">Premere per scaricare e installare</string>
|
||||
<string name="magisk_updates">Aggiornamenti Magisk</string>
|
||||
<string name="flashing">Flashando</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Generale</string>
|
||||
@@ -138,7 +144,7 @@
|
||||
<string name="settings_clear_cache_summary">Azzera le informazioni nella cache per i repository online, e forza l\'aggiornamento online dell\'app</string>
|
||||
|
||||
<string name="settings_core_only_title">Solo modo core Magisk</string>
|
||||
<string name="settings_core_only_summary">Abilita solo le funzioni principali. Non tutti i moduli verranno caricati. MagiskSU, MagiskHide, host systemless, e busybox rimarranno abilitati</string>
|
||||
<string name="settings_core_only_summary">Abilita solo le funzioni principali. Non tutti i moduli verranno caricati. MagiskSU, MagiskHide, e host systemless rimarranno abilitati</string>
|
||||
<string name="settings_magiskhide_summary">Nasconde Magisk da numerose rilevazioni</string>
|
||||
<string name="settings_busybox_title">Abilita BusyBox</string>
|
||||
<string name="settings_busybox_summary">Collega il mount della busybox interna di Magisk a xbin</string>
|
||||
@@ -158,7 +164,7 @@
|
||||
<string name="request_timeout">Timeout richiesta</string>
|
||||
<string name="superuser_notification">Notifica Superuser</string>
|
||||
<string name="request_timeout_summary">%1$s secondi</string>
|
||||
<string name="settings_su_reauth_title">Ri-autentifica dopo aggironamento</string>
|
||||
<string name="settings_su_reauth_title">Ri-autentifica dopo aggiornamento</string>
|
||||
<string name="settings_su_reauth_summary">Ri-autentifica permessi superuser dopo aggiornamento applicazione</string>
|
||||
|
||||
<string name="multiuser_mode">Modo multiutente</string>
|
||||
|
@@ -134,7 +134,7 @@
|
||||
<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、busyboxは引き続き有効になります。</string>
|
||||
<string name="settings_core_only_summary">コア機能のみを有効にすると、すべてのモジュールがロードされなくなります。 MagiskSU、MagiskHide、systemless hostsは引き続き有効になります。</string>
|
||||
<string name="settings_magiskhide_summary">さまざまな検出からMagiskを隠す</string>
|
||||
<string name="settings_busybox_title">BusyBoxを有効にする</string>
|
||||
<string name="settings_busybox_summary">Magiskに搭載するBusyBoxをxbinにバインドする</string>
|
||||
|
@@ -133,7 +133,7 @@
|
||||
<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 및 busybox는 계속 사용할 수 있습니다.</string>
|
||||
<string name="settings_core_only_summary">핵심 기능만 사용합니다. 모든 모듈은 로드하지 않습니다. MagiskSU, MagiskHide 및 systemless hosts 는 계속 사용할 수 있습니다.</string>
|
||||
<string name="settings_magiskhide_summary">다양한 감지로부터 Magisk를 숨깁니다.</string>
|
||||
<string name="settings_busybox_title">BusyBox 사용</string>
|
||||
<string name="settings_busybox_summary">xbin 디렉터리에 Magisk의 빌트인 busybox를 바인드합니다.</string>
|
||||
@@ -192,5 +192,6 @@
|
||||
<string name="pid">PID:\u0020</string>
|
||||
<string name="target_uid">대상 UID:\u0020</string>
|
||||
<string name="command">명령:\u0020</string>
|
||||
<string name="download">다운로드</string>
|
||||
|
||||
</resources>
|
||||
|
@@ -52,6 +52,8 @@
|
||||
<string name="uninstall_magisk_title">Magisk deïnstalleren</string>
|
||||
<string name="uninstall_magisk_msg">Dit verwijdert alle modules, MagiskSU, en versleutelt mogelijk alle niet-versleutelde data\nZeker weten voortzetten?</string>
|
||||
<string name="version_none">(Geen)</string>
|
||||
<string name="reinstall">Herinstalleren</string>
|
||||
<string name="update">Bijwerken</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Geen info verstrekt)</string>
|
||||
@@ -136,9 +138,11 @@
|
||||
<string name="settings_notification_summary">Een update melding weergeven wanneer een nieuwe versie beschikbaar is</string>
|
||||
<string name="settings_clear_cache_title">Opslagcache wissen</string>
|
||||
<string name="settings_clear_cache_summary">Wis de gecachte informatie voor online opslagplaatsen. Dit dwingt de app om online te verversen</string>
|
||||
|
||||
<string name="language">Taal</string>
|
||||
<string name="system_default">(Systeem standaard)</string>
|
||||
|
||||
<string name="settings_core_only_title">Magisk basismodus</string>
|
||||
<string name="settings_core_only_summary">Alleen kernfuncties inschakelen. Alle modules worden niet geladen. MagiskSU, MagiskHide, systeemloze hosts, en busybox blijven ingeschakeld</string>
|
||||
<string name="settings_core_only_summary">Alleen kernfuncties inschakelen. Alle modules worden niet geladen. MagiskSU, MagiskHide, en systeemloze hosts blijven ingeschakeld</string>
|
||||
<string name="settings_magiskhide_summary">Magisk van verschillende detecties verbergen</string>
|
||||
<string name="settings_busybox_title">Busybox inschakelen</string>
|
||||
<string name="settings_busybox_summary">Magisk\'s ingebouwde busybox naar xbin bind mounten</string>
|
||||
|
@@ -143,7 +143,7 @@
|
||||
<string name="settings_clear_cache_summary">Wymusza na aplikacji odświeżenie online repozytorium</string>
|
||||
|
||||
<string name="settings_core_only_title">Tylko Tryb Rdzeni Magisk</string>
|
||||
<string name="settings_core_only_summary">Włącz tylko podstawowe funkcje, wszystkie moduły nie zostaną załadowane. MagiskSU, MagiskHide, systemless hosts i BusyBox nadal będą włączone</string>
|
||||
<string name="settings_core_only_summary">Włącz tylko podstawowe funkcje, wszystkie moduły nie zostaną załadowane. MagiskSU, MagiskHide i systemless hosts nadal będą włączone</string>
|
||||
<string name="settings_magiskhide_summary">Włącz Hide Magisk dla wykrytych aplikacji</string>
|
||||
<string name="settings_busybox_title">Włącz BusyBox</string>
|
||||
<string name="settings_busybox_summary">Zmień montowanie Magisk z wbudowanego busybox do xbin</string>
|
||||
|
@@ -28,12 +28,16 @@
|
||||
<string name="not_rooted">Sem root</string>
|
||||
<string name="proper_root">Rooteado</string>
|
||||
<string name="safetyNet_check_text">Pressione para checar o SafetyNet</string>
|
||||
<string name="checking_safetyNet_status">Checando status do SafetyNet…</string>
|
||||
<string name="checking_safetyNet_status">Verificando status do SafetyNet…</string>
|
||||
<string name="safetyNet_check_success">SafetyNet verificado</string>
|
||||
<string name="safetyNet_connection_failed">Não é possível conectar-se à API do Google</string>
|
||||
<string name="safetyNet_connection_suspended">A conexão com API do Google foi suspensa</string>
|
||||
<string name="safetyNet_no_response">Não é possível verificar o SafetyNet, sem Internet?</string>
|
||||
<string name="safetyNet_fail">SafetyNet Falhou: CTS profile mismatch</string>
|
||||
<string name="safetyNet_pass">SafetyNet Passado</string>
|
||||
<string name="safetyNet_network_loss">Conexão com a rede perdida</string>
|
||||
<string name="safetyNet_service_disconnected">O serviço foi morto</string>
|
||||
<string name="safetyNet_res_invalid">A resposta é inválida</string>
|
||||
<string name="root_info_warning">Funcionalidade muito limitada</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
@@ -126,6 +130,9 @@
|
||||
<string name="internal_storage">O zip foi salvo em:\n[Armazenamento interno]%1$s</string>
|
||||
<string name="zip_process_title">Processando</string>
|
||||
<string name="manual_boot_image">Por Favor, selecione manualmente a Boot Image</string>
|
||||
<string name="manager_update_title">Nova atualização do Magisk Manager disponível!</string>
|
||||
<string name="manager_download_install">Pressione para baixar e instalar</string>
|
||||
<string name="magisk_updates">Atualizações do Magisk</string>
|
||||
|
||||
<!--Settings Fragment -->
|
||||
<string name="settings_general_category">Geral</string>
|
||||
@@ -137,7 +144,7 @@
|
||||
<string name="settings_clear_cache_summary">Limpe as informações armazenadas em cache para repos. online, forçando o aplicativo a atualizar online</string>
|
||||
|
||||
<string name="settings_core_only_title">Magisk modo somente Core</string>
|
||||
<string name="settings_core_only_summary">Ativar somente recursos principais, todos os módulos não serão carregados. MagiskSU, MagiskHide, systemless hosts, e busybox ainda estará ativado</string>
|
||||
<string name="settings_core_only_summary">Ativar somente recursos principais, todos os módulos não serão carregados. MagiskSU, MagiskHide, e systemless hosts ainda estará ativado</string>
|
||||
<string name="settings_magiskhide_summary">Ocultar Magisk de várias detecções</string>
|
||||
<string name="settings_busybox_title">Ativar BusyBox</string>
|
||||
<string name="settings_busybox_summary">Monta a busybox interna do Magisk\'s para xbin</string>
|
||||
@@ -157,7 +164,26 @@
|
||||
<string name="request_timeout">Tempo limite de solicitação</string>
|
||||
<string name="superuser_notification">Notificação do superusuário</string>
|
||||
<string name="request_timeout_summary">%1$s segundos</string>
|
||||
<string name="settings_su_reauth_title">Re-autenticar após a atualização</string>
|
||||
<string name="settings_su_reauth_summary">Re-autenticar permissões de superusuário após as atualizações de um aplicativo</string>
|
||||
|
||||
<string name="multiuser_mode">Modo Multiusuário</string>
|
||||
<string name="settings_owner_only">Apenas Proprietário do Dispositivo</string>
|
||||
<string name="settings_owner_manage">Proprietário do dispositivo gerenciado</string>
|
||||
<string name="settings_user_independent">Usuário Independente</string>
|
||||
<string name="owner_only_summary">Somente o proprietário possui acesso de root</string>
|
||||
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso root e receber paineis de solicitações</string>
|
||||
<string name="user_indepenent_summary">Cada usuário tem suas próprias regras raiz separadas</string>
|
||||
<string name="multiuser_hint_owner_request">Um pedido foi enviado ao proprietário do dispositivo. Mude para o proprietário e conceda a permissão</string>
|
||||
|
||||
<string name="mount_namespace_mode">Modo namespace de montagem</string>
|
||||
<string name="settings_ns_global">Global namespace</string>
|
||||
<string name="settings_ns_requester">Herdar namespace</string>
|
||||
<string name="settings_ns_isolate">Isolar namespace</string>
|
||||
<string name="global_summary">Todas as sessões raiz usam o namespace de montagem global</string>
|
||||
<string name="requester_summary">As sessões de raiz herdarão o namespace do seu solicitante</string>
|
||||
<string name="isolate_summary">Cada sessão raiz terá seu próprio namespace isolado</string>
|
||||
|
||||
<string name="settings_development_category">Desenvolvimento</string>
|
||||
<string name="settings_developer_logging_title">Ativar registro mais detalhado</string>
|
||||
<string name="settings_developer_logging_summary">Marque essa opção para habilitar um registro mais detalhado</string>
|
227
app/src/main/res/values-pt-rPT/strings.xml
Normal file
227
app/src/main/res/values-pt-rPT/strings.xml
Normal file
@@ -0,0 +1,227 @@
|
||||
<resources>
|
||||
<!--Universal-->
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="navigation_drawer_open">Abrir gaveta de notificações</string>
|
||||
<string name="navigation_drawer_close">Fechar gaveta de notificações</string>
|
||||
<string name="modules">Módulos</string>
|
||||
<string name="downloads">Transferir</string>
|
||||
<string name="superuser">Super-Utilizador</string>
|
||||
<string name="log">Registo</string>
|
||||
<string name="settings">Definições</string>
|
||||
<string name="status">Estado</string>
|
||||
<string name="install">Instalar</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version">Magisk v%1$s Instalado</string>
|
||||
<string name="magisk_version_core_only">Magisk v%1$s Instalado(Somente em modo Core)</string>
|
||||
<string name="magisk_version_error">Magisk não instalado</string>
|
||||
|
||||
<string name="checking_for_updates">A procurar por atualizações…</string>
|
||||
<string name="magisk_update_available">Magisk v%1$s disponível!</string>
|
||||
<string name="cannot_check_updates">Não foi possível verificar atualizações, sem internet?</string>
|
||||
<string name="up_to_date">Última versão do %1$s instalado</string>
|
||||
<string name="root_error">Com root mas sem permissão de root, o acesso foi permitido?</string>
|
||||
<string name="not_rooted">Sem root</string>
|
||||
<string name="proper_root">Root instalado corretamente</string>
|
||||
<string name="safetyNet_check_text">Pressione para verificar SafetyNet</string>
|
||||
<string name="checking_safetyNet_status">A verificar o estado do SafetyNet…</string>
|
||||
<string name="safetyNet_check_success">SafetyNet verificado com sucesso</string>
|
||||
<string name="safetyNet_connection_failed">Não é possível ligar à API do Google</string>
|
||||
<string name="safetyNet_connection_suspended">A ligação com API do Google foi suspensa</string>
|
||||
<string name="safetyNet_no_response">Não é possível verificar o SafetyNet, sem Internet?</string>
|
||||
<string name="safetyNet_fail">SafetyNet Falhou: perfil CTS não corresponde</string>
|
||||
<string name="safetyNet_pass">SafetyNet Passado</string>
|
||||
<string name="safetyNet_network_loss">Perda de ligação</string>
|
||||
<string name="safetyNet_service_disconnected">Serviço foi interrompido</string>
|
||||
<string name="safetyNet_res_invalid">A resposta é inválida</string>
|
||||
<string name="root_info_warning">Funcionalidade muito limitada</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="auto_detect">(Auto) %1$s</string>
|
||||
<string name="cannot_auto_detect">(Não foi auto detetado)</string>
|
||||
<string name="boot_image_title">Local da Imagem de Arranque</string>
|
||||
<string name="detect_button">Detectar</string>
|
||||
<string name="advanced_settings_title">Definições avançadas</string>
|
||||
<string name="keep_force_encryption">Manter encriptação forçada</string>
|
||||
<string name="keep_dm_verity">Manter dm-verity</string>
|
||||
<string name="current_magisk_title">Versão instalada do Magisk: %1$s</string>
|
||||
<string name="install_magisk_title">Última versão do Magisk: %1$s</string>
|
||||
<string name="uninstall">Desinstalar</string>
|
||||
<string name="reboot_countdown">A reiniciar em %1$d</string>
|
||||
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Isso irá remover todos os módulos, MagiskSU, e Potencialmente encriptar seus dados se estiverem encriptados
|
||||
\nDeseja continuar?</string>
|
||||
<string name="version_none">(Nenhum)</string>
|
||||
<string name="reinstall">Reinstalar</string>
|
||||
<string name="update">Atualizar</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
|
||||
<string name="no_modules_found">Nenhum módulo encontrado</string>
|
||||
<string name="update_file_created">Módulo será atualizado depois de reiniciar</string>
|
||||
<string name="remove_file_created">Módulo será removido depois de reiniciar</string>
|
||||
<string name="remove_file_deleted">Módulo não será removido ao reiniciar</string>
|
||||
<string name="disable_file_created">Módulo será desativado depois de reiniciar</string>
|
||||
<string name="disable_file_removed">Módulo será ativado depois de reiniciar</string>
|
||||
<string name="author">Criado por %1$s</string>
|
||||
<string name="fab_flash_zip">Instalar Módulo Zip</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Atualização disponível</string>
|
||||
<string name="installed">Instalado</string>
|
||||
<string name="not_installed">Não Instalado</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveToSd">Gravar no SD</string>
|
||||
<string name="menuReload">Recarregar</string>
|
||||
<string name="menuClearLog">Limpar registo agora</string>
|
||||
<string name="logs_cleared">Registo limpo com sucesso</string>
|
||||
<string name="log_is_empty">Registo está vazio</string>
|
||||
<string name="logs_save_failed">Não foi possível gravar o registo para o cartão SD:</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">Sobre</string>
|
||||
<string name="app_developers">Principais programadores</string>
|
||||
<string name="app_developers_"><![CDATA[App criado por <a href="https://github.com/topjohnwu">topjohnwu</a> em colaboração com <a href="https://github.com/d8ahazard">Digitalhigh</a> e <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
|
||||
<string name="app_changelog">Lista de alterações da aplicação</string>
|
||||
<string name="app_version">Versão do aplicação</string>
|
||||
<string name="app_source_code">Código fonte</string>
|
||||
<string name="donation">Doar</string>
|
||||
<string name="app_translators">Tradutores da Aplicação</string>
|
||||
<string name="support_thread">Suporte</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="permissionNotGranted">Esta funcionalidade não funcionará sem permissão de escrita do armazenamento externo.</string>
|
||||
<string name="no_thanks">Não, Obrigado</string>
|
||||
<string name="yes">Sim</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="close">Fechar</string>
|
||||
<string name="repo_install_title">Instalar %1$s</string>
|
||||
<string name="repo_install_msg">Deseja instalar%1$s agora?</string>
|
||||
<string name="download_install">Transferir & instalar</string>
|
||||
<string name="download">Transferir</string>
|
||||
<string name="goto_install">Ir para secção instalar</string>
|
||||
<string name="download_file_error">Erro ao transferir ficheiro</string>
|
||||
<string name="install_error">Erro na instalação!</string>
|
||||
<string name="invalid_zip">Este zip não é um Módulo Magisk!!</string>
|
||||
<string name="reboot_title">Instalação bem-sucedida!</string>
|
||||
<string name="reboot_msg">Deseja reiniciar agora?</string>
|
||||
<string name="reboot">Reiniciar</string>
|
||||
<string name="copying_msg">A copiar zip para diretório temporário</string>
|
||||
<string name="zip_install_progress_title">A instalar</string>
|
||||
<string name="zip_unzip_msg">A descompactar ficheiro zip …</string>
|
||||
<string name="zip_process_msg">A processar ficheiro zip …</string>
|
||||
<string name="zip_install_progress_msg">A instalar %1$s …</string>
|
||||
<string name="no_magisk_title">Magisk Não Instalado!</string>
|
||||
<string name="no_magisk_msg">Deseja transferir e instalar o Magisk?</string>
|
||||
<string name="downloading_toast">A transferir %1$s</string>
|
||||
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
|
||||
<string name="settings_reboot_toast">Reinicie para aplicar definições</string>
|
||||
<string name="release_notes">Notas da atualização</string>
|
||||
<string name="repo_cache_cleared">Cache do repositório apagado</string>
|
||||
<string name="safetyNet_hide_notice">Esta aplicação usa SafetyNet
|
||||
\nJá manipulado pelo MagiskHide por padrão</string>
|
||||
<string name="start_magiskhide">A iniciar MagiskHide …</string>
|
||||
<string name="no_magisksu_title">Não está a usar MagiskSU!</string>
|
||||
<string name="no_magisksu_msg">Não está root instalado com MagiskSU, Usar somente MagiskHide pode não ser suficiente!
|
||||
\nNão é oficialmente suportado, E precisaria de ferramentas adicionais (ex: suhide) para passar pelo SafetyNet.</string>
|
||||
<string name="understand">Eu entendo</string>
|
||||
<string name="process_error">Erro no processo</string>
|
||||
<string name="internal_storage">O zip foi guardado em:
|
||||
\n[Armazenamento interno]%1$s</string>
|
||||
<string name="zip_process_title">A processar</string>
|
||||
<string name="manual_boot_image">Por Favor, selecione manualmente a imagem de Arranque</string>
|
||||
<string name="manager_update_title">Nova atualização do Magisk Manager disponível!</string>
|
||||
<string name="manager_download_install">Pressione para transferir e instalar</string>
|
||||
<string name="magisk_updates">Atualizações do Magisk</string>
|
||||
<string name="flashing">A instalar</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Geral</string>
|
||||
<string name="settings_dark_theme_title">Tema escuro</string>
|
||||
<string name="settings_dark_theme_summary">Ativa o tema escuro</string>
|
||||
<string name="settings_notification_title">Notificação de Atualização</string>
|
||||
<string name="settings_notification_summary">Mostrar notificações de atualização quando a nova versão estiver disponível</string>
|
||||
<string name="settings_clear_cache_title">Apagar Cache de Repositório</string>
|
||||
<string name="settings_clear_cache_summary">Apaga a informação cache de repositórios online. online, forçando a aplicação a atualizar online</string>
|
||||
<string name="language">Língua</string>
|
||||
<string name="system_default">(Padrão do Sistema)</string>
|
||||
|
||||
<string name="settings_core_only_title">Magisk somente em Modo Core</string>
|
||||
<string name="settings_core_only_summary">Ativar somente funcionalidades principais, todos os módulos não serão carregados. MagiskSU, MagiskHide, e systemless hosts ainda estará ativado</string>
|
||||
<string name="settings_magiskhide_summary">Oculta Magisk de várias deteções</string>
|
||||
<string name="settings_busybox_title">Ativar BusyBox</string>
|
||||
<string name="settings_busybox_summary">Ativar systemless hosts</string>
|
||||
<string name="settings_hosts_title">Ativar systemless hosts</string>
|
||||
<string name="settings_hosts_summary">Suporte de systemless para aplicações Adblock</string>
|
||||
|
||||
<string name="settings_su_app_adb">Aplicações e ADB</string>
|
||||
<string name="settings_su_app">Somente Aplicações</string>
|
||||
<string name="settings_su_adb">Somente ADB</string>
|
||||
<string name="settings_su_disable">Desativado</string>
|
||||
<string name="settings_su_request_10">10 segundos</string>
|
||||
<string name="settings_su_request_20">20 segundos</string>
|
||||
<string name="settings_su_request_30">30 segundos</string>
|
||||
<string name="settings_su_request_60">60 segundos</string>
|
||||
<string name="superuser_access">Acesso de Super-Utilizador</string>
|
||||
<string name="auto_response">Resposta Automática</string>
|
||||
<string name="request_timeout">Tempo limite de solicitação</string>
|
||||
<string name="superuser_notification">Notificação de Super-Utilizador</string>
|
||||
<string name="request_timeout_summary">%1$s segundos</string>
|
||||
<string name="settings_su_reauth_title">Autenticar novamente após atualizar</string>
|
||||
<string name="settings_su_reauth_summary">Autenticar novamente permissões de Super-Utilizador após atualizar aplicações</string>
|
||||
|
||||
<string name="multiuser_mode">Modo Multi-Utilizador</string>
|
||||
<string name="settings_owner_only">Apenas Proprietário de Dispositivo</string>
|
||||
<string name="settings_owner_manage">Gerido Proprietário do Dispositivo</string>
|
||||
<string name="settings_user_independent">Independente de Utilizadores</string>
|
||||
<string name="owner_only_summary">Apenas o proprietário tem acesso a root</string>
|
||||
<string name="owner_manage_summary">Apenas o proprietário pode gerir acesso root e receber pedidos</string>
|
||||
<string name="user_indepenent_summary">Cada utilizador tem suas próprias regras de root separadas</string>
|
||||
<string name="multiuser_hint_owner_request">Um pedido foi enviado ao proprietário do dispositivo. Mude para o proprietário e conceda a permissão</string>
|
||||
|
||||
<string name="mount_namespace_mode">Cada sessão root terá sua própria identificação isolada</string>
|
||||
<string name="settings_ns_global">Identificação Global</string>
|
||||
<string name="settings_ns_requester">Herdar Identificação</string>
|
||||
<string name="settings_ns_isolate">Identificação Isolada</string>
|
||||
<string name="global_summary">Todas as sessões root usam a identificação de montagem global</string>
|
||||
<string name="requester_summary">As sessões de root herdarão a identificação do seu solicitante</string>
|
||||
<string name="isolate_summary">Cada sessão root terá sua própria identificação isolada</string>
|
||||
|
||||
<string name="settings_development_category">Desenvolvimento</string>
|
||||
<string name="settings_developer_logging_title">Ativar registo mais detalhado</string>
|
||||
<string name="settings_developer_logging_summary">Marque essa opção para permitir um registo mais detalhado</string>
|
||||
<string name="settings_shell_logging_title">Ativar registo da linha de comandos</string>
|
||||
<string name="settings_shell_logging_summary">Marque esta opção para permitir o registo de todos os comandos</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Pedido de Super-Utilizador</string>
|
||||
<string name="deny_with_str">Negar%1$s</string>
|
||||
<string name="deny">Negar</string>
|
||||
<string name="prompt">Perguntar</string>
|
||||
<string name="grant">Permitir</string>
|
||||
<string name="su_warning">Concede acesso total ao seu dispositivo.
|
||||
\nNegue se não tiver certeza!</string>
|
||||
<string name="forever">Sempre</string>
|
||||
<string name="once">Uma vez</string>
|
||||
<string name="tenmin">10 minutos</string>
|
||||
<string name="twentymin">20 minutos</string>
|
||||
<string name="thirtymin">30 minutos</string>
|
||||
<string name="sixtymin">60 minutos</string>
|
||||
<string name="su_allow_toast">%1$s foi permitido o acesso de Super-Utilizador</string>
|
||||
<string name="su_deny_toast">%1$s foi negado o acesso de Super-Utilizador</string>
|
||||
<string name="no_apps_found">Não foram encontrados aplicações</string>
|
||||
<string name="su_snack_grant">Acesso de Super-Utilizador a %1$s foi permitido</string>
|
||||
<string name="su_snack_deny">Acesso de Super-Utilizador a %1$s foi negado</string>
|
||||
<string name="su_snack_notif_on">Notificações de %1$s está ativado</string>
|
||||
<string name="su_snack_notif_off">Notificações da %1$s está desativado</string>
|
||||
<string name="su_snack_log_on">Registo de %1$s está ativado</string>
|
||||
<string name="su_snack_log_off">Registo de %1$s está desativado</string>
|
||||
<string name="su_snack_revoke">%1$s direitos foram revogados</string>
|
||||
<string name="su_revoke_title">Revogar?</string>
|
||||
<string name="su_revoke_msg">Revogar os diretos do %1$s, Confirmar?</string>
|
||||
<string name="toast">Notificação(pop-up)</string>
|
||||
<string name="none">Nenhum</string>
|
||||
|
||||
<!--Superuser logs-->
|
@@ -134,7 +134,7 @@
|
||||
<string name="settings_clear_cache_summary">Ștergeți informațiile memorate în cache, forțează actualizarea aplicației online</string>
|
||||
|
||||
<string name="settings_core_only_title">Mod de bază</string>
|
||||
<string name="settings_core_only_summary">Se activează numai caracteristicile principale, toate modulele nu vor fi încărcate. MagiskSU, MagiskHide, systemless hosts şi busybox vor fi în continuare activate</string>
|
||||
<string name="settings_core_only_summary">Se activează numai caracteristicile principale, toate modulele nu vor fi încărcate. MagiskSU, MagiskHide şi systemless hosts vor fi în continuare activate</string>
|
||||
<string name="settings_magiskhide_summary">Ascundeţi Magisk de la diferite detectări</string>
|
||||
<string name="settings_busybox_title">Activare BusyBox</string>
|
||||
<string name="settings_busybox_summary">Montare busybox Magisk în xbin</string>
|
||||
|
@@ -1,66 +1,70 @@
|
||||
<resources>
|
||||
<!--Universal-->
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="navigation_drawer_open">Открыть меню навигации</string>
|
||||
<string name="navigation_drawer_close">Закрыть меню навигации</string>
|
||||
<string name="modules">Модули</string>
|
||||
<string name="downloads">Загрузки</string>
|
||||
<string name="superuser">Суперпользователь</string>
|
||||
<string name="log">Лог</string>
|
||||
<string name="log">История</string>
|
||||
<string name="settings">Настройки</string>
|
||||
<string name="status">Статус</string>
|
||||
<string name="status">Состояние</string>
|
||||
<string name="install">Установка</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version">Установлен Magisk v%1$s</string>
|
||||
<string name="magisk_version_core_only">Установлен v%1$s (Базовый режим)</string>
|
||||
<string name="magisk_version_core_only">Установлен Magisk v%1$s (Базовый режим)</string>
|
||||
<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="cannot_check_updates">Невозможно проверить обновления, нет соединения?</string>
|
||||
<string name="cannot_check_updates">Невозможно проверить наличие обновлений</string>
|
||||
<string name="up_to_date">Установлена последняя версия %1$s</string>
|
||||
<string name="root_error">Рут есть, но нет разрешения, не разрешено?</string>
|
||||
<string name="not_rooted">Нет рута</string>
|
||||
<string name="proper_root">Рут получен правильно</string>
|
||||
<string name="safetyNet_check_text">Нажмите для запуска проверки SafetyNet</string>
|
||||
<string name="root_error">Root присутствует, но отсутствует разрешение</string>
|
||||
<string name="not_rooted">Root отсутствует</string>
|
||||
<string name="proper_root">Корректный root-доступ</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_connection_failed">Невозможно соединиться с API Google</string>
|
||||
<string name="safetyNet_connection_suspended">Соединение с API Google было приостановлено</string>
|
||||
<string name="safetyNet_no_response">Невозможно выполнить проверку SafetyNet, нет соединения?</string>
|
||||
<string name="safetyNet_fail">SafetyNet не пройден: несовпадение профиля CTS</string>
|
||||
<string name="safetyNet_pass">SafetyNet пройден</string>
|
||||
<string name="safetyNet_network_loss">Потеря сетевого соединения</string>
|
||||
<string name="safetyNet_connection_failed">Невозможно подключиться к Google API</string>
|
||||
<string name="safetyNet_connection_suspended">Подключение к Google API было прервано</string>
|
||||
<string name="safetyNet_no_response">Невозможно выполнить проверку SafetyNet</string>
|
||||
<string name="safetyNet_fail">Проверка SafetyNet неудачна: несоответствие профиля CTS</string>
|
||||
<string name="safetyNet_pass">Проверка SafetyNet пройдена</string>
|
||||
<string name="safetyNet_network_loss">Подключение к интернету прервано</string>
|
||||
<string name="safetyNet_service_disconnected">Служба была остановлена</string>
|
||||
<string name="safetyNet_res_invalid">Некорректный ответ</string>
|
||||
<string name="root_info_warning">Функциональность значительно ограничена</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="auto_detect">(Авто) %1$s</string>
|
||||
<string name="cannot_auto_detect">(Невозможно определить)</string>
|
||||
<string name="boot_image_title">Местоположение образа Boot</string>
|
||||
<string name="cannot_auto_detect">(Автоопределение невозможно)</string>
|
||||
<string name="boot_image_title">Распоожение boot-образа</string>
|
||||
<string name="detect_button">Определить</string>
|
||||
<string name="advanced_settings_title">Дополнительные настройки</string>
|
||||
<string name="keep_force_encryption">Оставить шифрование</string>
|
||||
<string name="advanced_settings_title">Расширенные настройки</string>
|
||||
<string name="keep_force_encryption">Оставить принуд. шифрование</string>
|
||||
<string name="keep_dm_verity">Оставить dm-verity</string>
|
||||
<string name="current_magisk_title">Установленная версия Magisk: %1$s</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="reboot_countdown">Перезагрузка через %1$d</string>
|
||||
<string name="uninstall_magisk_title">Удалить Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Это удалит все модули, MagiskSU, и может зашифровать ваши данные, если они не зашифрованы\nПродолжить?</string>
|
||||
<string name="version_none">(Нет)</string>
|
||||
|
||||
<string name="uninstall_magisk_msg">Данное действие приведет к удалению всех модулей, MagiskSU, и может зашифровать данные, если они не зашифрованы.\nУверены, что желаете продолжить?</string>
|
||||
<string name="version_none">(Нет данных)</string>
|
||||
<string name="reinstall">Переустановить</string>
|
||||
<string name="update">Обновить</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Нет информации)</string>
|
||||
<string name="no_modules_found">Модули не найдены</string>
|
||||
<string name="update_file_created">Модуль будет обновлён при перезагрузке</string>
|
||||
<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="disable_file_created">Модуль будет отключен при перезагрузке</string>
|
||||
<string name="disable_file_removed">Модуль будет включен при перезагрузке</string>
|
||||
<string name="author">Автор: %1$s</string>
|
||||
<string name="fab_flash_zip">Прошить zip-архив</string>
|
||||
<string name="fab_flash_zip">Прошить архив с модулем</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Доступно обновление</string>
|
||||
@@ -68,132 +72,153 @@
|
||||
<string name="not_installed">Не установлен</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveToSd">Сохранить на SD-карту</string>
|
||||
<string name="menuSaveToSd">Сохранить на карту памяти</string>
|
||||
<string name="menuReload">Обновить</string>
|
||||
<string name="menuClearLog">Очистить</string>
|
||||
<string name="logs_cleared">Лог успешно очищен</string>
|
||||
<string name="log_is_empty">Лог пуст</string>
|
||||
<string name="logs_save_failed">Не удалось сохранить лог на SD-карту:</string>
|
||||
<string name="menuClearLog">Очистить историю сейчас</string>
|
||||
<string name="logs_cleared">История успешно очищена</string>
|
||||
<string name="log_is_empty">История пуста</string>
|
||||
<string name="logs_save_failed">Не удалось записать файл истории на карту памяти:</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">О приложении</string>
|
||||
<string name="app_developers">Основные разработчики</string>
|
||||
<string name="app_developers">Главные разработчики</string>
|
||||
<string name="app_developers_"><![CDATA[Приложение создано <a href="https://github.com/topjohnwu">topjohnwu</a> совместно с <a href="https://github.com/d8ahazard">Digitalhigh</a> и <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
|
||||
<string name="app_changelog">Список изменений</string>
|
||||
<string name="translators">Exalm</string>
|
||||
<string name="translators" />
|
||||
<string name="app_version">Версия</string>
|
||||
<string name="app_source_code">Исходный код</string>
|
||||
<string name="donation">Пожертвовать</string>
|
||||
<string name="donation">Поддержать проект</string>
|
||||
<string name="app_translators">Переводчики</string>
|
||||
<string name="support_thread">Страница поддержки</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="permissionNotGranted">Это не будет работать без доступа к внешнему хранилищу</string>
|
||||
<string name="permissionNotGranted">Данная функция не будет работать без разрешения на запись во внешнее хранилище</string>
|
||||
<string name="no_thanks">Нет, спасибо</string>
|
||||
<string name="yes">Да</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="close">Закрыть</string>
|
||||
<string name="repo_install_title">Установить %1$s</string>
|
||||
<string name="repo_install_msg">Вы хотите установить %1$s ?</string>
|
||||
<string name="repo_install_msg">Желаете установить %1$s ?</string>
|
||||
<string name="download_install">Скачать и установить</string>
|
||||
<string name="download">Скачать</string>
|
||||
<string name="goto_install">Перейти в раздел «Установка»</string>
|
||||
<string name="download_file_error">Ошибка при скачивании файла</string>
|
||||
<string name="install_error">Ошибка при установке!</string>
|
||||
<string name="invalid_zip">Этот архив не содержит модуль Magisk!!</string>
|
||||
<string name="goto_install">Перейти в раздел \"Установка\"</string>
|
||||
<string name="download_file_error">Ошибка скачивания файла</string>
|
||||
<string name="install_error">Ошибка во время установки!</string>
|
||||
<string name="invalid_zip">В архив отсутствует модуль Magisk!</string>
|
||||
<string name="reboot_title">Установка успешна!</string>
|
||||
<string name="reboot_msg">Вы хотите перезагрузиться?</string>
|
||||
<string name="reboot_msg">Желаете перезагрузить сейчас?</string>
|
||||
<string name="reboot">Перезагрузка</string>
|
||||
<string name="copying_msg">Копирование архива во временную директорию</string>
|
||||
<string name="copying_msg">Копирование архива во временную папку</string>
|
||||
<string name="zip_install_progress_title">Установка</string>
|
||||
<string name="zip_unzip_msg">Распаковка zip-файла…</string>
|
||||
<string name="zip_process_msg">Обработка zip-файла…</string>
|
||||
<string name="zip_install_progress_msg">Установка %1$s…</string>
|
||||
<string name="zip_unzip_msg">Распаковка архива …</string>
|
||||
<string name="zip_process_msg">Обработка архива …</string>
|
||||
<string name="zip_install_progress_msg">Установка %1$s …</string>
|
||||
<string name="no_magisk_title">Magisk не установлен!</string>
|
||||
<string name="no_magisk_msg">Вы хотите скачать и установить Magisk?</string>
|
||||
<string name="no_magisk_msg">Желаете скачать и установить Magisk?</string>
|
||||
<string name="downloading_toast">Скачивание %1$s</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="safetyNet_hide_notice">Это приложение использует SafetyNet\nУже обработано MagiskHide по умолчанию</string>
|
||||
<string name="start_magiskhide">Запуск MagiskHide…</string>
|
||||
<string name="no_magisksu_title">MagiskSU не используется!</string>
|
||||
<string name="no_magisksu_msg">Если рут получен не через MagiskSU, использования MagiskHide может не хватить!\nЭто официально не поддерживается, и вам могут понадобиться дополнительные инструменты (например, suhide), чтобы пройти SafetyNet.</string>
|
||||
<string name="understand">Я понимаю</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="safetyNet_hide_notice">Данное приложение использует SafetyNet.\nУже обработано MagiskHide по умолчанию</string>
|
||||
<string name="start_magiskhide">Запуск MagiskHide …</string>
|
||||
<string name="no_magisksu_title">Не использовать MagiskSU!</string>
|
||||
<string name="no_magisksu_msg">В том случае, если root-доступ получен не с помощью MagiskSU, использования MagiskHide может быть недостаточно!\nОфициально не поддерживается, следовательно, могут понадобиться дополнительные инструменты (например, suhide), для успешного прохождения проверки Safety Net</string>
|
||||
<string name="understand">Понимаю</string>
|
||||
<string name="process_error">Ошибка обработки</string>
|
||||
<string name="internal_storage">Этот архив расположен в:\n[Внутреннее хранилище]%1$s</string>
|
||||
<string name="internal_storage">Архив расположен:\n[Внутреннее Хранилище]%1$s</string>
|
||||
<string name="zip_process_title">Обработка</string>
|
||||
<string name="manual_boot_image">Выберите образ Boot вручную!</string>
|
||||
<string name="manual_boot_image">Пожалуйста, выберите вручную boot-образ!</string>
|
||||
<string name="manager_update_title">Доступно новое обновление менеджера Magisk!</string>
|
||||
<string name="manager_download_install">Нажмите, чтобы скачать и установить</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_notification_title">Уведомления об обновлениях</string>
|
||||
<string name="settings_notification_summary">Показывать уведомления при наличии новых версий</string>
|
||||
<string name="settings_clear_cache_title">Очистить кэш репозиториев</string>
|
||||
<string name="settings_clear_cache_summary">Удалить сохранённую информацию о сетевых репозиториях, чтобы приложение обновило информацию из сети</string>
|
||||
<string name="settings_dark_theme_summary">Включить тёмное оформление</string>
|
||||
<string name="settings_notification_title">Уведомление об обновлении</string>
|
||||
<string name="settings_notification_summary">Показывать уведомления об обновлении, когда доступна новая версия</string>
|
||||
<string name="settings_clear_cache_title">Очистка кеша</string>
|
||||
<string name="settings_clear_cache_summary">Очистить сохранённую информацию о сетевых репозиториях, заставляя приложение принудительно обновляться через Интернете</string>
|
||||
|
||||
<string name="settings_core_only_title">Базовый режим</string>
|
||||
<string name="settings_core_only_summary">Включить только основные функции, не загружать модули. MagiskSU, MagiskHide, Systemless hosts, и BusyBox будут включены</string>
|
||||
<string name="settings_core_only_title">Режим Magisk Core</string>
|
||||
<string name="settings_core_only_summary">Включить возможности только уровня Core, все модули не будут загружены. MagiskSU, MagiskHide и внесистемные хосты останутся включенными</string>
|
||||
<string name="settings_magiskhide_summary">Скрыть Magisk от различных проверок</string>
|
||||
<string name="settings_busybox_title">Включить BusyBox</string>
|
||||
<string name="settings_busybox_summary">Примонтировать встроенный busybox из Magisk в xbin</string>
|
||||
<string name="settings_hosts_title">Включить Systemless hosts</string>
|
||||
<string name="settings_hosts_summary">Поддержа Systemless hosts для блокировщиков рекламы</string>
|
||||
<string name="settings_busybox_summary">Монтирование встроенного в Magisk busybox в xbin</string>
|
||||
<string name="settings_hosts_title">Внесистемные хосты</string>
|
||||
<string name="settings_hosts_summary">Поддержка внесистемных хостов для приложений блокировки рекламы</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_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">Доступ суперпользователя</string>
|
||||
<string name="auto_response">Автоматический ответ</string>
|
||||
<string name="request_timeout">Таймаут запроса</string>
|
||||
<string name="auto_response">Автоответ</string>
|
||||
<string name="request_timeout">Период запроса</string>
|
||||
<string name="superuser_notification">Уведомление суперпользователя</string>
|
||||
<string name="request_timeout_summary">%1$s секунд</string>
|
||||
<string name="request_timeout_summary">%1$s сек.</string>
|
||||
<string name="settings_su_reauth_title">Реаутентификация после обновления</string>
|
||||
<string name="settings_su_reauth_summary">Перевыдача прав суперпользователя после обновлений приложения</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">Только владелец имеет root-доступ</string>
|
||||
<string name="owner_manage_summary">Только владелец может управлять root-доступом и обрабатывать запросы на предоставление</string>
|
||||
<string name="user_indepenent_summary">Каждый пользователь имеет свои собственные правила root-доступа</string>
|
||||
<string name="multiuser_hint_owner_request">Запрос был отправлен владельцу устройства. Пожалуйста, переключитесь на профиль владельца и предоставьте разрешение</string>
|
||||
|
||||
<string name="mount_namespace_mode">Режим монтирования пространства имён</string>
|
||||
<string name="settings_ns_global">Глобальное пространство имён</string>
|
||||
<string name="settings_ns_requester">Наследуемое пространство имён</string>
|
||||
<string name="settings_ns_isolate">Изолированное пространство имён</string>
|
||||
<string name="global_summary">Все сеансы Суперпользователя используют глобальное пространство имён</string>
|
||||
<string name="requester_summary">Сессии Суперпользователя наследуют пространство имен запрашивающего</string>
|
||||
<string name="isolate_summary">Каждая сессия Суперпользователя будет иметь собственное изолированное пространство имен</string>
|
||||
|
||||
<string name="settings_development_category">Разработка</string>
|
||||
<string name="settings_developer_logging_title">Включить подробное логгирование</string>
|
||||
<string name="settings_developer_logging_summary">Нажмите, чтобы включить подробную запись</string>
|
||||
<string name="settings_shell_logging_title">Включить подробное логгирование команд оболочки</string>
|
||||
<string name="settings_shell_logging_summary">Нажмите, чтобы включить запись всех команд оболочки и их вывод</string>
|
||||
<string name="settings_developer_logging_title">Расширенная история</string>
|
||||
<string name="settings_developer_logging_summary">Включить подробнейшее ведение истории отладки</string>
|
||||
<string name="settings_shell_logging_title">История команд оболочки</string>
|
||||
<string name="settings_shell_logging_summary">Включить подробную запись всех команд оболочки и их вывод</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Запрос прав суперпользователя</string>
|
||||
<string name="su_request_title">Запрос прав Суперпользователя</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="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</string>
|
||||
<string name="su_deny_toast">Отказано в получении прав суперпользователя для %1$s</string>
|
||||
<string name="no_apps_found">Приложения не найдены</string>
|
||||
<string name="su_snack_grant">Права суперпользователя предоставлены для %1$s</string>
|
||||
<string name="su_snack_deny">Права суперпользователя для %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="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 предоставлены права Суперпользователя</string>
|
||||
<string name="su_deny_toast">%1$s отказано в правах Суперпользователя</string>
|
||||
<string name="no_apps_found">Приложения не обнаружены</string>
|
||||
<string name="su_snack_grant">%1$s предоставлены права Суперпользователя</string>
|
||||
<string name="su_snack_deny">%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="target_uid">Целевой UID:\u0020</string>
|
||||
<string name="command">Команда:\u0020</string>
|
||||
|
||||
</resources>
|
||||
|
225
app/src/main/res/values-sv/strings.xml
Normal file
225
app/src/main/res/values-sv/strings.xml
Normal file
@@ -0,0 +1,225 @@
|
||||
<resources>
|
||||
<!--Universal-->
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="navigation_drawer_open">Öppna navigeringslåda</string>
|
||||
<string name="navigation_drawer_close">Stäng navigeringslåda</string>
|
||||
<string name="modules">Moduler</string>
|
||||
<string name="downloads">Nerladdningar</string>
|
||||
<string name="superuser">Superuser</string>
|
||||
<string name="log">Logg</string>
|
||||
<string name="settings">Inställningar</string>
|
||||
<string name="status">Status</string>
|
||||
<string name="install">Install</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version">Magisk v%1$s installerad</string>
|
||||
<string name="magisk_version_core_only">Magisk v%1$s installerad (endast kärnläge)</string>
|
||||
<string name="magisk_version_error">Magisk är inte installerad</string>
|
||||
|
||||
<string name="checking_for_updates">Söker efter uppdateringar…</string>
|
||||
<string name="magisk_update_available">Magisk v%1$s tillgänglig!</string>
|
||||
<string name="cannot_check_updates">Kan inte söka efter uppdateringar, inget internet?</string>
|
||||
<string name="up_to_date">Senaste version av %1$s installerad</string>
|
||||
<string name="root_error">Rootad men inga root-rättigheter, inte tillåtet?</string>
|
||||
<string name="not_rooted">Inte rootad</string>
|
||||
<string name="proper_root">Troligen rootad</string>
|
||||
<string name="safetyNet_check_text">Tryck för att starta SafetyNet-kontroll</string>
|
||||
<string name="checking_safetyNet_status">Kontrollerar SafetyNet-status…</string>
|
||||
<string name="safetyNet_check_success">SafetyNet-kontroll lyckades</string>
|
||||
<string name="safetyNet_connection_failed">Kan inte ansluta till Google-API</string>
|
||||
<string name="safetyNet_connection_suspended">Anslutningen till Google-API stängdes av</string>
|
||||
<string name="safetyNet_no_response">Kan inte kontrollera SafetyNet, inget internet?</string>
|
||||
<string name="safetyNet_fail">SafetyNet misslyckades: CTS-profilen matchade inte</string>
|
||||
<string name="safetyNet_pass">SafetyNet godkänd</string>
|
||||
<string name="safetyNet_network_loss">Tappade nätverksanslutningen</string>
|
||||
<string name="safetyNet_service_disconnected">Tjänsten har dödats</string>
|
||||
<string name="safetyNet_res_invalid">Svaret är ogiltigt</string>
|
||||
<string name="root_info_warning">Funktionen är mycket begränsad</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="auto_detect">(Auto) %1$s</string>
|
||||
<string name="cannot_auto_detect">(Det går inte att auto-detektera)</string>
|
||||
<string name="boot_image_title">Boot-image plats</string>
|
||||
<string name="detect_button">Detektera</string>
|
||||
<string name="advanced_settings_title">Advancerade inställningar</string>
|
||||
<string name="keep_force_encryption">Fortsätt tvinga kryptering</string>
|
||||
<string name="keep_dm_verity">Behåll dm-verity</string>
|
||||
<string name="current_magisk_title">Installerad Magisk: %1$s</string>
|
||||
<string name="install_magisk_title">Senaste Magisk: %1$s</string>
|
||||
<string name="uninstall">Avinstallera</string>
|
||||
<string name="reboot_countdown">Omstart om %1$d</string>
|
||||
<string name="uninstall_magisk_title">Avinstallera Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Detta kommer att ta bort alla moduler, MagiskSU, och potentiellt kryptera din data om inte krypterad\nÄr det säker du vill fortsätta?</string>
|
||||
<string name="version_none">(Inga)</string>
|
||||
<string name="reinstall">Installera om</string>
|
||||
<string name="update">Uppdatera</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Ingen information tillhandahållen)</string>
|
||||
<string name="no_modules_found">Hittade inga moduler</string>
|
||||
<string name="update_file_created">Modulen kommer att uppdateras vid nästa omstart</string>
|
||||
<string name="remove_file_created">Modulen kommer att tas bort vid nästa omstart</string>
|
||||
<string name="remove_file_deleted">Modulen kommer att inte att tas bort vid nästa omstart</string>
|
||||
<string name="disable_file_created">Modulen kommer att inaktiveras vid nästa omstart</string>
|
||||
<string name="disable_file_removed">Modulen kommer att aktiveras vid nästa omstart</string>
|
||||
<string name="author">Skapad av %1$s</string>
|
||||
<string name="fab_flash_zip">Flasha ZIP-modul</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Uppdatering tillgänglig</string>
|
||||
<string name="installed">Installerad</string>
|
||||
<string name="not_installed">Inte installerad</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveToSd">Spara till SD-kort</string>
|
||||
<string name="menuReload">Uppdatera</string>
|
||||
<string name="menuClearLog">Rensa loggen</string>
|
||||
<string name="logs_cleared">Loggen rensad</string>
|
||||
<string name="log_is_empty">Loggen är tom</string>
|
||||
<string name="logs_save_failed">Loggen kunde inte skrivas till SD-kort:</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">Om</string>
|
||||
<string name="app_developers">Huvudutvecklare</string>
|
||||
<string name="app_developers_"><![CDATA[Appen skapades av <a href="https://github.com/topjohnwu">topjohnwu</a> i samarbete med <a href="https://github.com/d8ahazard">Digitalhigh</a> och <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
|
||||
<string name="app_changelog">Ändringslogg</string>
|
||||
<string name="translators" />
|
||||
<string name="app_version">Version</string>
|
||||
<string name="app_source_code">Källkod</string>
|
||||
<string name="donation">Donation</string>
|
||||
<string name="app_translators">Översättare</string>
|
||||
<string name="support_thread">Supporttråd</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="permissionNotGranted">Denna funktionen måste ha behörighet att skriva till externt lagringsutrymme.</string>
|
||||
<string name="no_thanks">Nej tack</string>
|
||||
<string name="yes">Ja</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="close">Stäng</string>
|
||||
<string name="repo_install_title">Installera %1$s</string>
|
||||
<string name="repo_install_msg">Vill du installera %1$s ?</string>
|
||||
<string name="download_install">Ladda ner & installera</string>
|
||||
<string name="download">Ladda ner</string>
|
||||
<string name="goto_install">Gå till sektionen \"Installera\"</string>
|
||||
<string name="download_file_error">Fel vid nerladdning av fil</string>
|
||||
<string name="install_error">Installation error!</string>
|
||||
<string name="invalid_zip">ZIP-filen är inte en modul till Magisk!</string>
|
||||
<string name="reboot_title">Installationen lyckades!</string>
|
||||
<string name="reboot_msg">Vill du starta om nu?</string>
|
||||
<string name="reboot">Starta om</string>
|
||||
<string name="copying_msg">Kopierar ZIP-filen till temp-katalogen</string>
|
||||
<string name="zip_install_progress_title">Installerar</string>
|
||||
<string name="zip_unzip_msg">Packar upp ZIP-filen …</string>
|
||||
<string name="zip_process_msg">Bearbetar ZIP-filen …</string>
|
||||
<string name="zip_install_progress_msg">Installerar %1$s …</string>
|
||||
<string name="no_magisk_title">Magisk är inte installerad!</string>
|
||||
<string name="no_magisk_msg">Vill du ladda ner och installera Magisk?</string>
|
||||
<string name="downloading_toast">Laddar ner %1$s</string>
|
||||
<string name="magisk_update_title">En uppdatering av Magisk finns tillgänglig!</string>
|
||||
<string name="settings_reboot_toast">Starta om för att tillämpa inställningar</string>
|
||||
<string name="release_notes">Release notes</string>
|
||||
<string name="repo_cache_cleared">Repo-cache rensad</string>
|
||||
<string name="safetyNet_hide_notice">Denna appen använder SafetyNet\nHanteras redan av MagiskHide som standard</string>
|
||||
<string name="start_magiskhide">Startar MagiskHide …</string>
|
||||
<string name="no_magisksu_title">Använder inte MagiskSU!</string>
|
||||
<string name="no_magisksu_msg">Du är inte rootad med MagiskSU och att endast använda MagiskHide kanske inte räcker!\nDet stöds inte officiellt och du skulle behöva ytterligare verktyg (t.ex suhide) för att ta dig förbi Safety Net.</string>
|
||||
<string name="understand">Jag förstår</string>
|
||||
<string name="process_error">Processfel</string>
|
||||
<string name="internal_storage">ZIP-filen är sparad i:\n[Internal Storage]%1$s</string>
|
||||
<string name="zip_process_title">Arbetar</string>
|
||||
<string name="manual_boot_image">Välj manuellt en boot-image!</string>
|
||||
<string name="manager_update_title">En uppdatering av Magisk maneger finns tillgänglig!</string>
|
||||
<string name="manager_download_install">Tryck för att ladda ner och installera</string>
|
||||
<string name="magisk_updates">Magiska uppdateringar</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Allmän</string>
|
||||
<string name="settings_dark_theme_title">Mörkt tema</string>
|
||||
<string name="settings_dark_theme_summary">Aktivera mörkt tema</string>
|
||||
<string name="settings_notification_title">Uppdateringsavisering</string>
|
||||
<string name="settings_notification_summary">Visa en avisering när det finns en ny version tillgänglig</string>
|
||||
<string name="settings_clear_cache_title">Rensa repo-cache</string>
|
||||
<string name="settings_clear_cache_summary">Rensa den lagrade information för online-repos, tvingar appen att uppdatera online</string>
|
||||
|
||||
<string name="settings_core_only_title">Endast Magisk kärnläge</string>
|
||||
<string name="settings_core_only_summary">Aktiverar endast kärnfunktioner, alla moduler laddas inte. MagiskSU, MagiskHide och systemless hosts kommer fortfarande att vara aktiverade</string>
|
||||
<string name="settings_magiskhide_summary">Dölj Magisk från att bli upptäckt</string>
|
||||
<string name="settings_busybox_title">Aktivera BusyBox</string>
|
||||
<string name="settings_busybox_summary">Bind mount Magisk\'s inbyggda busybox till xbin</string>
|
||||
<string name="settings_hosts_title">Systemless hosts</string>
|
||||
<string name="settings_hosts_summary">Systemless hosts-stöd för Adblock-appar</string>
|
||||
|
||||
<string name="settings_su_app_adb">Apps och ADB</string>
|
||||
<string name="settings_su_app">Endast appar</string>
|
||||
<string name="settings_su_adb">Endast ADB</string>
|
||||
<string name="settings_su_disable">Inaktiverad</string>
|
||||
<string name="settings_su_request_10">10 sekunder</string>
|
||||
<string name="settings_su_request_20">20 sekunder</string>
|
||||
<string name="settings_su_request_30">30 sekunder</string>
|
||||
<string name="settings_su_request_60">60 sekunder</string>
|
||||
<string name="superuser_access">Superuser-tillgång</string>
|
||||
<string name="auto_response">Automatiskt svar</string>
|
||||
<string name="request_timeout">Förfrågnings-timeout</string>
|
||||
<string name="superuser_notification">Superuser-avisering</string>
|
||||
<string name="request_timeout_summary">%1$s sekunder</string>
|
||||
<string name="settings_su_reauth_title">Återautentisera efter uppdatering</string>
|
||||
<string name="settings_su_reauth_summary">Återautentisera superuser-behörigheter efter en applikationsuppdatering</string>
|
||||
|
||||
<string name="multiuser_mode">Multianvändarläge</string>
|
||||
<string name="settings_owner_only">Endast ägaren av enheten</string>
|
||||
<string name="settings_owner_manage">Enhetsägarhantering</string>
|
||||
<string name="settings_user_independent">Användaroberoende</string>
|
||||
<string name="owner_only_summary">Endast ägaren har root-tillgång</string>
|
||||
<string name="owner_manage_summary">Endast ägaren kan hantera root-åtkomst och få begärda förfrågningar</string>
|
||||
<string name="user_indepenent_summary">Varje användare har sina egna separata root-regler</string>
|
||||
<string name="multiuser_hint_owner_request">En förfrågan har skickats till enhetens ägaren. Byt till ägaren och bevilja behörigheten</string>
|
||||
|
||||
<string name="mount_namespace_mode">Montera namnrymdsläge</string>
|
||||
<string name="settings_ns_global">Global namnrymd</string>
|
||||
<string name="settings_ns_requester">Ärv namnrymden</string>
|
||||
<string name="settings_ns_isolate">Isolerad namnrymd</string>
|
||||
<string name="global_summary">Alla root-sessioner använder den globala monteringsnamnrymden</string>
|
||||
<string name="requester_summary">Root-sessioner kommer att ärva den sökandes namnrymd</string>
|
||||
<string name="isolate_summary">Varje root-session kommer att ha sin egen isolerade namnrymd</string>
|
||||
|
||||
<string name="settings_development_category">Apputveckling</string>
|
||||
<string name="settings_developer_logging_title">Aktivera avancerad debug-loggning</string>
|
||||
<string name="settings_developer_logging_summary">Markera för att aktivera detaljerad loggning</string>
|
||||
<string name="settings_shell_logging_title">Aktivera felsökningsloggning av shell-kommandon</string>
|
||||
<string name="settings_shell_logging_summary">Markera för att aktivera loggning av alla shell-kommandon och dess utmatning</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Superuser-förfrågan</string>
|
||||
<string name="deny_with_str">Neka%1$s</string>
|
||||
<string name="deny">Neka</string>
|
||||
<string name="prompt">Fråga</string>
|
||||
<string name="grant">Bevilja</string>
|
||||
<string name="su_warning">Beviljar full tillgång till din enhet.\nNeka om du är osäker!</string>
|
||||
<string name="forever">För alltid</string>
|
||||
<string name="once">En gång</string>
|
||||
<string name="tenmin">10 min</string>
|
||||
<string name="twentymin">20 min</string>
|
||||
<string name="thirtymin">30 min</string>
|
||||
<string name="sixtymin">60 min</string>
|
||||
<string name="su_allow_toast">%1$s är beviljad Superuser-rättigheter</string>
|
||||
<string name="su_deny_toast">%1$s är nekad Superuser-rättigheter</string>
|
||||
<string name="no_apps_found">Hittade inga appar</string>
|
||||
<string name="su_snack_grant">Superuser-rättigheter av %1$s är beviljad</string>
|
||||
<string name="su_snack_deny">Superuser-rättigheter av %1$s är nekad</string>
|
||||
<string name="su_snack_notif_on">Aviseringar från %1$s är aktiverad</string>
|
||||
<string name="su_snack_notif_off">Aviseringar från %1$s är inaktiverade</string>
|
||||
<string name="su_snack_log_on">Loggning av %1$s är aktiverad</string>
|
||||
<string name="su_snack_log_off">Loggning av %1$s är inaktiverad</string>
|
||||
<string name="su_snack_revoke">%1$s rättigheter är upphävda</string>
|
||||
<string name="su_revoke_title">Upphäv?</string>
|
||||
<string name="su_revoke_msg">Bekräfta upphävning av %1$s rättigheter?</string>
|
||||
<string name="toast">Toast-meddelande</string>
|
||||
<string name="none">Inga</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID:\u0020</string>
|
||||
<string name="target_uid">Mål-UID:\u0020</string>
|
||||
<string name="command">Kommando:\u0020</string>
|
||||
|
||||
</resources>
|
@@ -1,8 +1,9 @@
|
||||
<resources>
|
||||
<!--Universal-->
|
||||
<!--Welcome Activity-->
|
||||
<string name="navigation_drawer_open">Gezinti çekmecesini aç</string>
|
||||
<string name="navigation_drawer_close">Gezinti çekmecesini kapat</string>
|
||||
<string name="modules">Modüller</string>
|
||||
<string name="navigation_drawer_open">Gezinme çekmecesini aç</string>
|
||||
<string name="navigation_drawer_close">Gezinme çekmecesini kapat</string>
|
||||
<string name="modules">Modüller</string>
|
||||
<string name="downloads">İndir</string>
|
||||
<string name="superuser">Yetkili kullanıcı</string>
|
||||
<string name="log">Günlük</string>
|
||||
@@ -12,39 +13,46 @@
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version">Magisk v%1$s yüklü</string>
|
||||
<string name="magisk_version_error">Magisk yüklü değil</string>
|
||||
<string name="magisk_version_core_only">Magisk v%1$s yüklü (Yalnızca Çekirdek Modu)</string>
|
||||
<string name="magisk_version_error">Magisk yüklü değil</string>
|
||||
|
||||
<string name="checking_for_updates">Güncelleştirmeler denetleniyor…</string>
|
||||
<string name="magisk_update_available">Magisk v%1$s mevcut!</string>
|
||||
<string name="cannot_check_updates">Güncelleştirmeler denetlenemiyor, İnternet yok mu?</string>
|
||||
<string name="cannot_check_updates">Güncelleştirmeler denetlenemiyor, İnternet bağlantınız yok mu?</string>
|
||||
<string name="up_to_date">%1$s\'in son sürümü yüklü</string>
|
||||
<string name="root_error">Rootlu ama root izni yok, izin verilmedi mi?</string>
|
||||
<string name="not_rooted">Rootlu değil</string>
|
||||
<string name="proper_root">Düzgünce rootlandı</string>
|
||||
<string name="root_error">Kök erişimli ama kök erişimi izni yok, izin verilmedi mi?</string>
|
||||
<string name="not_rooted">Kök erişimli değil</string>
|
||||
<string name="proper_root">Uygun şekilde kök erişimi alındı</string>
|
||||
<string name="safetyNet_check_text">SafetyNet kontrolünü başlatmak için dokunun</string>
|
||||
<string name="checking_safetyNet_status">SafetyNet durumu kontrol ediliyor…</string>
|
||||
<string name="safetyNet_connection_failed">"Google API'ye bağlanılamıyor"</string>
|
||||
<string name="safetyNet_check_success">SafetyNet Kontrolü Başarılı</string>
|
||||
<string name="safetyNet_connection_failed">"Google API\'ye bağlanılamıyor"</string>
|
||||
<string name="safetyNet_connection_suspended">Google API bağlantısı askıya alındı</string>
|
||||
<string name="safetyNet_no_response">SafetyNet kontrol edilemiyor, İnternet yok mu?</string>
|
||||
<string name="safetyNet_no_response">SafetyNet kontrol edilemiyor, İnternet bağlantınız yok mu?</string>
|
||||
<string name="safetyNet_fail">SafetyNet başarısız: CTS profili uyumsuzluğu</string>
|
||||
<string name="safetyNet_pass">SafetyNet Geçti</string>
|
||||
<string name="safetyNet_network_loss">Kötü ağ bağlantısı</string>
|
||||
<string name="safetyNet_service_disconnected">Servis sonlandırıldı</string>
|
||||
<string name="safetyNet_res_invalid">Yanıt geçersiz</string>
|
||||
<string name="root_info_warning">İşlevsellik çok sınırlıdır</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="auto_detect">(Otomatik) %1$s</string>
|
||||
<string name="cannot_auto_detect">(Otomatik algılanamıyor)</string>
|
||||
<string name="boot_image_title">Boot İmajı Konumu</string>
|
||||
<string name="boot_image_title">Önyükleme İmajı Konumu</string>
|
||||
<string name="detect_button">Algıla</string>
|
||||
<string name="advanced_settings_title">Gelişmiş Ayarlar</string>
|
||||
<string name="keep_force_encryption">Şifrelemeyi zorlamayı sürdür</string>
|
||||
<string name="keep_dm_verity">"Dm-verity'yi koru"</string>
|
||||
<string name="keep_dm_verity">"Dm-verity\'yi koru"</string>
|
||||
<string name="current_magisk_title">Yüklenmiş Magisk Sürümü: %1$s</string>
|
||||
<string name="install_magisk_title">Son Magisk Sürümü: %1$s</string>
|
||||
<string name="uninstall">Kaldır</string>
|
||||
<string name="reboot_countdown">%1$d saniye içinde yeniden başlatılacak</string>
|
||||
<string name="uninstall_magisk_title">"Magisk'i kaldır"</string>
|
||||
<string name="uninstall_magisk_msg">"Bu, tüm modülleri, MagiskSU'yu kaldıracak ve şifrelenmemişse verilerinizi potansiyel olarak şifreleyecektir\nDevam etmek istediğinize emin misiniz?"</string>
|
||||
<string name="uninstall_magisk_title">"Magisk\'i kaldır"</string>
|
||||
<string name="uninstall_magisk_msg">"Bu, tüm modülleri, MagiskSU\'yu kaldıracak ve şifrelenmemişse verilerinizi potansiyel olarak şifreleyecektir\nDevam etmek istediğinize emin misiniz?"</string>
|
||||
<string name="version_none">(Hiçbiri)</string>
|
||||
<string name="reinstall">Yeniden Yükle</string>
|
||||
<string name="update">Güncelle</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Hiçbir açıklama sağlanmadı)</string>
|
||||
@@ -55,7 +63,7 @@
|
||||
<string name="disable_file_created">Modül sonraki yeniden başlatmada devre dışı bırakılacak</string>
|
||||
<string name="disable_file_removed">Modül sonraki yeniden başlatmada etkinleştirilecek</string>
|
||||
<string name="author">Yapımcı: %1$s</string>
|
||||
<string name="fab_flash_zip">"Modül Zip'ini Yükle"</string>
|
||||
<string name="fab_flash_zip">"Modül Zip\'ini Yükle"</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Güncelleme Mevcut</string>
|
||||
@@ -63,7 +71,7 @@
|
||||
<string name="not_installed">Yüklenmemiş</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveToSd">"SD'ye kaydet"</string>
|
||||
<string name="menuSaveToSd">"SD Kart\'a kaydet"</string>
|
||||
<string name="menuReload">Yenile</string>
|
||||
<string name="menuClearLog">Günlüğü temizle</string>
|
||||
<string name="logs_cleared">Günlük başarıyla temizlendi</string>
|
||||
@@ -73,13 +81,13 @@
|
||||
<!--About Activity-->
|
||||
<string name="about">Hakkında</string>
|
||||
<string name="app_developers">Ana geliştiriciler</string>
|
||||
<string name="app_developers_">"<![CDATA[<a href="https://github.com/topjohnwu">topjohnwu</a> tarafından <a href="https://github.com/d8ahazard">Digitalhigh</a> ve <a href="https://github.com/dvdandroid">Dvdandroid</a>]]>'in katkılarıyla oluşturuldu"</string>
|
||||
<string name="app_developers_">"<![CDATA[<a href="https://github.com/topjohnwu">topjohnwu</a> tarafından <a href="https://github.com/d8ahazard">Digitalhigh</a> ve <a href="https://github.com/dvdandroid">Dvdandroid</a>]]>\'in katkılarıyla oluşturuldu"</string>
|
||||
<string name="app_changelog">Uygulama değişiklikleri</string>
|
||||
<string name="translators">Fatih Fırıncı</string>
|
||||
<string name="translators">Fatih Fırıncı - Mevlüt TOPÇU</string>
|
||||
<string name="app_version">Uygulama sürümü</string>
|
||||
<string name="app_source_code">Kaynak kodu</string>
|
||||
<string name="donation">Bağış</string>
|
||||
<string name="app_translators">Çevirmen</string>
|
||||
<string name="donation">Bağış Yapın</string>
|
||||
<string name="app_translators">Çevirmenler</string>
|
||||
<string name="support_thread">Destek konusu</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
@@ -105,7 +113,7 @@
|
||||
<string name="zip_process_msg">Zip dosyası işleniyor …</string>
|
||||
<string name="zip_install_progress_msg">%1$s yükleniyor …</string>
|
||||
<string name="no_magisk_title">Magisk Yüklü Değil!</string>
|
||||
<string name="no_magisk_msg">"Magisk'i indirip yüklemek istiyor musunuz?"</string>
|
||||
<string name="no_magisk_msg">"Magisk\'i indirip yüklemek istiyor musunuz?"</string>
|
||||
<string name="downloading_toast">%1$s indiriliyor</string>
|
||||
<string name="magisk_update_title">Yeni Magisk Güncellemesi Mevcut!</string>
|
||||
<string name="settings_reboot_toast">Ayarları uygulamak için yeniden başlatın</string>
|
||||
@@ -114,12 +122,16 @@
|
||||
<string name="safetyNet_hide_notice">Bu uygulama, SafetyNet kullanıyor\nZaten MagiskHide tarafından varsayılan olarak ele alındı</string>
|
||||
<string name="start_magiskhide">MagiskHide başlatılıyor …</string>
|
||||
<string name="no_magisksu_title">MagiskSU kullanılmıyor!</string>
|
||||
<string name="no_magisksu_msg">"MagiskSU ile rootlu değilsiniz, MagiskHide'ın kendisini kullanmak yeterli olmayabilir!\nResmi olarak desteklenmez ve SafetyNet'i geçmek için ek araçlar (ör. suhide) gerekir."</string>
|
||||
<string name="no_magisksu_msg">"MagiskSU ile kök erişimli değilsiniz, MagiskHide\'ın kendisini kullanmak yeterli olmayabilir!\nResmi olarak desteklenmez ve SafetyNet\'i geçmek için ek araçlar (ör. suhide) gerekir."</string>
|
||||
<string name="understand">Anladım</string>
|
||||
<string name="process_error">İşlem hatası</string>
|
||||
<string name="internal_storage">Zip şuraya depolandı:\n[Dahili Hafıza]%1$s</string>
|
||||
<string name="zip_process_title">İşleniyor</string>
|
||||
<string name="manual_boot_image">Lütfen elle bir boot imajı seçin!</string>
|
||||
<string name="manager_update_title">Yeni Magisk Manager Güncellemesi Mevcut!</string>
|
||||
<string name="manager_download_install">İndirmek ve yüklemek için dokunun</string>
|
||||
<string name="magisk_updates">Magisk Güncellemeleri</string>
|
||||
<string name="flashing">Flaşlayın</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Genel</string>
|
||||
@@ -129,10 +141,14 @@
|
||||
<string name="settings_notification_summary">Yeni sürüm kullanılabilir olduğunda güncelleme bildirimlerini göster</string>
|
||||
<string name="settings_clear_cache_title">Repo Önbelleğini Temizle</string>
|
||||
<string name="settings_clear_cache_summary">Çevrimiçi repolar için önbellek bilgilerini temizle, uygulamayı çevrimiçi yenilemeye zorla</string>
|
||||
<string name="language">Dil</string>
|
||||
<string name="system_default">(Sistem Varsayılanı)</string>
|
||||
|
||||
<string name="settings_magiskhide_summary">"Magisk'i çeşitli algılamalardan gizle"</string>
|
||||
<string name="settings_busybox_title">"BusyBox'ı etkinleştir"</string>
|
||||
<string name="settings_busybox_summary">"Magisk'in dahili busybox'ını xbin'e bağla"</string>
|
||||
<string name="settings_core_only_title">Magisk Yalnızca Çekirdek Modu</string>
|
||||
<string name="settings_core_only_summary">Yalnızca temel özellikleri etkinleştirin, tüm modüller yüklenmez. MagiskSU, MagiskHide ve host yine de etkinleştirilecektir</string>
|
||||
<string name="settings_magiskhide_summary">"Magisk\'i çeşitli algılamalardan gizle"</string>
|
||||
<string name="settings_busybox_title">"BusyBox\'ı etkinleştir"</string>
|
||||
<string name="settings_busybox_summary">"Magisk\'in dahili busybox\'ını xbin\'e bağla"</string>
|
||||
<string name="settings_hosts_title">Sistemsiz host</string>
|
||||
<string name="settings_hosts_summary">Reklam engelleme uygulamaları için sistemsiz host desteği</string>
|
||||
|
||||
@@ -149,8 +165,27 @@
|
||||
<string name="request_timeout">İstek Zaman Aşımı</string>
|
||||
<string name="superuser_notification">Yetkili Kullanıcı Bildirimi</string>
|
||||
<string name="request_timeout_summary">%1$s saniye</string>
|
||||
<string name="settings_su_reauth_title">Yükseltmeden sonra yeniden kimlik doğrulaması yapın</string>
|
||||
<string name="settings_su_reauth_summary">Uygulama yükseltmeleri sonrasında yetkili kullanıcı izinlerini yeniden doğrulama</string>
|
||||
|
||||
<string name="settings_development_category">Uygulama Geliştirme</string>
|
||||
<string name="multiuser_mode">Çok Kullanıcılı Modu</string>
|
||||
<string name="settings_owner_only">Yalnızca Cihaz Sahibi</string>
|
||||
<string name="settings_owner_manage">Cihaz Sahibi Tarafından Yönetilen</string>
|
||||
<string name="settings_user_independent">Bağımsız Kullanıcı</string>
|
||||
<string name="owner_only_summary">Yalnızca kök erişimi olan kullanıcı</string>
|
||||
<string name="owner_manage_summary">Yalnızca cihaz sahibi kök erişimini yönetebilir ve izin isteklerini alabilir</string>
|
||||
<string name="user_indepenent_summary">Her kullanıcının kendi ayrı kök erişimi kuralları vardır</string>
|
||||
<string name="multiuser_hint_owner_request">Cihaz sahibine bir istek gönderilmiştir. Lütfen cihaz sahibi hesabına geçin ve izin verin</string>
|
||||
|
||||
<string name="mount_namespace_mode">Ad Alanı Modunu Doldur</string>
|
||||
<string name="settings_ns_global">Global Ad Alanı</string>
|
||||
<string name="settings_ns_requester">Inherit Ad Alanı</string>
|
||||
<string name="settings_ns_isolate">Isolated Ad Alanı</string>
|
||||
<string name="global_summary">Tüm kök oturumları genel bağlama ad alanını kullanır</string>
|
||||
<string name="requester_summary">Kök oturumları, istekte bulunanın ad alanını devralır</string>
|
||||
<string name="isolate_summary">Her bir kök oturumunun kendi izole ad alanı olacaktır</string>
|
||||
|
||||
<string name="settings_development_category">Uygulama Geliştirme</string>
|
||||
<string name="settings_developer_logging_title">Gelişmiş hata ayıklama günlüğünü etkinleştir</string>
|
||||
<string name="settings_developer_logging_summary">Ayrıntılı günlüğü etkinleştirmek için bunu işaretleyin</string>
|
||||
<string name="settings_shell_logging_title">Kabuk komut hata ayıklama günlüğünü etkinleştir</string>
|
||||
|
@@ -52,6 +52,8 @@
|
||||
<string name="uninstall_magisk_title">卸载 Magisk</string>
|
||||
<string name="uninstall_magisk_msg">将会删除所有模块及 MagiskSU,并有可能在目前未加密的情况下加密你的数据\n你确定要继续吗?</string>
|
||||
<string name="version_none">(无)</string>
|
||||
<string name="reinstall">重新安装</string>
|
||||
<string name="update">更新</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(未提供信息)</string>
|
||||
@@ -129,6 +131,8 @@
|
||||
<string name="manual_boot_image">请手动选择 Boot 镜像位置!</string>
|
||||
<string name="manager_update_title">Magisk Manager 有更新!</string>
|
||||
<string name="manager_download_install">点击以下载并安装</string>
|
||||
<string name="magisk_updates">Magisk 更新</string>
|
||||
<string name="flashing">正在刷入</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">常规</string>
|
||||
@@ -138,9 +142,11 @@
|
||||
<string name="settings_notification_summary">当有新版本可用时显示更新通知</string>
|
||||
<string name="settings_clear_cache_title">清除资源库缓存</string>
|
||||
<string name="settings_clear_cache_summary">清除已缓存的在线资源库信息,强制刷新在线数据</string>
|
||||
<string name="language">语言</string>
|
||||
<string name="system_default">(系统默认)</string>
|
||||
|
||||
<string name="settings_core_only_title">Magisk 核心功能模式</string>
|
||||
<string name="settings_core_only_summary">仅启用核心功能,所有模块将不会被载入。MagiskSU、MagiskHide、systemless hosts 和 busybox 仍会持续运作</string>
|
||||
<string name="settings_core_only_summary">仅启用核心功能,所有模块将不会被载入。MagiskSU、MagiskHide 和 systemless hosts 仍会持续运作</string>
|
||||
<string name="settings_magiskhide_summary">隐藏 Magisk 使其不被多种方法检测到</string>
|
||||
<string name="settings_busybox_title">启用 BusyBox</string>
|
||||
<string name="settings_busybox_summary">将 Magisk 内置的 Busybox 挂载到 xbin</string>
|
||||
|
@@ -192,7 +192,7 @@
|
||||
<string name="settings_notification_summary">有更新的時候顯示通知</string>
|
||||
<string name="settings_notification_title">更新通知</string>
|
||||
<string name="magisk_version_core_only">已安裝 Magisk v%1$s (僅核心功能)</string>
|
||||
<string name="settings_core_only_summary">僅啟用核心功能,所有模組將不會被載入。MagiskSU、MagiskHide、systemless hosts、和 busybox 仍會持續運作</string>
|
||||
<string name="settings_core_only_summary">僅啟用核心功能,所有模組將不會被載入。MagiskSU、MagiskHide 和 systemless hosts 仍會持續運作</string>
|
||||
<string name="safetyNet_check_success">SafetyNet 檢查成功</string>
|
||||
<string name="safetyNet_network_loss">網路斷線</string>
|
||||
<string name="safetyNet_res_invalid">回傳值無效</string>
|
||||
@@ -216,5 +216,10 @@
|
||||
<string name="settings_ns_global">全域 Namespace</string>
|
||||
<string name="settings_ns_isolate">獨立 Namespace</string>
|
||||
<string name="settings_ns_requester">繼承 Namespace</string>
|
||||
<string name="reinstall">重新安裝</string>
|
||||
<string name="update">更新</string>
|
||||
<string name="magisk_updates">Magisk 更新</string>
|
||||
<string name="system_default">(系統預設)</string>
|
||||
<string name="language">語言</string>
|
||||
|
||||
</resources>
|
||||
|
@@ -16,29 +16,29 @@
|
||||
<string name="install">Install</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version">Installed Magisk v%1$s</string>
|
||||
<string name="magisk_version_core_only">Installed Magisk v%1$s (Core Only Mode)</string>
|
||||
<string name="magisk_version_error">Magisk not installed</string>
|
||||
<string name="magisk_version">Magisk v%1$s Installed</string>
|
||||
<string name="magisk_version_core_only">Magisk v%1$s Installed (Core Only Mode)</string>
|
||||
<string name="magisk_version_error">Magisk is not installed</string>
|
||||
|
||||
<string name="checking_for_updates">Checking for updates…</string>
|
||||
<string name="magisk_update_available">Magisk v%1$s available!</string>
|
||||
<string name="cannot_check_updates">Cannot check for updates, no Internet?</string>
|
||||
<string name="up_to_date">Latest version of %1$s installed</string>
|
||||
<string name="magisk_update_available">Magisk v%1$s is available!</string>
|
||||
<string name="cannot_check_updates">Cannot check for updates, no internet?</string>
|
||||
<string name="up_to_date">Latest version of %1$s is installed</string>
|
||||
<string name="root_error">Rooted but no root permission, not allowed?</string>
|
||||
<string name="not_rooted">Not rooted</string>
|
||||
<string name="proper_root">Properly rooted</string>
|
||||
<string name="safetyNet_check_text">Tap to start SafetyNet check</string>
|
||||
<string name="checking_safetyNet_status">Checking SafetyNet status…</string>
|
||||
<string name="safetyNet_check_success">SafetyNet Check Success</string>
|
||||
<string name="safetyNet_check_success">SafetyNet Check Was Successful</string>
|
||||
<string name="safetyNet_connection_failed">Cannot connect to Google API</string>
|
||||
<string name="safetyNet_connection_suspended">Connection to Google API was suspended</string>
|
||||
<string name="safetyNet_no_response">Cannot check SafetyNet, no Internet?</string>
|
||||
<string name="safetyNet_fail">SafetyNet Failed: CTS profile mismatch</string>
|
||||
<string name="safetyNet_no_response">Cannot verify SafetyNet, no internet?</string>
|
||||
<string name="safetyNet_fail">SafetyNet Invalid: CTS profile mismatch</string>
|
||||
<string name="safetyNet_pass">SafetyNet Passed</string>
|
||||
<string name="safetyNet_network_loss">Network connection loss</string>
|
||||
<string name="safetyNet_network_loss">Network connection unavailable</string>
|
||||
<string name="safetyNet_service_disconnected">Service has been killed</string>
|
||||
<string name="safetyNet_res_invalid">The response is invalid</string>
|
||||
<string name="root_info_warning">Functionality greatly limited</string>
|
||||
<string name="root_info_warning">Functionality is greatly limited</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="auto_detect">(Auto) %1$s</string>
|
||||
@@ -55,6 +55,8 @@
|
||||
<string name="uninstall_magisk_title">Uninstall Magisk</string>
|
||||
<string name="uninstall_magisk_msg">This will remove all modules, MagiskSU, and potentially encrypt your data if not encrypted\nAre you sure to continue?</string>
|
||||
<string name="version_none">(None)</string>
|
||||
<string name="reinstall">Re-Install</string>
|
||||
<string name="update">Update</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(No info provided)</string>
|
||||
@@ -99,13 +101,13 @@
|
||||
<string name="ok">OK</string>
|
||||
<string name="close">Close</string>
|
||||
<string name="repo_install_title">Install %1$s</string>
|
||||
<string name="repo_install_msg">Do you want to install %1$s ?</string>
|
||||
<string name="repo_install_msg">Do you want to install %1$s now?</string>
|
||||
<string name="download_install">Download & Install</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="goto_install">Go to \"Install\" section</string>
|
||||
<string name="download_file_error">Error downloading file</string>
|
||||
<string name="install_error">Installation error!</string>
|
||||
<string name="invalid_zip">The zip is not a Magisk Module!!</string>
|
||||
<string name="invalid_zip">This zip is not a Magisk Module!</string>
|
||||
<string name="reboot_title">Installation succeeded!</string>
|
||||
<string name="reboot_msg">Do you want to reboot now?</string>
|
||||
<string name="reboot">Reboot</string>
|
||||
@@ -114,7 +116,7 @@
|
||||
<string name="zip_unzip_msg">Unzipping zip file …</string>
|
||||
<string name="zip_process_msg">Processing zip file …</string>
|
||||
<string name="zip_install_progress_msg">Installing %1$s …</string>
|
||||
<string name="no_magisk_title">No Magisk Installed!</string>
|
||||
<string name="no_magisk_title">Magisk Is Not Installed!</string>
|
||||
<string name="no_magisk_msg">Do you want to download and install Magisk?</string>
|
||||
<string name="downloading_toast">Downloading %1$s</string>
|
||||
<string name="magisk_update_title">New Magisk Update Available!</string>
|
||||
@@ -132,6 +134,8 @@
|
||||
<string name="manual_boot_image">Please manually select a boot image!</string>
|
||||
<string name="manager_update_title">New Magisk Manager Update Available!</string>
|
||||
<string name="manager_download_install">Press to download and install</string>
|
||||
<string name="magisk_updates">Magisk Updates</string>
|
||||
<string name="flashing">Flashing</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">General</string>
|
||||
@@ -141,9 +145,11 @@
|
||||
<string name="settings_notification_summary">Show update notifications when new version is available</string>
|
||||
<string name="settings_clear_cache_title">Clear Repo Cache</string>
|
||||
<string name="settings_clear_cache_summary">Clear the cached information for online repos, forces the app to refresh online</string>
|
||||
<string name="language">Language</string>
|
||||
<string name="system_default">(System Default)</string>
|
||||
|
||||
<string name="settings_core_only_title">Magisk Core Only Mode</string>
|
||||
<string name="settings_core_only_summary">Enable only core features, all modules will not be loaded. MagiskSU, MagiskHide, systemless hosts, and busybox will still be enabled</string>
|
||||
<string name="settings_core_only_summary">Enable only core features, all modules will not be loaded. MagiskSU, MagiskHide, and systemless hosts will still be enabled</string>
|
||||
<string name="settings_magiskhide_summary">Hide Magisk from various detections</string>
|
||||
<string name="settings_busybox_title">Enable BusyBox</string>
|
||||
<string name="settings_busybox_summary">Bind mount Magisk\'s built-in busybox to xbin</string>
|
||||
@@ -202,13 +208,13 @@
|
||||
<string name="twentymin">20 min</string>
|
||||
<string name="thirtymin">30 min</string>
|
||||
<string name="sixtymin">60 min</string>
|
||||
<string name="su_allow_toast">%1$s is granted Superuser rights</string>
|
||||
<string name="su_deny_toast">%1$s is denied Superuser rights</string>
|
||||
<string name="su_allow_toast">%1$s was granted Superuser rights</string>
|
||||
<string name="su_deny_toast">%1$s was denied Superuser rights</string>
|
||||
<string name="no_apps_found">No apps found</string>
|
||||
<string name="su_snack_grant">Superuser rights of %1$s is granted</string>
|
||||
<string name="su_snack_deny">Superuser rights of %1$s is denied</string>
|
||||
<string name="su_snack_notif_on">Notifications of %1$s is enabled</string>
|
||||
<string name="su_snack_notif_off">Notifications of %1$s is disabled</string>
|
||||
<string name="su_snack_grant">Superuser rights of %1$s are granted</string>
|
||||
<string name="su_snack_deny">Superuser rights of %1$s are denied</string>
|
||||
<string name="su_snack_notif_on">Notifications of %1$s are enabled</string>
|
||||
<string name="su_snack_notif_off">Notifications of %1$s are disabled</string>
|
||||
<string name="su_snack_log_on">Logging of %1$s is enabled</string>
|
||||
<string name="su_snack_log_off">Logging of %1$s is disabled</string>
|
||||
<string name="su_snack_revoke">%1$s rights are revoked</string>
|
||||
|
@@ -2,6 +2,7 @@
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory
|
||||
android:key="general"
|
||||
android:title="@string/settings_general_category">
|
||||
|
||||
<SwitchPreference
|
||||
|
@@ -7,7 +7,7 @@ buildscript {
|
||||
maven { url "https://maven.google.com" }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.0-alpha5'
|
||||
classpath 'com.android.tools.build:gradle:3.0.0-beta2'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
@@ -23,3 +23,4 @@ org.gradle.daemon=true
|
||||
|
||||
# Enable AAPT2
|
||||
android.enableAapt2=true
|
||||
android.enableD8=true
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Sat Jul 01 15:55:10 CST 2017
|
||||
#Fri Jul 21 11:51:44 SGT 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip
|
||||
|
100
gradlew
vendored
100
gradlew
vendored
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
@@ -6,42 +6,6 @@
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
@@ -60,6 +24,46 @@ cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -85,7 +89,7 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
@@ -150,11 +154,19 @@ if $cygwin ; then
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
14
gradlew.bat
vendored
14
gradlew.bat
vendored
@@ -8,14 +8,14 @@
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
@@ -46,10 +46,9 @@ echo location of your Java installation.
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
@@ -60,11 +59,6 @@ set _SKIP=2
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
Reference in New Issue
Block a user