Compare commits

..

119 Commits

Author SHA1 Message Date
topjohnwu
55ecc41d06 Bump version 2017-07-20 03:20:17 +08:00
#DarkBasic - BasicHD
28fcdf2cbb Update strings.xml
Delele Translate "Magisk Modo Sólo Núcleo". (After several hours (Days :v ). I thought it was best left in its original form .Magisk Hide, should also be translated if it were the case, it was better to leave it that way so as not to confuse the users.)
Fix translation error
Translations Updates and added new line
2017-07-20 03:19:58 +08:00
topjohnwu
24087679a8 Update uninstaller 2017-07-20 02:56:36 +08:00
topjohnwu
5ac6a8cb4a Small minor updates 2017-07-20 02:54:34 +08:00
topjohnwu
668d85d14e Improve notification support 2017-07-20 01:44:32 +08:00
topjohnwu
c11a3dc95c Fix Magisk Manager freezing issue 2017-07-20 00:51:30 +08:00
topjohnwu
56f57c20a2 Update AsyncTasks to prevent memory leak 2017-07-19 18:01:22 +08:00
topjohnwu
240d14779a Minor cleanup in check updates 2017-07-19 16:10:17 +08:00
topjohnwu
3550d1e61c Bump version 2017-07-19 00:38:25 +08:00
topjohnwu
6513ad249c Fix string.xml 2017-07-19 00:36:54 +08:00
killer7mod
50297b1880 update strings.xml portuguese brazil 2017-07-19 00:25:36 +08:00
#DarkBasic - BasicHD
f189b78b9e #DBC01 - Translation update 2017-07-19 00:25:23 +08:00
zertyuiop
5c0250f495 Fix too long string
checking_safetyNet_status string is too long.
2017-07-19 00:24:47 +08:00
pavlaras
2093f726e9 Update strings.xml
corrected Greek translation
2017-07-19 00:24:36 +08:00
topjohnwu
10efe3859d Update repo fragment and adapter 2017-07-18 23:18:57 +08:00
topjohnwu
6933bcf7bb Merge shells 2017-07-18 17:14:42 +08:00
topjohnwu
2ea046cd80 Add flashing screen 2017-07-18 17:14:42 +08:00
topjohnwu
f4097a372b Root shell with no outputs 2017-07-18 01:06:05 +08:00
topjohnwu
87ea2a2bef Rewrite root shell 2017-07-16 03:00:01 +08:00
JpegXguy
cc14a1c361 Fix untranslated strings 2017-07-15 01:23:59 +08:00
topjohnwu
bcdface60d Fix crashing when installing modules 2017-07-15 01:22:00 +08:00
topjohnwu
4dc9419d2e Bump version 2017-07-14 02:31:29 +08:00
topjohnwu
d2bcac813e Fix update notifications on Android O 2017-07-14 02:27:02 +08:00
topjohnwu
080c37a7f6 Remove busybox from strings 2017-07-14 01:18:20 +08:00
topjohnwu
f9a3838db6 Fix strings 2017-07-13 15:37:00 +08:00
JpegXguy
1e61db104b Added Greek Language 2017-07-13 15:22:53 +08:00
Generator
30a9c7718d Added (European) Portuguese
Split Portuguese into pt_BR and pt_PT
2017-07-13 15:22:40 +08:00
Dmitry Val'd
34b052b5d3 Update strings.xml
Full and correct translation to russian language
2017-07-13 15:21:27 +08:00
topjohnwu
aaa12853ad Prevent crashing when requesting SN check while checking
Fixed #208, fixed #212
2017-07-13 15:12:43 +08:00
topjohnwu
b0ab55b0bf Only show one notification at a time 2017-07-13 14:51:12 +08:00
topjohnwu
d2f8496f4e Update dependency 2017-07-13 14:47:47 +08:00
topjohnwu
1a69b16d36 Bump version 2017-07-11 01:11:10 +08:00
topjohnwu
b5e8673e62 Fix small UI bug 2017-07-11 01:09:40 +08:00
topjohnwu
264c6a50b6 Update uninstallation 2017-07-11 00:55:53 +08:00
topjohnwu
493642eb38 Minor translation update 2017-07-11 00:55:44 +08:00
gh2923
28d42b9164 fix some expressions 2017-07-08 11:17:41 -05:00
Jens Lody
42f29062ca Fix timeout of temporary granted su-rights. 2017-07-08 11:17:07 -05:00
topjohnwu
c4377ed6c2 Bump version 2017-07-03 01:08:54 +08:00
topjohnwu
7d283ed65f Optimize imports 2017-07-01 18:09:34 +08:00
topjohnwu
bf1f941e50 Adapt to Android O new broadcast limitations 2017-07-01 18:09:34 +08:00
topjohnwu
789fef34ba Fix crash on Android O 2017-07-01 18:09:34 +08:00
topjohnwu
1daf5a611c MagiskHide now defaults to enabled 2017-07-01 17:38:33 +08:00
topjohnwu
6aed1db67e Update Android Studio 2017-07-01 15:57:49 +08:00
gh2923
cf68854770 Update Simplified Chinese Translation 2017-06-20 21:46:36 +08:00
linar10
711392c73b Update Strings PL 2017-06-20 21:45:46 +08:00
c727
9573c32481 update strings.de 2017-06-20 21:45:38 +08:00
RoySchutte
a15f80f79d Create strings.xml 2017-06-20 21:45:28 +08:00
Igor Sorocean
23e7475f06 update romanian translation 2017-06-20 21:45:11 +08:00
topjohnwu
1eb571b787 Proper handle policy changes 2017-06-20 18:33:50 +08:00
topjohnwu
dd3b716d85 Extract expandable viewholder 2017-06-20 17:57:17 +08:00
topjohnwu
28649c07e3 SU policy DB bug fix 2017-06-20 17:57:17 +08:00
topjohnwu
961e02be0d Update Android Studio 2017-06-20 17:54:40 +08:00
topjohnwu
a161491bfd Disable shrinkResources due to buildtool bug 2017-06-16 15:25:22 +08:00
topjohnwu
e0b4d1c1e4 Bump version 2017-06-16 04:07:10 +08:00
topjohnwu
fd4aaab137 Rewrite zip signing 2017-06-16 03:12:57 +08:00
topjohnwu
42d14d5ca2 Update to new build tools, target API 26 2017-06-16 03:06:22 +08:00
topjohnwu
d3ff482c9b Bump version 2017-06-08 22:55:48 +08:00
topjohnwu
f682368eeb Update strings 2017-06-08 22:49:26 +08:00
topjohnwu
4a5d033efb Store data in intent for OTA 2017-06-08 22:35:30 +08:00
topjohnwu
343161b195 Add mount namespace options 2017-06-08 22:27:24 +08:00
topjohnwu
bc576a9659 Update uninstall script 2017-06-08 04:28:55 +08:00
topjohnwu
19e407fcc4 Update translations 2017-06-08 04:23:17 +08:00
RoySchutte
bc7327d004 Update strings.xml 2017-06-08 04:14:12 +08:00
ROBERTO
666fa1c797 Update Italian translation 2017-06-08 04:14:01 +08:00
Igor Sorocean
0eda4a7821 Update romanian translation 2017-06-08 04:13:44 +08:00
topjohnwu
862058fd2b Bump version 2017-06-08 03:20:04 +08:00
topjohnwu
69e5bcd57d Simple OTA implementation 2017-06-07 02:21:58 +08:00
topjohnwu
efeddda328 Use Java synchronize instead serial tasks 2017-06-06 03:21:52 +08:00
topjohnwu
ff6938280e Switch to DB based su configs 2017-06-01 03:18:41 +08:00
RoySchutte
1e4425b30f Update strings-nl.xml 2017-05-31 11:45:02 -05:00
Igor Sorocean
b5d1d8cdad Update romanian translation 2017-05-31 11:44:37 -05:00
gh2923
029be5ccca Update Simplified Chinese Translation 2017-05-31 11:44:17 -05:00
gh2923
29c2d785b5 Update Simplified Chinese Translation 2017-05-31 11:44:04 -05:00
Exalm
abda8cfa32 Updated russian translation 2017-05-31 11:43:48 -05:00
topjohnwu
44e7d79d4c Add Arabic translation
Credits to @xx6600xx
2017-06-01 00:41:36 +08:00
topjohnwu
9a1dc8ee0e Refactor su database 2017-06-01 00:26:36 +08:00
topjohnwu
27879c3f01 Improve Logger 2017-05-31 17:43:55 +08:00
topjohnwu
29096eb5d7 Monitor package (un)install events 2017-05-31 16:31:33 +08:00
topjohnwu
a573baea03 Simplify SU requests, binary should be much superior now 2017-05-30 01:27:10 +08:00
topjohnwu
5af07c4531 Update Traditional Chinese translate 2017-05-28 01:44:29 +08:00
topjohnwu
44e36feb09 Improve multiuser settings and notification 2017-05-28 01:31:19 +08:00
topjohnwu
2a7d996881 Add multiuser support 2017-05-27 02:41:24 +08:00
topjohnwu
738f943a68 Several UI tweaks 2017-05-26 18:20:53 +08:00
dvdandroid
47e62a5681 Small code cleanup 2017-05-24 21:21:15 +02:00
dvdandroid
1ecbfd7590 Adjust theme in about and settings activities 2017-05-24 20:55:47 +02:00
topjohnwu
67c139a04b Fix theme changing glitch 2017-05-24 00:37:15 +08:00
RoySchutte
31cc008249 Update strings.xml
2 small changes to make strings more similar.
2017-05-23 19:47:38 +08:00
topjohnwu
9cb026439d Update translations 2017-05-23 17:02:05 +08:00
topjohnwu
e6f10176c6 Network check 2017-05-23 17:01:38 +08:00
RoySchutte
0917c79470 Update strings.xml
Added and translated new strings.
2017-05-22 23:53:59 +08:00
ROBERTO
597baa986d Updated Italian language 2017-05-22 23:53:43 +08:00
topjohnwu
75cc4b4843 Merge install and status 2017-05-21 12:16:38 +08:00
topjohnwu
aac088d496 Update strings.xml 2017-05-20 03:17:37 +08:00
RoySchutte
a822e5bbc5 Update strings.xml
Fixed many Dutch translations which were gramatically incorrect. Added translations (up-to-date).
Hopefully these translations will make it to the next release, because the current translations aren't pretty *_*.
2017-05-20 03:08:22 +08:00
Igor Sorocean
c527249c21 Add romanian translation 2017-05-20 03:08:14 +08:00
topjohnwu
9ef798f534 Update SafetyNet check UI 2017-05-20 03:04:14 +08:00
topjohnwu
e69b99f089 Update status UI 2017-05-19 08:37:57 -07:00
topjohnwu
55b8079e86 Update MagiskHide method 2017-05-12 23:11:28 +08:00
topjohnwu
e272dbe9af Include busybox binary and remove busybox toggle 2017-05-12 04:05:21 +08:00
topjohnwu
962f8354ac Use new version detection method 2017-05-12 02:25:07 +08:00
topjohnwu
20e4a960f7 Fix strings 2017-05-10 22:54:17 +08:00
ROBERTO
82249cb50a Italian language update 2017-04-28 23:45:41 +08:00
gh2923
fad417e553 Update Simplified Chinese Translation 2017-04-28 15:41:59 +08:00
lindwurm
5ba692f50c l10n: Update Japanese Translations
* Fixed more strings!

Signed-off-by: lindwurm <lindwurm.q@gmail.com>
2017-04-28 15:41:50 +08:00
topjohnwu
907e01e524 Use stable build tools + retrolambda 2017-04-26 19:04:06 +08:00
lindwurm
b8ed23efa7 l10n: Update Japanese Translations
Signed-off-by: lindwurm <lindwurm.q@gmail.com>
2017-04-26 19:03:14 +08:00
topjohnwu
2b3bbf7e67 Bump version 2017-04-26 00:59:56 +08:00
topjohnwu
464fe627a3 Swap tabs 2017-04-26 00:27:55 +08:00
topjohnwu
6a9e39c470 Support unlimited amount of repos 2017-04-26 00:15:53 +08:00
topjohnwu
7fec9a3cc6 Fix string.xml errors 2017-04-24 22:26:40 +08:00
Primokorn
008f6ef462 Update french strings.xml
Better translation.
2017-04-24 21:54:34 +08:00
lilymaniac
2440c108ca Update values-ko/strings.xml 2017-04-24 21:54:22 +08:00
linar10
430baad8a4 Update strings pl 2017-04-24 21:54:05 +08:00
Nosi
51132e74b4 Changes Spanish 2017-04-24 21:53:48 +08:00
killer7Mod
a4f33e106a Update Portuguese translation 2017-04-24 21:53:21 +08:00
SakuraSa233
baba3190e0 Add Japanese Translation 2017-04-24 21:53:05 +08:00
topjohnwu
47b13aa5ea Use stock FAB; Log monospace; Fixes 2017-04-24 21:52:23 +08:00
topjohnwu
ae88d3054d Finally, official Java 8 support 2017-04-05 17:02:18 +08:00
topjohnwu
411b600e14 Screw that Jack compiler, use retrolambda 2017-03-31 16:04:12 +08:00
112 changed files with 5722 additions and 4608 deletions

2
.gitignore vendored
View File

@@ -3,6 +3,6 @@
/local.properties
.idea/
/build
app/app-release.apk
app/release
*.hprof
app/.externalNativeBuild/

View File

@@ -1,4 +1,6 @@
# Magisk Manager
The project should be built with Android Studio version 2.2.0+
I use Java 8 features, which requires Jack compiler and it's only available in 2.2.0+
Also, you need to install CMake and NDK to build the zipadjust library for zip preprocessing
You need to install CMake and NDK to build the zipadjust library for zip preprocessing
## 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)

View File

@@ -1,28 +1,25 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
compileSdkVersion 26
buildToolsVersion "26.0.0"
defaultConfig {
applicationId "com.topjohnwu.magisk"
minSdkVersion 21
targetSdkVersion 25
versionCode 28
versionName "4.3.1"
jackOptions {
enabled true
jackInProcess true
}
targetSdkVersion 26
versionCode 51
versionName "5.1.1"
ndk {
moduleName 'zipadjust'
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
abiFilters 'x86', 'armeabi-v7a'
}
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -31,34 +28,36 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
dexOptions {
preDexLibraries = true
preDexLibraries true
javaMaxHeapSize "2g"
}
externalNativeBuild {
cmake {
path 'src/main/jni/CMakeLists.txt'
}
}
lintOptions {
disable 'MissingTranslation'
}
}
repositories {
jcenter()
maven { url "https://jitpack.io" }
maven { url "https://maven.google.com" }
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
compile 'com.android.support:support-v4:25.3.1'
compile 'com.jakewharton:butterknife:8.5.1'
compile 'com.github.clans:fab:1.6.4'
compile 'com.thoughtbot:expandablerecyclerview:1.4'
compile 'us.feras.mdv:markdownview:1.1.0'
compile 'com.madgag.spongycastle:core:1.54.0.0'
compile 'com.madgag.spongycastle:prov:1.54.0.0'
compile 'com.madgag.spongycastle:pkix:1.54.0.0'
compile 'com.madgag.spongycastle:pg:1.54.0.0'
compile 'com.google.android.gms:play-services-safetynet:9.0.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
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.7.0'
implementation 'com.thoughtbot:expandablerecyclerview:1.4'
implementation 'us.feras.mdv:markdownview:1.1.0'
implementation 'com.madgag.spongycastle:core:1.54.0.0'
implementation 'com.madgag.spongycastle:prov:1.54.0.0'
implementation 'com.madgag.spongycastle:pkix:1.54.0.0'
implementation 'com.google.android.gms:play-services-safetynet:9.0.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
}

View File

@@ -16,10 +16,10 @@
# public *;
#}
-keep class android.support.v7.internal.** { *; }
-keep interface android.support.v7.internal.** { *; }
-keep class android.support.v7.** { *; }
-keep interface android.support.v7.** { *; }
# SpongyCastle
-keep class org.spongycastle.** {*;}
-keep class org.spongycastle.** { *; }
-dontwarn javax.naming.**
-dontwarn android.content.**
-dontwarn android.animation.**

View File

@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.topjohnwu.magisk"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.topjohnwu.magisk">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application
android:name=".MagiskManager"
@@ -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"
@@ -52,21 +57,27 @@
android:taskAffinity="internal.superuser"
android:theme="@style/SuRequest" />
<receiver
android:name=".superuser.SuReceiver" />
<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" />
<service android:name=".services.BootupIntentService" />
<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"

View File

@@ -1,133 +1,153 @@
#!/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
# This path should work in any cases
TMPDIR=/dev/tmp
BOOTTMP=$TMPDIR/boottmp
MAGISKBIN=/data/magisk
CHROMEDIR=$MAGISKBIN/chromeos
SYSTEMLIB=/system/lib
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64
# Default permissions
umask 022
ui_print_wrapper() {
type ui_print >/dev/null && ui_print "$1" || echo "$1"
}
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
}
find_boot_image() {
if [ -z "$BOOTIMAGE" ]; then
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
fi
if [ -z "$BOOTIMAGE" ]; then
FSTAB="/etc/recovery.fstab"
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
[ -f "$FSTAB" ] && BOOTIMAGE=`grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*'`
fi
}
# Environments
# Set permissions
chmod -R 755 $CHROMEDIR/futility $MAGISKBIN 2>/dev/null
# Temporary busybox for installation
mkdir -p $TMPDIR/busybox
$MAGISKBIN/busybox --install -s $TMPDIR/busybox
rm -f $TMPDIR/busybox/su $TMPDIR/busybox/sh $TMPDIR/busybox/reboot
PATH=$TMPDIR/busybox:$PATH
# Load utility functions
. $MAGISKBIN/util_functions.sh
# Find the boot image
find_boot_image
if [ -z "$BOOTIMAGE" ]; then
ui_print_wrapper "! Unable to detect boot image"
exit 1
fi
[ -z $BOOTIMAGE ] && abort "! Unable to detect boot image"
ui_print_wrapper "- Found Boot Image: $BOOTIMAGE"
ui_print_wrap "- Found Boot Image: $BOOTIMAGE"
rm -rf $BOOTTMP 2>/dev/null
mkdir -p $BOOTTMP
cd $BOOTTMP
cd $MAGISKBIN
ui_print_wrapper "- Unpacking boot image"
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --unpack $BOOTIMAGE
if [ $? -ne 0 ]; then
ui_print_wrapper "! Unable to unpack boot image"
exit 1
fi
ui_print_wrap "- Unpacking boot image"
./magiskboot --unpack "$BOOTIMAGE"
CHROMEOS=false
case $? in
1 )
abort_wrap "! Unable to unpack boot image"
;;
2 )
CHROMEOS=true
;;
3 )
ui_print_wrap "! Sony ELF32 format detected"
abort_wrap "! Please use BootBridge from @AdrianDC to flash Magisk"
;;
4 )
ui_print_wrap "! Sony ELF64 format detected"
abort_wrap "! Stock kernel cannot be patched, please use a custom kernel"
esac
# Update our previous backup to new format if exists
if [ -f /data/stock_boot.img ]; then
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --sha1 /data/stock_boot.img | tail -n 1`
SHA1=`./magiskboot --sha1 /data/stock_boot.img | tail -n 1`
STOCKDUMP=/data/stock_boot_${SHA1}.img
mv /data/stock_boot.img $STOCKDUMP
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --compress $STOCKDUMP
./magiskboot --compress $STOCKDUMP
fi
# Detect boot image state
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-test ramdisk.cpio
./magiskboot --cpio-test ramdisk.cpio
case $? in
0 )
ui_print_wrapper "! Magisk is not installed!"
ui_print_wrapper "! Nothing to uninstall"
0 ) # Stock boot
ui_print_wrap "- Stock boot image detected!"
ui_print_wrap "! Magisk is not installed!"
exit
;;
1 )
1 ) # Magisk patched
ui_print_wrap "- Magisk patched image detected!"
# Find SHA1 of stock boot image
if [ -z $SHA1 ]; then
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc`
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
rm -f init.magisk.rc
./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_wrapper "- Boot image backup found!"
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
ui_print_wrap "- Boot image backup found!"
./magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
else
ui_print_wrapper "! Boot image backup unavailable"
ui_print_wrapper "- Restoring ramdisk with backup"
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
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 )
ui_print_wrapper "- SuperSU patched image detected"
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
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 > config
echo > bootloader
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 config --arch arm --bootloader bootloader --flags 0x1
rm -f stock_boot.img
if $CHROMEOS; then
echo > empty
./chromeos/futility vbutil_kernel --pack stock_boot.img.signed \
--keyblock ./chromeos/kernel.keyblock --signprivate ./chromeos/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_wrapper "- Flashing stock/reverted image"
[ ! -L "$BOOTIMAGE" ] && dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
dd if=stock_boot.img of=$BOOTIMAGE bs=4096
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_wrapper "- Removing Magisk files"
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/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null
/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 /data/property/*magisk* \
/data/app/com.topjohnwu.magisk* /data/user/*/com.topjohnwu.magisk 2>/dev/null
$BOOTMODE && reboot

View File

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

View File

@@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
@@ -13,13 +12,11 @@ import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import com.topjohnwu.magisk.components.AboutCardRow;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.utils.Logger;
import java.io.IOException;
import java.io.InputStream;
@@ -29,7 +26,7 @@ import butterknife.ButterKnife;
public class AboutActivity extends Activity {
private static final String DONATION_URL = "http://topjohnwu.github.io/donate";
private static final String DONATION_URL = "https://www.paypal.me/topjohnwu";
private static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
private static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/MagiskManager";
@@ -45,10 +42,8 @@ public class AboutActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String theme = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("theme", "");
Logger.dev("AboutActivity: Theme is " + theme);
if (getApplicationContext().isDarkTheme) {
setTheme(R.style.AppTheme_Dark);
setTheme(R.style.AppTheme_Transparent_Dark);
}
setContentView(R.layout.activity_about);
ButterKnife.bind(this);
@@ -135,18 +130,4 @@ public class AboutActivity extends Activity {
setFloating();
}
public void setFloating() {
boolean isTablet = getResources().getBoolean(R.bool.isTablet);
if (isTablet) {
WindowManager.LayoutParams params = getWindow().getAttributes();
params.height = getResources().getDimensionPixelSize(R.dimen.floating_height);
params.width = getResources().getDimensionPixelSize(R.dimen.floating_width);
params.alpha = 1.0f;
params.dimAmount = 0.6f;
params.flags |= 2;
getWindow().setAttributes(params);
setFinishOnTouchOutside(true);
}
}
}

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

View File

@@ -1,228 +0,0 @@
package com.topjohnwu.magisk;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.TextView;
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.Utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
public class InstallFragment extends Fragment implements CallbackEvent.Listener<Void> {
private static final String UNINSTALLER = "magisk_uninstaller.sh";
@BindView(R.id.current_version_title) TextView currentVersionTitle;
@BindView(R.id.install_title) TextView installTitle;
@BindView(R.id.block_spinner) Spinner spinner;
@BindView(R.id.detect_bootimage) Button detectButton;
@BindView(R.id.install_button) CardView installButton;
@BindView(R.id.install_text) TextView installText;
@BindView(R.id.uninstall_button) CardView uninstallButton;
@BindView(R.id.keep_force_enc) CheckBox keepEncChkbox;
@BindView(R.id.keep_verity) CheckBox keepVerityChkbox;
@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 (magiskManager.bootBlock != null) {
if (idx > 0) {
bootImage = magiskManager.blockList.get(idx - 1);
}
} else {
if (idx > 0) {
bootImage = magiskManager.blockList.get(idx - 1);
} else {
SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG);
}
}
}
final String finalBootImage = bootImage;
String filename = "Magisk-v" + magiskManager.remoteMagiskVersion + ".zip";
new AlertDialogBuilder(getActivity())
.setTitle(getString(R.string.repo_install_title, getString(R.string.magisk)))
.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();
@Override
public void onDownloadDone(Uri uri) {
new ProcessMagiskZip(getActivity(), uri, boot, enc, verity).exec();
}
},
magiskManager.magiskLink,
Utils.getLegalFilename(filename)))
.setNeutralButton(R.string.release_notes, (dialog, which) -> {
if (magiskManager.releaseNoteLink != null) {
Intent openReleaseNoteLink = new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink));
openReleaseNoteLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
magiskManager.startActivity(openReleaseNoteLink);
}
})
.setNegativeButton(R.string.no_thanks, null)
.show();
}
@OnClick(R.id.uninstall_button)
public void uninstall() {
new AlertDialogBuilder(getActivity())
.setTitle(R.string.uninstall_magisk_title)
.setMessage(R.string.uninstall_magisk_msg)
.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
try {
InputStream in = magiskManager.getAssets().open(UNINSTALLER);
File uninstaller = new File(magiskManager.getCacheDir(), UNINSTALLER);
FileOutputStream out = new FileOutputStream(uninstaller);
byte[] bytes = new byte[1024];
int read;
while ((read = in.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
in.close();
out.close();
ProgressDialog progress = new ProgressDialog(getActivity());
progress.setTitle(R.string.reboot);
progress.show();
new CountDownTimer(5000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
progress.setMessage(getString(R.string.reboot_countdown, millisUntilFinished / 1000));
}
@Override
public void onFinish() {
progress.setMessage(getString(R.string.reboot_countdown, 0));
Shell.su(true, "mv -f " + uninstaller + " /cache/" + UNINSTALLER,
"reboot");
}
}.start();
} catch (IOException e) {
e.printStackTrace();
}
})
.setNegativeButton(R.string.no_thanks, null)
.show();
}
private Unbinder unbinder;
private MagiskManager magiskManager;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_install, container, false);
unbinder = ButterKnife.bind(this, v);
magiskManager = getApplication();
if (magiskManager.magiskVersion < 0) {
currentVersionTitle.setText(getString(R.string.current_magisk_title, getString(R.string.version_none)));
} else {
currentVersionTitle.setText(getString(R.string.current_magisk_title, "v" + magiskManager.magiskVersionString));
}
installTitle.setText(getString(R.string.install_magisk_title, "v" + String.format(Locale.US, "%.1f", magiskManager.remoteMagiskVersion)));
updateUI();
return v;
}
@Override
public void onTrigger(CallbackEvent<Void> event) {
updateUI();
}
private void updateUI() {
if (magiskManager.blockList == null || !Shell.rootAccess()) {
uninstallButton.setVisibility(View.GONE);
installText.setText(R.string.download);
detectButton.setEnabled(false);
keepEncChkbox.setEnabled(false);
keepVerityChkbox.setEnabled(false);
spinner.setEnabled(false);
} else {
uninstallButton.setVisibility(magiskManager.magiskVersion > 10.3 ? View.VISIBLE : View.GONE);
installText.setText(R.string.download_install);
detectButton.setEnabled(true);
keepEncChkbox.setEnabled(true);
keepVerityChkbox.setEnabled(true);
spinner.setEnabled(true);
List<String> items = new ArrayList<>();
if (magiskManager.bootBlock != null) {
items.add(getString(R.string.auto_detect, magiskManager.bootBlock));
} 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();
}
}
@Override
public void onStart() {
super.onStart();
getActivity().setTitle(R.string.install);
magiskManager.blockDetectionDone.register(this);
}
@Override
public void onStop() {
magiskManager.blockDetectionDone.unRegister(this);
super.onStop();
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}

View File

@@ -31,14 +31,14 @@ public class LogFragment extends Fragment {
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
if (getApplication().isSuClient) {
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
tab.setupWithViewPager(viewPager);
tab.setVisibility(View.VISIBLE);
}
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
viewPager.setAdapter(adapter);
return v;

View File

@@ -0,0 +1,505 @@
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;
import android.os.CountDownTimer;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
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.Utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindColor;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
public class MagiskFragment extends Fragment
implements CallbackEvent.Listener<Void>, SwipeRefreshLayout.OnRefreshListener {
public static final String SHOW_DIALOG = "dialog";
private static int expandHeight = 0;
private static boolean mExpanded = false;
private MagiskManager magiskManager;
private Unbinder unbinder;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.magisk_update_card) CardView magiskUpdateCard;
@BindView(R.id.magisk_update_icon) ImageView magiskUpdateIcon;
@BindView(R.id.magisk_update_status) TextView magiskUpdateText;
@BindView(R.id.magisk_update_progress) ProgressBar magiskUpdateProgress;
@BindView(R.id.magisk_status_icon) ImageView magiskStatusIcon;
@BindView(R.id.magisk_version) TextView magiskVersionText;
@BindView(R.id.root_status_icon) ImageView rootStatusIcon;
@BindView(R.id.root_status) TextView rootStatusText;
@BindView(R.id.safetyNet_card) CardView safetyNetCard;
@BindView(R.id.safetyNet_refresh) ImageView safetyNetRefreshIcon;
@BindView(R.id.safetyNet_status) TextView safetyNetStatusText;
@BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress;
@BindView(R.id.expand_layout) LinearLayout expandLayout;
@BindView(R.id.cts_status_icon) ImageView ctsStatusIcon;
@BindView(R.id.cts_status) TextView ctsStatusText;
@BindView(R.id.basic_status_icon) ImageView basicStatusIcon;
@BindView(R.id.basic_status) TextView basicStatusText;
@BindView(R.id.bootimage_card) CardView bootImageCard;
@BindView(R.id.block_spinner) Spinner spinner;
@BindView(R.id.detect_bootimage) Button detectButton;
@BindView(R.id.install_option_card) CardView installOptionCard;
@BindView(R.id.keep_force_enc) CheckBox keepEncChkbox;
@BindView(R.id.keep_verity) CheckBox keepVerityChkbox;
@BindView(R.id.install_button) CardView installButton;
@BindView(R.id.install_text) TextView installText;
@BindView(R.id.uninstall_button) CardView uninstallButton;
@BindColor(R.color.red500) int colorBad;
@BindColor(R.color.green500) int colorOK;
@BindColor(R.color.yellow500) int colorWarn;
@BindColor(R.color.grey500) int colorNeutral;
@BindColor(R.color.blue500) int colorInfo;
@OnClick(R.id.safetyNet_title)
public void safetyNet() {
safetyNetProgress.setVisibility(View.VISIBLE);
safetyNetRefreshIcon.setVisibility(View.GONE);
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
Utils.checkSafetyNet(getActivity());
collapse();
}
@OnClick(R.id.install_button)
public void install() {
String bootImage = null;
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).show();
return;
}
}
}
final String finalBootImage = bootImage;
String filename = "Magisk-v" + magiskManager.remoteMagiskVersionString + ".zip";
new AlertDialogBuilder(getActivity())
.setTitle(getString(R.string.repo_install_title, getString(R.string.magisk)))
.setMessage(getString(R.string.repo_install_msg, filename))
.setCancelable(true)
.setPositiveButton(Shell.rootAccess() ? R.string.install : R.string.download,
(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) {
if (Shell.rootAccess()) {
magiskManager.shell.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, (d, i) -> {
if (magiskManager.releaseNoteLink != null) {
Intent openReleaseNoteLink = new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink));
openReleaseNoteLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
magiskManager.startActivity(openReleaseNoteLink);
}
})
.setNegativeButton(R.string.no_thanks, null)
.show();
}
@OnClick(R.id.uninstall_button)
public void uninstall() {
new AlertDialogBuilder(getActivity())
.setTitle(R.string.uninstall_magisk_title)
.setMessage(R.string.uninstall_magisk_msg)
.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
try {
InputStream in = magiskManager.getAssets().open(MagiskManager.UNINSTALLER);
File uninstaller = new File(magiskManager.getCacheDir(), MagiskManager.UNINSTALLER);
FileOutputStream out = new FileOutputStream(uninstaller);
byte[] bytes = new byte[1024];
int read;
while ((read = in.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
in.close();
out.close();
in = magiskManager.getAssets().open(MagiskManager.UTIL_FUNCTIONS);
File utils = new File(magiskManager.getCacheDir(), MagiskManager.UTIL_FUNCTIONS);
out = new FileOutputStream(utils);
while ((read = in.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
in.close();
out.close();
ProgressDialog progress = new ProgressDialog(getActivity());
progress.setTitle(R.string.reboot);
progress.show();
new CountDownTimer(5000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
progress.setMessage(getString(R.string.reboot_countdown, millisUntilFinished / 1000));
}
@Override
public void onFinish() {
progress.setMessage(getString(R.string.reboot_countdown, 0));
magiskManager.shell.su_raw(
"mv -f " + uninstaller + " /cache/" + MagiskManager.UNINSTALLER,
"mv -f " + utils + " /data/magisk/" + MagiskManager.UTIL_FUNCTIONS,
"reboot"
);
}
}.start();
} catch (IOException e) {
e.printStackTrace();
}
})
.setNegativeButton(R.string.no_thanks, null)
.show();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_magisk, container, false);
unbinder = ButterKnife.bind(this, v);
magiskManager = getApplication();
expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (expandHeight == 0) {
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
expandLayout.measure(widthSpec, heightSpec);
expandHeight = expandLayout.getMeasuredHeight();
}
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
setExpanded();
return true;
}
});
mSwipeRefreshLayout.setOnRefreshListener(this);
updateUI();
if (getArguments() != null && getArguments().getBoolean(SHOW_DIALOG))
install();
return v;
}
@Override
public void onRefresh() {
updateUI();
magiskUpdateText.setText(R.string.checking_for_updates);
magiskUpdateProgress.setVisibility(View.VISIBLE);
magiskUpdateIcon.setVisibility(View.GONE);
safetyNetStatusText.setText(R.string.safetyNet_check_text);
magiskManager.safetyNetDone.isTriggered = false;
magiskManager.updateCheckDone.isTriggered = false;
magiskManager.remoteMagiskVersionString = null;
magiskManager.remoteMagiskVersionCode = -1;
collapse();
// Trigger state check
if (Utils.checkNetworkStatus(magiskManager)) {
new CheckUpdates(getActivity()).exec();
} else {
mSwipeRefreshLayout.setRefreshing(false);
}
}
@Override
public void onTrigger(CallbackEvent<Void> event) {
if (event == magiskManager.updateCheckDone) {
updateCheckUI();
} else if (event == magiskManager.safetyNetDone) {
updateSafetyNetUI();
}
}
@Override
public void onStart() {
super.onStart();
// Manual trigger if already done
if (magiskManager.updateCheckDone.isTriggered)
updateCheckUI();
if (magiskManager.safetyNetDone.isTriggered)
updateSafetyNetUI();
magiskManager.updateCheckDone.register(this);
magiskManager.safetyNetDone.register(this);
getActivity().setTitle(R.string.magisk);
}
@Override
public void onStop() {
magiskManager.updateCheckDone.unRegister(this);
magiskManager.safetyNetDone.unRegister(this);
super.onStop();
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
private void updateUI() {
((MainActivity) getActivity()).checkHideSection();
magiskManager.updateMagiskInfo();
final int ROOT = 0x1, NETWORK = 0x2, UPTODATE = 0x4;
int status = 0;
status |= Shell.rootAccess() ? ROOT : 0;
status |= Utils.checkNetworkStatus(magiskManager) ? NETWORK : 0;
status |= magiskManager.magiskVersionCode >= 130 ? UPTODATE : 0;
magiskUpdateCard.setVisibility(Utils.checkBits(status, NETWORK) ? View.VISIBLE : View.GONE);
safetyNetCard.setVisibility(Utils.checkBits(status, NETWORK) ? View.VISIBLE : View.GONE);
bootImageCard.setVisibility(Utils.checkBits(status, NETWORK, ROOT) ? View.VISIBLE : View.GONE);
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);
int image, color;
if (magiskManager.magiskVersionCode < 0) {
color = colorBad;
image = R.drawable.ic_cancel;
magiskVersionText.setText(R.string.magisk_version_error);
} else {
color = colorOK;
image = R.drawable.ic_check_circle;
magiskVersionText.setText(getString(R.string.current_magisk_title, "v" + magiskManager.magiskVersionString));
}
magiskStatusIcon.setImageResource(image);
magiskStatusIcon.setColorFilter(color);
switch (Shell.rootStatus) {
case 0:
color = colorBad;
image = R.drawable.ic_cancel;
rootStatusText.setText(R.string.not_rooted);
break;
case 1:
if (magiskManager.suVersion != null) {
color = colorOK;
image = R.drawable.ic_check_circle;
rootStatusText.setText(magiskManager.suVersion);
break;
}
case -1:
default:
color = colorNeutral;
image = R.drawable.ic_help;
rootStatusText.setText(R.string.root_error);
}
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() {
int image, color;
if (magiskManager.remoteMagiskVersionCode < 0) {
color = colorNeutral;
image = R.drawable.ic_help;
magiskUpdateText.setText(R.string.cannot_check_updates);
} else {
color = colorOK;
image = R.drawable.ic_check_circle;
magiskUpdateText.setText(getString(R.string.install_magisk_title, "v" + magiskManager.remoteMagiskVersionString));
}
magiskUpdateIcon.setImageResource(image);
magiskUpdateIcon.setColorFilter(color);
magiskUpdateIcon.setVisibility(View.VISIBLE);
magiskUpdateProgress.setVisibility(View.GONE);
mSwipeRefreshLayout.setRefreshing(false);
if (magiskManager.remoteMagiskVersionCode > magiskManager.magiskVersionCode)
install();
}
private void updateSafetyNetUI() {
int image, color;
safetyNetProgress.setVisibility(View.GONE);
safetyNetRefreshIcon.setVisibility(View.VISIBLE);
if (magiskManager.SNCheckResult.failed) {
safetyNetStatusText.setText(magiskManager.SNCheckResult.errmsg);
collapse();
} else {
safetyNetStatusText.setText(R.string.safetyNet_check_success);
if (magiskManager.SNCheckResult.ctsProfile) {
color = colorOK;
image = R.drawable.ic_check_circle;
} else {
color = colorBad;
image = R.drawable.ic_cancel;
}
ctsStatusText.setText("ctsProfile: " + magiskManager.SNCheckResult.ctsProfile);
ctsStatusIcon.setImageResource(image);
ctsStatusIcon.setColorFilter(color);
if (magiskManager.SNCheckResult.basicIntegrity) {
color = colorOK;
image = R.drawable.ic_check_circle;
} else {
color = colorBad;
image = R.drawable.ic_cancel;
}
basicStatusText.setText("basicIntegrity: " + magiskManager.SNCheckResult.basicIntegrity);
basicStatusIcon.setImageResource(image);
basicStatusIcon.setColorFilter(color);
expand();
}
}
private void setExpanded() {
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = mExpanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
expandLayout.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
}
private void expand() {
if (mExpanded) return;
expandLayout.setVisibility(View.VISIBLE);
ValueAnimator mAnimator = slideAnimator(0, expandHeight);
mAnimator.start();
mExpanded = true;
}
private void collapse() {
if (!mExpanded) return;
int finalHeight = expandLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationEnd(Animator animator) {
expandLayout.setVisibility(View.GONE);
}
@Override
public void onAnimationStart(Animator animator) {}
@Override
public void onAnimationCancel(Animator animator) {}
@Override
public void onAnimationRepeat(Animator animator) {}
});
mAnimator.start();
mExpanded = false;
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
}
}

View File

@@ -1,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.SerialTask;
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 {
}
}
public class LogManager extends SerialTask<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 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();
magiskManager.shell.su(logList, "cat " + MAGISK_LOG);
return logList.toString();
case 1:
Shell.su("echo > " + MAGISK_LOG);
magiskManager.shell.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;
FileWritingList fileWritingList = new FileWritingList(out);
magiskManager.shell.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;
}
}
}

View File

@@ -1,17 +1,22 @@
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.os.Build;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.SparseArray;
import android.text.TextUtils;
import android.widget.Toast;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.SafetyNetHelper;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ValueSortedMap;
@@ -22,33 +27,41 @@ import java.util.List;
public class MagiskManager extends Application {
public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk";
public static final String MAGISK_HIDE_PATH = "/magisk/.core/magiskhide/";
public static final String TMP_FOLDER_PATH = "/dev/tmp";
public static final String MAGISK_PATH = "/magisk";
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 INTENT_VERSION = "version";
public static final String INTENT_LINK = "link";
public static final String BUSYBOX_VERSION = "1.26.2";
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";
// 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<>();
public final SparseArray<CallbackEvent<Policy>> uidSuRequest = new SparseArray<>();
// Info
public double magiskVersion;
public String magiskVersionString;
public double remoteMagiskVersion = -1;
public int magiskVersionCode = -1;
public String remoteMagiskVersionString;
public int remoteMagiskVersionCode = -1;
public String magiskLink;
public String releaseNoteLink;
public int SNCheckResult = -1;
public String remoteManagerVersionString;
public int remoteManagerVersionCode = -1;
public String managerLink;
public SafetyNetHelper.Result SNCheckResult;
public String bootBlock = null;
public boolean isSuClient = false;
public String suVersion = null;
public boolean disabled;
public boolean magiskHideStarted;
// Data
public ValueSortedMap<String, Repo> repoMap;
@@ -64,21 +77,28 @@ public class MagiskManager extends Application {
public boolean magiskHide;
public boolean isDarkTheme;
public boolean updateNotification;
public boolean busybox;
public boolean suReauth;
public int suRequestTimeout;
public int suLogTimeout = 14;
public int suAccessState;
public int multiuserMode;
public int suResponseType;
public int suNotificationType;
public int suNamespaceMode;
// Global resources
public SharedPreferences prefs;
public SuDatabaseHelper suDB;
public Shell shell;
private static Handler mHandler = new Handler();
@Override
public void onCreate() {
super.onCreate();
new File(getApplicationInfo().dataDir).mkdirs(); /* Create the app data directory */
prefs = PreferenceManager.getDefaultSharedPreferences(this);
shell = Shell.getShell();
}
public void toast(String msg, int duration) {
@@ -91,89 +111,125 @@ 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);
magiskHide = prefs.getBoolean("magiskhide", false);
updateNotification = prefs.getBoolean("notification", true);
// Always start a new root shell manually, just for safety
Shell.init();
} else {
devLogging = false;
shellLogging = false;
}
magiskHide = prefs.getBoolean("magiskhide", true);
initSU();
updateMagiskInfo();
initSuAccess();
initSuConfigs();
updateBlockInfo();
// 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_raw(
"cp -f " + new File(getApplicationInfo().nativeLibraryDir, "libbusybox.so") + " " + busybox,
"chmod -R 755 " + busybox.getParent(),
busybox + " --install -s " + busybox.getParent()
);
}
// Initialize prefs
prefs.edit()
.putBoolean("dark_theme", isDarkTheme)
.putBoolean("magiskhide", magiskHide)
.putBoolean("notification", updateNotification)
.putBoolean("busybox", busybox)
.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))
.putString("su_notification", String.valueOf(suNotificationType))
.putString("su_access", String.valueOf(suAccessState))
.putString("multiuser_mode", String.valueOf(multiuserMode))
.putString("mnt_ns", String.valueOf(suNamespaceMode))
.putString("busybox_version", BUSYBOX_VERSION)
.apply();
// Add busybox to PATH
shell.su_raw("PATH=$PATH:" + busybox.getParent());
// 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 initSuConfigs() {
}
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 initSuAccess() {
List<String> ret = Shell.sh("su -v");
public void initSU() {
initSUConfig();
List<String> ret = shell.sh("su -v");
if (Utils.isValidShellResponse(ret)) {
suVersion = ret.get(0);
isSuClient = suVersion.toUpperCase().contains("MAGISK");
}
if (isSuClient) {
ret = Shell.sh("getprop persist.sys.root_access");
if (Utils.isValidShellResponse(ret)) {
suAccessState = Integer.parseInt(ret.get(0));
} else {
Shell.su(true, "setprop persist.sys.root_access 3");
suAccessState = 3;
}
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 = Shell.sh("getprop magisk.version");
updateNotification = prefs.getBoolean("notification", true);
List<String> ret;
ret = shell.sh("magisk -v");
if (!Utils.isValidShellResponse(ret)) {
magiskVersion = -1;
} else {
ret = shell.sh("getprop magisk.version");
if (Utils.isValidShellResponse(ret)) {
try {
magiskVersionString = ret.get(0);
magiskVersion = Double.parseDouble(ret.get(0));
} catch (NumberFormatException e) {
// Custom version don't need to receive updates
magiskVersion = Double.POSITIVE_INFINITY;
magiskVersionCode = (int) Double.parseDouble(ret.get(0)) * 10;
} catch (NumberFormatException ignored) {}
}
}
ret = Shell.sh("getprop persist.magisk.busybox");
} else {
magiskVersionString = ret.get(0).split(":")[0];
ret = shell.sh("magisk -V");
try {
busybox = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) {
busybox = false;
magiskVersionCode = Integer.parseInt(ret.get(0));
} catch (NumberFormatException ignored) {}
}
ret = Shell.sh("getprop ro.magisk.disable");
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 persist.magisk.hide");
ret = shell.sh("getprop " + MAGISKHIDE_PROP);
try {
magiskHideStarted = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
magiskHide = !Utils.isValidShellResponse(ret) || Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) {
magiskHideStarted = false;
}
if (magiskHideStarted) {
magiskHide = true;
}
}
public void updateBlockInfo() {
List<String> res = shell.su(
"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",
"[ ! -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");
}
}
}

View File

@@ -22,6 +22,7 @@ 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.Utils;
import butterknife.BindView;
import butterknife.ButterKnife;
@@ -81,7 +82,6 @@ public class MainActivity extends Activity
navigationView.setNavigationItemSelectedListener(this);
getApplicationContext().reloadMainActivity.register(this);
getApplicationContext().updateCheckDone.register(this);
}
@@ -91,32 +91,22 @@ public class MainActivity extends Activity
checkHideSection();
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
navigate(savedInstanceState.getInt(MagiskManager.INTENT_SECTION, R.id.status));
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(MagiskManager.INTENT_SECTION, mDrawerItem);
}
@Override
protected void onDestroy() {
getApplicationContext().reloadMainActivity.unRegister(this);
getApplicationContext().updateCheckDone.unRegister(this);
super.onDestroy();
}
@Override
public void onBackPressed() {
if (drawer.isDrawerOpen(navigationView))
if (drawer.isDrawerOpen(navigationView)) {
drawer.closeDrawer(navigationView);
else
} else if (mDrawerItem != R.id.magisk) {
navigate(R.id.magisk);
} else {
finish();
}
}
@Override
public boolean onNavigationItemSelected(@NonNull final MenuItem menuItem) {
@@ -128,37 +118,32 @@ public class MainActivity extends Activity
@Override
public void onTrigger(CallbackEvent<Void> event) {
if (event == getApplicationContext().reloadMainActivity) {
recreate();
} else if (event == getApplicationContext().updateCheckDone) {
checkHideSection();
}
}
private void checkHideSection() {
public void checkHideSection() {
Menu menu = navigationView.getMenu();
menu.findItem(R.id.magiskhide).setVisible(
Shell.rootAccess() && getApplicationContext().magiskVersion >= 8
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 1300
&& prefs.getBoolean("magiskhide", false));
menu.findItem(R.id.modules).setVisible(
Shell.rootAccess() && getApplicationContext().magiskVersion >= 4);
menu.findItem(R.id.downloads).setVisible(
Shell.rootAccess() && getApplicationContext().magiskVersion >= 4);
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 0);
menu.findItem(R.id.downloads).setVisible(Utils.checkNetworkStatus(this) &&
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 0);
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
menu.findItem(R.id.superuser).setVisible(
Shell.rootAccess() && getApplicationContext().isSuClient);
menu.findItem(R.id.install).setVisible(getApplicationContext().remoteMagiskVersion > 0);
}
public void navigate(String item) {
int itemId = R.id.status;
int itemId = R.id.magisk;
if (item != null) {
switch (item) {
case "status":
itemId = R.id.status;
case "magisk":
itemId = R.id.magisk;
break;
case "install":
itemId = R.id.install;
itemId = -1;
break;
case "superuser":
itemId = R.id.superuser;
@@ -191,11 +176,15 @@ public class MainActivity extends Activity
mDrawerItem = itemId;
navigationView.setCheckedItem(itemId);
switch (itemId) {
case R.id.status:
displayFragment(new StatusFragment(), "status", true);
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.install:
displayFragment(new InstallFragment(), "install", true);
case R.id.magisk:
displayFragment(new MagiskFragment(), "magisk", true);
break;
case R.id.superuser:
displayFragment(new SuperuserFragment(), "superuser", true);

View File

@@ -2,9 +2,9 @@ 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;
@@ -12,9 +12,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.github.clans.fab.FloatingActionButton;
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;
@@ -86,8 +84,9 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener<
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);
}
}

View File

@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -14,18 +13,11 @@ 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.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 butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
@@ -37,16 +29,7 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
@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,10 +43,9 @@ 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));
adapter = new ReposAdapter(getApplication().repoMap);
recyclerView.setAdapter(mSectionedAdapter);
recyclerView.setAdapter(adapter);
mSwipeRefreshLayout.setRefreshing(true);
@@ -73,38 +55,42 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
});
if (getApplication().repoLoadDone.isTriggered) {
reloadRepos();
updateUI();
onTrigger(null);
}
searchListener = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
new FilterApps().exec(newText);
return false;
}
};
return view;
}
@Override
public void onTrigger(CallbackEvent<Void> event) {
Logger.dev("ReposFragment: UI refresh triggered");
reloadRepos();
updateUI();
if (getApplication().repoMap.isEmpty()) {
recyclerView.setVisibility(View.GONE);
emptyRv.setVisibility(View.VISIBLE);
} else {
adapter.filter(getApplication().moduleMap, "");
recyclerView.setVisibility(View.VISIBLE);
emptyRv.setVisibility(View.GONE);
mSwipeRefreshLayout.setRefreshing(false);
}
}
@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);
SearchView search = (SearchView) menu.findItem(R.id.repo_search).getActionView();
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.filter(getApplication().moduleMap, newText);
return false;
}
});
}
@Override
@@ -125,92 +111,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();
}
}
}

View File

@@ -1,6 +1,7 @@
package com.topjohnwu.magisk;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.PreferenceCategory;
@@ -10,13 +11,12 @@ import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.view.WindowManager;
import android.widget.Toast;
import com.topjohnwu.magisk.asyncs.MagiskHide;
import com.topjohnwu.magisk.asyncs.SerialTask;
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.Utils;
@@ -32,10 +32,10 @@ public class SettingsActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getApplicationContext().isDarkTheme) {
setTheme(R.style.AppTheme_Dark);
setTheme(R.style.AppTheme_Transparent_Dark);
}
setContentView(R.layout.activity_container);
setContentView(R.layout.activity_settings);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
@@ -56,31 +56,14 @@ public class SettingsActivity extends Activity {
}
public void setFloating() {
boolean isTablet = getResources().getBoolean(R.bool.isTablet);
if (isTablet) {
WindowManager.LayoutParams params = getWindow().getAttributes();
params.height = getResources().getDimensionPixelSize(R.dimen.floating_height);
params.width = getResources().getDimensionPixelSize(R.dimen.floating_width);
params.alpha = 1.0f;
params.dimAmount = 0.6f;
params.flags |= 2;
getWindow().setAttributes(params);
setFinishOnTouchOutside(true);
}
}
public static class SettingsFragment extends PreferenceFragment
implements SharedPreferences.OnSharedPreferenceChangeListener {
private SharedPreferences prefs;
private PreferenceScreen prefScreen;
private ListPreference suAccess, autoRes, suNotification, requestTimeout;
private MagiskManager getApplication() {
return Utils.getMagiskManager(getActivity());
}
private ListPreference suAccess, autoRes, suNotification, requestTimeout, multiuserMode, namespaceMode;
private MagiskManager magiskManager;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -88,30 +71,50 @@ public class SettingsActivity extends Activity {
addPreferencesFromResource(R.xml.app_settings);
prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
prefScreen = getPreferenceScreen();
magiskManager = Utils.getMagiskManager(getActivity());
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
PreferenceCategory developer = (PreferenceCategory) findPreference("developer");
suAccess = (ListPreference) findPreference("su_access");
autoRes = (ListPreference) findPreference("su_auto_response");
requestTimeout = (ListPreference) findPreference("su_request_timeout");
suNotification = (ListPreference) findPreference("su_notification");
multiuserMode = (ListPreference) findPreference("multiuser_mode");
namespaceMode = (ListPreference) findPreference("mnt_ns");
SwitchPreference reauth = (SwitchPreference) findPreference("su_reauth");
setSummary();
// Disable dangerous settings in user mode if selected owner manage
if (getActivity().getApplicationInfo().uid > 99999) {
prefScreen.removePreference(magiskCategory);
prefScreen.removePreference(suCategory);
}
// Remove re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
suCategory.removePreference(reauth);
}
findPreference("clear").setOnPreferenceClickListener((pref) -> {
Utils.clearRepoCache(getActivity());
return true;
});
if (!BuildConfig.DEBUG) {
prefScreen.removePreference(developer);
}
if (!Shell.rootAccess()) {
prefScreen.removePreference(magiskCategory);
prefScreen.removePreference(suCategory);
} else {
if (!getApplication().isSuClient) {
if (!magiskManager.isSuClient) {
prefScreen.removePreference(suCategory);
}
if (getApplication().magiskVersion < 11) {
if (magiskManager.magiskVersionCode < 1300) {
prefScreen.removePreference(magiskCategory);
}
}
@@ -137,93 +140,70 @@ public class SettingsActivity extends Activity {
switch (key) {
case "dark_theme":
enabled = prefs.getBoolean("dark_theme", false);
if (getApplication().isDarkTheme != enabled) {
getApplication().isDarkTheme = enabled;
getApplication().reloadMainActivity.trigger();
if (magiskManager.isDarkTheme != enabled) {
magiskManager.isDarkTheme = enabled;
magiskManager.reloadMainActivity.trigger();
getActivity().recreate();
}
break;
case "disable":
enabled = prefs.getBoolean("disable", false);
new SerialTask<Void, Void, Void>() {
private boolean enable = enabled;
@Override
protected Void doInBackground(Void... voids) {
if (enable) {
Utils.createFile(MagiskManager.MAGISK_DISABLE_FILE);
if (enabled) {
Utils.createFile(magiskManager.shell, MagiskManager.MAGISK_DISABLE_FILE);
} else {
Utils.removeItem(MagiskManager.MAGISK_DISABLE_FILE);
Utils.removeItem(magiskManager.shell, MagiskManager.MAGISK_DISABLE_FILE);
}
return null;
}
}.exec();
Toast.makeText(getActivity(), R.string.settings_reboot_toast, Toast.LENGTH_LONG).show();
break;
case "busybox":
enabled = prefs.getBoolean("busybox", false);
new SerialTask<Void, Void, Void>() {
private boolean enable = enabled;
@Override
protected Void doInBackground(Void... voids) {
if (enable) {
Shell.su(
"setprop persist.magisk.busybox 1",
"sh /sbin/magic_mask.sh mount_busybox");
} else {
Shell.su(
"setprop persist.magisk.busybox 0",
"umount /system/xbin");
}
return null;
}
}.exec();
break;
case "magiskhide":
enabled = prefs.getBoolean("magiskhide", false);
if (enabled) {
if (!getApplication().isSuClient) {
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())
.setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide(getActivity()).enable())
.setCancelable(false)
.show();
} else {
new MagiskHide().enable();
new MagiskHide(getActivity()).enable();
}
} else {
new MagiskHide().disable();
new MagiskHide(getActivity()).disable();
}
break;
case "hosts":
enabled = prefs.getBoolean("hosts", false);
new SerialTask<Void, Void, Void>() {
private boolean enable = enabled;
@Override
protected Void doInBackground(Void... voids) {
if (enable) {
Shell.su("cp -af /system/etc/hosts /magisk/.core/hosts",
if (enabled) {
magiskManager.shell.su_raw(
"cp -af /system/etc/hosts /magisk/.core/hosts",
"mount -o bind /magisk/.core/hosts /system/etc/hosts");
} else {
Shell.su("umount -l /system/etc/hosts",
magiskManager.shell.su_raw(
"umount -l /system/etc/hosts",
"rm -f /magisk/.core/hosts");
}
return null;
}
}.exec();
break;
case "su_access":
getApplication().suAccessState = Utils.getPrefsInt(prefs, "su_access", 0);
Shell.su("setprop persist.sys.root_access " + getApplication().suAccessState);
magiskManager.suAccessState = Utils.getPrefsInt(prefs, "su_access", 3);
magiskManager.suDB.setSettings(SuDatabaseHelper.ROOT_ACCESS, magiskManager.suAccessState);
break;
case "multiuser_mode":
magiskManager.multiuserMode = Utils.getPrefsInt(prefs, "multiuser_mode", 0);
magiskManager.suDB.setSettings(SuDatabaseHelper.MULTIUSER_MODE, magiskManager.multiuserMode);
break;
case "mnt_ns":
magiskManager.suNamespaceMode = Utils.getPrefsInt(prefs, "mnt_ns", 1);
magiskManager.suDB.setSettings(SuDatabaseHelper.MNT_NS, magiskManager.suNamespaceMode);
break;
case "su_request_timeout":
getApplication().suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
magiskManager.suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
break;
case "su_auto_response":
getApplication().suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
magiskManager.suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
break;
case "su_notification":
getApplication().suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
magiskManager.suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
break;
case "developer_logging":
MagiskManager.devLogging = prefs.getBoolean("developer_logging", false);
@@ -237,13 +217,17 @@ public class SettingsActivity extends Activity {
private void setSummary() {
suAccess.setSummary(getResources()
.getStringArray(R.array.su_access)[getApplication().suAccessState]);
.getStringArray(R.array.su_access)[magiskManager.suAccessState]);
autoRes.setSummary(getResources()
.getStringArray(R.array.auto_response)[getApplication().suResponseType]);
.getStringArray(R.array.auto_response)[magiskManager.suResponseType]);
suNotification.setSummary(getResources()
.getStringArray(R.array.su_notification)[getApplication().suNotificationType]);
.getStringArray(R.array.su_notification)[magiskManager.suNotificationType]);
requestTimeout.setSummary(
getString(R.string.request_timeout_summary, prefs.getString("su_request_timeout", "10")));
multiuserMode.setSummary(getResources()
.getStringArray(R.array.multiuser_summary)[magiskManager.multiuserMode]);
namespaceMode.setSummary(getResources()
.getStringArray(R.array.namespace_summary)[magiskManager.suNamespaceMode]);
}
}

View File

@@ -6,15 +6,14 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
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.MagiskHide;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.services.UpdateCheckService;
import com.topjohnwu.magisk.utils.Utils;
public class SplashActivity extends Activity{
@@ -27,47 +26,41 @@ public class SplashActivity extends Activity{
MagiskManager magiskManager = getApplicationContext();
// Init the info and configs and root shell
// Init the info and configs and root sh
magiskManager.init();
// Initialize the update check service, notify every 3 hours
if (!"install".equals(getIntent().getStringExtra(MagiskManager.INTENT_SECTION))) {
ComponentName service = new ComponentName(magiskManager, UpdateCheckService.class);
// 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
if (!TextUtils.equals("install", getIntent().getStringExtra(MagiskManager.INTENT_SECTION))) {
ComponentName service = new ComponentName(this, UpdateCheckService.class);
JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.setPeriodic(3 * 60 * 60 * 1000)
.setPeriodic(8 * 60 * 60 * 1000)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);
}
loadModuleTask.setCallBack(() -> new LoadRepos(this).exec());
}
// Now fire all async tasks
new GetBootBlocks(this).exec();
if (magiskManager.magiskHide && magiskManager.magiskVersion > 11 &&
!magiskManager.magiskHideStarted) {
new MagiskHide().enable();
}
new LoadModules(this) {
@Override
protected void onPostExecute(Void v) {
super.onPostExecute(v);
new LoadRepos(activity).exec();
}
}.exec();
loadModuleTask.exec();
new LoadApps(this).exec();
new CheckUpdates(this, false){
@Override
protected void onPostExecute(Void v) {
super.onPostExecute(v);
Intent intent = new Intent(this, MainActivity.class);
String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION);
Intent intent = new Intent(magiskManager, MainActivity.class);
if (section != null) {
intent.putExtra(MagiskManager.INTENT_SECTION, section);
}
startActivity(intent);
finish();
}
}.exec();
}
}

View File

@@ -1,264 +0,0 @@
package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import butterknife.BindColor;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
public class StatusFragment extends Fragment implements CallbackEvent.Listener<Void> {
private static boolean noDialog = false;
private Unbinder unbinder;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.magisk_status_container) View magiskStatusContainer;
@BindView(R.id.magisk_status_icon) ImageView magiskStatusIcon;
@BindView(R.id.magisk_version) TextView magiskVersionText;
@BindView(R.id.magisk_update_status) TextView magiskUpdateText;
@BindView(R.id.magisk_check_updates_progress) ProgressBar magiskCheckUpdatesProgress;
@BindView(R.id.root_status_container) View rootStatusContainer;
@BindView(R.id.root_status_icon) ImageView rootStatusIcon;
@BindView(R.id.root_status) TextView rootStatusText;
@BindView(R.id.root_info) TextView rootInfoText;
@BindView(R.id.safetyNet_container) View safetyNetContainer;
@BindView(R.id.safetyNet_icon) ImageView safetyNetIcon;
@BindView(R.id.safetyNet_status) TextView safetyNetStatusText;
@BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress;
@BindColor(R.color.red500) int colorBad;
@BindColor(R.color.green500) int colorOK;
@BindColor(R.color.yellow500) int colorWarn;
@BindColor(R.color.grey500) int colorNeutral;
@BindColor(R.color.blue500) int colorInfo;
@BindColor(android.R.color.transparent) int trans;
@OnClick(R.id.safetyNet_container)
public void safetyNet() {
safetyNetProgress.setVisibility(View.VISIBLE);
safetyNetContainer.setBackgroundColor(trans);
safetyNetIcon.setImageResource(0);
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
Utils.checkSafetyNet(getApplication());
}
@OnClick(R.id.magisk_status_container)
public void gotoInstall() {
if (getApplication().remoteMagiskVersion > 0) {
((MainActivity) getActivity()).navigate(R.id.install);
}
}
private int defaultColor;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_status, container, false);
unbinder = ButterKnife.bind(this, v);
defaultColor = magiskUpdateText.getCurrentTextColor();
mSwipeRefreshLayout.setOnRefreshListener(() -> {
magiskStatusContainer.setBackgroundColor(trans);
magiskStatusIcon.setImageResource(0);
magiskUpdateText.setText(R.string.checking_for_updates);
magiskCheckUpdatesProgress.setVisibility(View.VISIBLE);
magiskUpdateText.setTextColor(defaultColor);
safetyNetProgress.setVisibility(View.GONE);
safetyNetContainer.setBackgroundColor(colorNeutral);
safetyNetIcon.setImageResource(R.drawable.ic_safetynet);
safetyNetStatusText.setText(R.string.safetyNet_check_text);
safetyNetStatusText.setTextColor(defaultColor);
getApplication().safetyNetDone.isTriggered = false;
noDialog = false;
updateUI();
new CheckUpdates(getActivity()).exec();
});
if (getApplication().magiskVersion < 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) -> gotoInstall())
.setNegativeButton(R.string.no_thanks, null)
.show();
}
updateUI();
if (getApplication().updateCheckDone.isTriggered)
updateCheckUI();
if (getApplication().safetyNetDone.isTriggered)
updateSafetyNetUI();
return v;
}
@Override
public void onTrigger(CallbackEvent<Void> event) {
if (event == getApplication().updateCheckDone) {
Logger.dev("StatusFragment: Update Check UI refresh triggered");
updateCheckUI();
} else if (event == getApplication().safetyNetDone) {
Logger.dev("StatusFragment: SafetyNet UI refresh triggered");
updateSafetyNetUI();
}
}
@Override
public void onStart() {
super.onStart();
getApplication().updateCheckDone.register(this);
getApplication().safetyNetDone.register(this);
getActivity().setTitle(R.string.status);
}
@Override
public void onStop() {
getApplication().updateCheckDone.unRegister(this);
getApplication().safetyNetDone.unRegister(this);
super.onStop();
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
private void updateUI() {
int image, color;
getApplication().updateMagiskInfo();
if (getApplication().magiskVersion < 0) {
magiskVersionText.setText(R.string.magisk_version_error);
} else if (getApplication().disabled) {
magiskVersionText.setText(getString(R.string.magisk_version_core_only, getApplication().magiskVersionString));
} else {
magiskVersionText.setText(getString(R.string.magisk_version, getApplication().magiskVersionString));
}
switch (Shell.rootStatus) {
case 0:
color = colorBad;
image = R.drawable.ic_cancel;
rootStatusText.setText(R.string.not_rooted);
rootInfoText.setText(R.string.root_info_warning);
break;
case 1:
if (getApplication().suVersion != null) {
color = colorOK;
image = R.drawable.ic_check_circle;
rootStatusText.setText(R.string.proper_root);
rootInfoText.setText(getApplication().suVersion);
break;
}
case -1:
default:
color = colorNeutral;
image = R.drawable.ic_help;
rootStatusText.setText(R.string.root_error);
rootInfoText.setText(R.string.root_info_warning);
}
rootStatusContainer.setBackgroundColor(color);
rootStatusText.setTextColor(color);
rootInfoText.setTextColor(color);
rootStatusIcon.setImageResource(image);
}
private void updateCheckUI() {
int image, color;
if (getApplication().remoteMagiskVersion < 0) {
color = colorNeutral;
image = R.drawable.ic_help;
magiskUpdateText.setText(R.string.cannot_check_updates);
} else if (getApplication().remoteMagiskVersion > getApplication().magiskVersion) {
color = colorInfo;
image = R.drawable.ic_update;
magiskUpdateText.setText(getString(R.string.magisk_update_available, getApplication().remoteMagiskVersion));
} else {
color = colorOK;
image = R.drawable.ic_check_circle;
magiskUpdateText.setText(getString(R.string.up_to_date, getString(R.string.magisk)));
}
if (getApplication().magiskVersion < 0) {
color = colorBad;
image = R.drawable.ic_cancel;
}
magiskStatusContainer.setBackgroundColor(color);
magiskVersionText.setTextColor(color);
magiskUpdateText.setTextColor(color);
magiskStatusIcon.setImageResource(image);
magiskCheckUpdatesProgress.setVisibility(View.GONE);
mSwipeRefreshLayout.setRefreshing(false);
}
private void updateSafetyNetUI() {
int image, color;
safetyNetProgress.setVisibility(View.GONE);
switch (getApplication().SNCheckResult) {
case -3:
color = colorNeutral;
image = R.drawable.ic_help;
safetyNetStatusText.setText(R.string.safetyNet_connection_suspended);
break;
case -2:
color = colorNeutral;
image = R.drawable.ic_help;
safetyNetStatusText.setText(R.string.safetyNet_connection_failed);
break;
case -1:
color = colorNeutral;
image = R.drawable.ic_help;
safetyNetStatusText.setText(R.string.safetyNet_error);
break;
case 0:
color = colorBad;
image = R.drawable.ic_cancel;
safetyNetStatusText.setText(R.string.safetyNet_fail);
break;
case 1:
default:
color = colorOK;
image = R.drawable.ic_check_circle;
safetyNetStatusText.setText(R.string.safetyNet_pass);
break;
}
safetyNetContainer.setBackgroundColor(color);
safetyNetStatusText.setTextColor(color);
safetyNetIcon.setImageResource(image);
}
}

View File

@@ -13,7 +13,6 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.SuLogAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.database.SuLogDatabaseHelper;
import com.topjohnwu.magisk.superuser.SuLogEntry;
import java.util.List;
@@ -28,7 +27,7 @@ public class SuLogFragment extends Fragment {
@BindView(R.id.recyclerView) RecyclerView recyclerView;
private Unbinder unbinder;
private SuLogDatabaseHelper dbHelper;
private MagiskManager magiskManager;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -48,8 +47,7 @@ public class SuLogFragment extends Fragment {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
unbinder = ButterKnife.bind(this, v);
dbHelper = new SuLogDatabaseHelper(getActivity());
magiskManager = getApplication();
updateList();
@@ -57,7 +55,7 @@ public class SuLogFragment extends Fragment {
}
private void updateList() {
List<SuLogEntry> logs = dbHelper.getLogList();
List<SuLogEntry> logs = magiskManager.suDB.getLogList();
if (logs.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);
@@ -76,7 +74,7 @@ public class SuLogFragment extends Fragment {
updateList();
return true;
case R.id.menu_clear:
dbHelper.clearLogs();
magiskManager.suDB.clearLogs();
updateList();
return true;
default:

View File

@@ -11,7 +11,6 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.PolicyAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.Policy;
import java.util.List;
@@ -33,15 +32,15 @@ public class SuperuserFragment extends Fragment {
unbinder = ButterKnife.bind(this, view);
PackageManager pm = getActivity().getPackageManager();
MagiskManager magiskManager = getApplication();
SuDatabaseHelper dbHelper = new SuDatabaseHelper(getActivity());
List<Policy> policyList = dbHelper.getPolicyList(pm);
List<Policy> policyList = magiskManager.suDB.getPolicyList(pm);
if (policyList.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
recyclerView.setAdapter(new PolicyAdapter(policyList, dbHelper, pm));
recyclerView.setAdapter(new PolicyAdapter(policyList, magiskManager.suDB, pm));
emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}

View File

@@ -1,5 +1,6 @@
package com.topjohnwu.magisk.adapters;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.support.design.widget.Snackbar;
@@ -86,10 +87,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);
new MagiskHide((Activity) holder.itemView.getContext()).add(info.packageName);
mHideList.add(info.packageName);
} else {
new MagiskHide().rm(info.packageName);
new MagiskHide((Activity) holder.itemView.getContext()).rm(info.packageName);
mHideList.remove(info.packageName);
}
});

View File

@@ -12,7 +12,6 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.SerialTask;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.utils.Shell;
@@ -39,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();
@@ -53,44 +53,31 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
holder.checkBox.setOnCheckedChangeListener(null);
holder.checkBox.setChecked(module.isEnabled());
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> new SerialTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
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;
}
return null;
}
@Override
protected void onPostExecute(Void v) {
int snack = isChecked ? R.string.disable_file_removed : R.string.disable_file_created;
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
}
}.exec());
});
holder.delete.setOnClickListener(v -> new SerialTask<Void, Void, Void>() {
private final boolean removed = module.willBeRemoved();
@Override
protected Void doInBackground(Void... voids) {
holder.delete.setOnClickListener(v -> {
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;
}
return null;
}
@Override
protected void onPostExecute(Void v) {
int snack = removed ? R.string.remove_file_deleted : R.string.remove_file_created;
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
updateDeleteButton(holder, module);
}
}.exec());
});
if (module.isUpdated()) {
holder.notice.setVisibility(View.VISIBLE);

View File

@@ -1,21 +1,18 @@
package com.topjohnwu.magisk.adapters;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.pm.PackageManager;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.ExpandableViewHolder;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.Policy;
@@ -49,7 +46,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Policy policy = policyList.get(position);
try {
holder.setExpanded(expandList.contains(policy));
holder.itemView.setOnClickListener(view -> {
@@ -64,7 +61,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
holder.appName.setText(policy.appName);
holder.packageName.setText(policy.packageName);
holder.appIcon.setImageDrawable(pm.getPackageInfo(policy.packageName, 0).applicationInfo.loadIcon(pm));
holder.appIcon.setImageDrawable(policy.info.loadIcon(pm));
holder.masterSwitch.setOnCheckedChangeListener((v, isChecked) -> {
if ((isChecked && policy.policy == Policy.DENY) ||
(!isChecked && policy.policy == Policy.ALLOW)) {
@@ -72,7 +69,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
String message = v.getContext().getString(
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
dbHelper.addPolicy(policy);
dbHelper.updatePolicy(policy);
}
});
holder.notificationSwitch.setOnCheckedChangeListener((v, isChecked) -> {
@@ -82,7 +79,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
String message = v.getContext().getString(
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
dbHelper.addPolicy(policy);
dbHelper.updatePolicy(policy);
}
});
holder.loggingSwitch.setOnCheckedChangeListener((v, isChecked) -> {
@@ -92,7 +89,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
String message = v.getContext().getString(
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
dbHelper.addPolicy(policy);
dbHelper.updatePolicy(policy);
}
});
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
@@ -104,7 +101,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
notifyItemRangeChanged(position, policyList.size());
SnackbarMaker.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
Snackbar.LENGTH_SHORT).show();
dbHelper.deletePolicy(policy.uid);
dbHelper.deletePolicy(policy);
})
.setNegativeButton(R.string.no_thanks, null)
.setCancelable(true)
@@ -115,12 +112,6 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
// Hide for now
holder.moreInfo.setVisibility(View.GONE);
} catch (PackageManager.NameNotFoundException e) {
policyList.remove(position);
dbHelper.deletePolicy(policy.uid);
onBindViewHolder(holder, position);
}
}
@Override
@@ -128,11 +119,10 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
return policyList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
static class ViewHolder extends ExpandableViewHolder {
@BindView(R.id.app_name) TextView appName;
@BindView(R.id.package_name) TextView packageName;
@BindView(R.id.expand_layout) LinearLayout expandLayout;
@BindView(R.id.app_icon) ImageView appIcon;
@BindView(R.id.master_switch) Switch masterSwitch;
@BindView(R.id.notification_switch) Switch notificationSwitch;
@@ -141,83 +131,14 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
@BindView(R.id.delete) ImageView delete;
@BindView(R.id.more_info) ImageView moreInfo;
private ValueAnimator mAnimator;
private boolean mExpanded = false;
private static int expandHeight = 0;
ViewHolder(View itemView) {
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (expandHeight == 0) {
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
expandLayout.measure(widthSpec, heightSpec);
expandHeight = expandLayout.getMeasuredHeight();
}
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
expandLayout.setVisibility(View.GONE);
mAnimator = slideAnimator(0, expandHeight);
return true;
}
});
}
private void setExpanded(boolean expanded) {
mExpanded = expanded;
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = expanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
}
private void expand() {
expandLayout.setVisibility(View.VISIBLE);
mAnimator.start();
mExpanded = true;
}
private void collapse() {
if (!mExpanded) return;
int finalHeight = expandLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationEnd(Animator animator) {
expandLayout.setVisibility(View.GONE);
}
@Override
public void onAnimationStart(Animator animator) {}
@Override
public void onAnimationCancel(Animator animator) {}
@Override
public void onAnimationRepeat(Animator animator) {}
});
mAnimator.start();
mExpanded = false;
public void setExpandLayout(View itemView) {
expandLayout = itemView.findViewById(R.id.expand_layout);
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
}
}
}

View File

@@ -1,5 +1,6 @@
package com.topjohnwu.magisk.adapters;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
@@ -15,67 +16,102 @@ import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.MarkDownWindow;
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 com.topjohnwu.magisk.utils.ValueSortedMap;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> {
public class ReposAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int SECTION_TYPE = 0;
private static final int REPO_TYPE = 1;
private List<Repo> mUpdateRepos, mInstalledRepos, mOthersRepos;
private Context mContext;
private int[] sectionList;
private int size;
private ValueSortedMap<String, Repo> repoMap;
public ReposAdapter(List<Repo> update, List<Repo> installed, List<Repo> others) {
mUpdateRepos = update;
mInstalledRepos = installed;
mOthersRepos = others;
public ReposAdapter(ValueSortedMap<String, Repo> map) {
repoMap = map;
mUpdateRepos = new ArrayList<>();
mInstalledRepos = new ArrayList<>();
mOthersRepos = new ArrayList<>();
sectionList = new int[3];
size = 0;
}
@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 RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
View v;
RecyclerView.ViewHolder holder = null;
switch (viewType) {
case SECTION_TYPE:
v = LayoutInflater.from(context).inflate(R.layout.section, parent, false);
holder = new SectionHolder(v);
break;
case REPO_TYPE:
v = LayoutInflater.from(context).inflate(R.layout.list_item_repo, parent, false);
holder = new RepoHolder(v);
break;
}
return holder;
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Repo repo = getItem(position);
holder.title.setText(repo.getName());
holder.versionName.setText(repo.getVersion());
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Context context = holder.itemView.getContext();
switch (getItemViewType(position)) {
case SECTION_TYPE:
SectionHolder section = (SectionHolder) holder;
if (position == sectionList[0]) {
section.sectionText.setText(context.getString(R.string.update_available));
} else if (position == sectionList[1]) {
section.sectionText.setText(context.getString(R.string.installed));
} else {
section.sectionText.setText(context.getString(R.string.not_installed));
}
break;
case REPO_TYPE:
RepoHolder repoHolder = (RepoHolder) holder;
Repo repo = getRepo(position);
repoHolder.title.setText(repo.getName());
repoHolder.versionName.setText(repo.getVersion());
String author = repo.getAuthor();
holder.author.setText(TextUtils.isEmpty(author) ? null : mContext.getString(R.string.author, author));
holder.description.setText(repo.getDescription());
repoHolder.author.setText(TextUtils.isEmpty(author) ? null : context.getString(R.string.author, author));
repoHolder.description.setText(repo.getDescription());
holder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), mContext));
repoHolder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), context));
holder.downloadImage.setOnClickListener(v -> {
repoHolder.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) {
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) {
new ProcessRepoZip(activity, uri, false).exec();
new ProcessRepoZip((Activity) context, uri, false).exec();
}
},
repo.getZipUrl(),
@@ -83,28 +119,81 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
.setNegativeButton(R.string.no_thanks, null)
.show();
});
break;
}
}
@Override
public int getItemViewType(int position) {
for (int i : sectionList) {
if (position == i)
return SECTION_TYPE;
}
return REPO_TYPE;
}
@Override
public int getItemCount() {
return mUpdateRepos.size() + mInstalledRepos.size() + mOthersRepos.size();
return size;
}
private Repo getItem(int position) {
if (position >= mUpdateRepos.size()) {
public void filter(ValueSortedMap<String, Module> moduleMap, String s) {
mUpdateRepos.clear();
mInstalledRepos.clear();
mOthersRepos.clear();
sectionList[0] = sectionList[1] = sectionList[2] = 0;
for (Repo repo : repoMap.values()) {
if (repo.getName().toLowerCase().contains(s.toLowerCase())
|| repo.getAuthor().toLowerCase().contains(s.toLowerCase())
|| repo.getDescription().toLowerCase().contains(s.toLowerCase())
) {
// Passed the filter
Module module = moduleMap.get(repo.getId());
if (module != null) {
if (repo.getVersionCode() > module.getVersionCode()) {
// Updates
mUpdateRepos.add(repo);
} else {
mInstalledRepos.add(repo);
}
} else {
mOthersRepos.add(repo);
}
}
}
sectionList[0] = mUpdateRepos.isEmpty() ? -1 : 0;
size = mUpdateRepos.isEmpty() ? 0 : mUpdateRepos.size() + 1;
sectionList[1] = mInstalledRepos.isEmpty() ? -1 : size;
size += mInstalledRepos.isEmpty() ? 0 : mInstalledRepos.size() + 1;
sectionList[2] = mOthersRepos.isEmpty() ? -1 : size;
size += mOthersRepos.isEmpty() ? 0 : mOthersRepos.size() + 1;
notifyDataSetChanged();
}
private Repo getRepo(int position) {
if (!mUpdateRepos.isEmpty()) position -= 1;
if (position < mUpdateRepos.size()) return mUpdateRepos.get(position);
position -= mUpdateRepos.size();
if (position >= mInstalledRepos.size()) {
if (!mInstalledRepos.isEmpty()) position -= 1;
if (position < mInstalledRepos.size()) return mInstalledRepos.get(position);
position -= mInstalledRepos.size();
if (!mOthersRepos.isEmpty()) position -= 1;
return mOthersRepos.get(position);
} else {
return mInstalledRepos.get(position);
}
} else {
return mUpdateRepos.get(position);
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;
@@ -113,7 +202,7 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
@BindView(R.id.info_layout) LinearLayout infoLayout;
@BindView(R.id.download) ImageView downloadImage;
ViewHolder(View itemView) {
RepoHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}

View File

@@ -1,178 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.Arrays;
import java.util.Comparator;
public class SimpleSectionedRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int SECTION_TYPE = 0;
private boolean mValid = true;
private int mSectionResourceId;
private int mTextResourceId;
private RecyclerView.Adapter mBaseAdapter;
private SparseArray<Section> mSections = new SparseArray<Section>();
public SimpleSectionedRecyclerViewAdapter(int sectionResourceId, int textResourceId,
RecyclerView.Adapter baseAdapter) {
mSectionResourceId = sectionResourceId;
mTextResourceId = textResourceId;
mBaseAdapter = baseAdapter;
mBaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
mValid = mBaseAdapter.getItemCount()>0;
notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
mValid = mBaseAdapter.getItemCount()>0;
notifyItemRangeChanged(positionStart, itemCount);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
mValid = mBaseAdapter.getItemCount()>0;
notifyItemRangeInserted(positionStart, itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
mValid = mBaseAdapter.getItemCount()>0;
notifyItemRangeRemoved(positionStart, itemCount);
}
});
}
public static class SectionViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public SectionViewHolder(View view, int mTextResourceid) {
super(view);
title = (TextView) view.findViewById(mTextResourceid);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int typeView) {
if (typeView == SECTION_TYPE) {
View view = LayoutInflater.from(parent.getContext()).inflate(mSectionResourceId, parent, false);
return new SectionViewHolder(view,mTextResourceId);
}else{
return mBaseAdapter.onCreateViewHolder(parent, typeView -1);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) {
if (isSectionHeaderPosition(position)) {
((SectionViewHolder)sectionViewHolder).title.setText(mSections.get(position).title);
}else{
mBaseAdapter.onBindViewHolder(sectionViewHolder,sectionedPositionToPosition(position));
}
}
@Override
public int getItemViewType(int position) {
return isSectionHeaderPosition(position)
? SECTION_TYPE
: mBaseAdapter.getItemViewType(sectionedPositionToPosition(position)) +1 ;
}
public static class Section {
int firstPosition;
int sectionedPosition;
CharSequence title;
public Section(int firstPosition, CharSequence title) {
this.firstPosition = firstPosition;
this.title = title;
}
public CharSequence getTitle() {
return title;
}
}
public void setSections(Section[] sections) {
mSections.clear();
Arrays.sort(sections, new Comparator<Section>() {
@Override
public int compare(Section o, Section o1) {
return (o.firstPosition == o1.firstPosition)
? 0
: ((o.firstPosition < o1.firstPosition) ? -1 : 1);
}
});
int offset = 0; // offset positions for the headers we're adding
for (Section section : sections) {
section.sectionedPosition = section.firstPosition + offset;
mSections.append(section.sectionedPosition, section);
++offset;
}
notifyDataSetChanged();
}
public int positionToSectionedPosition(int position) {
int offset = 0;
for (int i = 0; i < mSections.size(); i++) {
if (mSections.valueAt(i).firstPosition > position) {
break;
}
++offset;
}
return position + offset;
}
public int sectionedPositionToPosition(int sectionedPosition) {
if (isSectionHeaderPosition(sectionedPosition)) {
return RecyclerView.NO_POSITION;
}
int offset = 0;
for (int i = 0; i < mSections.size(); i++) {
if (mSections.valueAt(i).sectionedPosition > sectionedPosition) {
break;
}
--offset;
}
return sectionedPosition + offset;
}
public boolean isSectionHeaderPosition(int position) {
return mSections.get(position) != null;
}
@Override
public long getItemId(int position) {
return isSectionHeaderPosition(position)
? Integer.MAX_VALUE - mSections.indexOfKey(position)
: mBaseAdapter.getItemId(sectionedPositionToPosition(position));
}
@Override
public int getItemCount() {
return (mValid ? mBaseAdapter.getItemCount() + mSections.size() : 0);
}
}

View File

@@ -1,17 +1,13 @@
package com.topjohnwu.magisk.adapters;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.thoughtbot.expandablerecyclerview.ExpandableRecyclerViewAdapter;
@@ -19,6 +15,7 @@ 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.superuser.SuLogEntry;
import java.util.ArrayList;
@@ -90,7 +87,7 @@ public class SuLogAdapter {
SuLogEntry logEntry = (SuLogEntry) group.getItems().get(childIndex);
holder.setExpanded(expandList.contains(logEntry));
holder.itemView.setOnClickListener(view -> {
if (holder.mExpanded) {
if (holder.getExpanded()) {
holder.collapse();
expandList.remove(logEntry);
} else {
@@ -150,92 +147,50 @@ public class SuLogAdapter {
}
}
// Wrapper class
static class LogViewHolder extends ChildViewHolder {
private InternalViewHolder expandableViewHolder;
@BindView(R.id.app_name) TextView appName;
@BindView(R.id.action) TextView action;
@BindView(R.id.time) TextView time;
@BindView(R.id.fromPid) TextView fromPid;
@BindView(R.id.toUid) TextView toUid;
@BindView(R.id.command) TextView command;
@BindView(R.id.expand_layout) LinearLayout expandLayout;
private ValueAnimator mAnimator;
private boolean mExpanded = false;
private static int expandHeight = 0;
public LogViewHolder(View itemView) {
LogViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
expandableViewHolder = new InternalViewHolder(itemView);
}
private class InternalViewHolder extends ExpandableViewHolder {
InternalViewHolder(View itemView) {
super(itemView);
}
@Override
public boolean onPreDraw() {
if (expandHeight == 0) {
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
expandLayout.measure(widthSpec, heightSpec);
expandHeight = expandLayout.getMeasuredHeight();
public void setExpandLayout(View itemView) {
expandLayout = itemView.findViewById(R.id.expand_layout);
}
}
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
expandLayout.setVisibility(View.GONE);
mAnimator = slideAnimator(0, expandHeight);
return true;
}
});
private boolean getExpanded() {
return expandableViewHolder.mExpanded;
}
private void setExpanded(boolean expanded) {
mExpanded = expanded;
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = expanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
expandableViewHolder.setExpanded(expanded);
}
private void expand() {
expandLayout.setVisibility(View.VISIBLE);
mAnimator.start();
mExpanded = true;
expandableViewHolder.expand();
}
private void collapse() {
if (!mExpanded) return;
int finalHeight = expandLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationEnd(Animator animator) {
expandLayout.setVisibility(View.GONE);
}
@Override
public void onAnimationStart(Animator animator) {}
@Override
public void onAnimationCancel(Animator animator) {}
@Override
public void onAnimationRepeat(Animator animator) {}
});
mAnimator.start();
mExpanded = false;
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
expandableViewHolder.collapse();
}
}

View File

@@ -1,15 +1,9 @@
package com.topjohnwu.magisk.asyncs;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.NotificationCompat;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.SplashActivity;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.WebService;
@@ -18,55 +12,51 @@ import org.json.JSONObject;
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
private static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json";
private static final int NOTIFICATION_ID = 1;
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) {
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return null;
String jsonStr = WebService.request(UPDATE_JSON, WebService.GET);
try {
JSONObject json = new JSONObject(jsonStr);
JSONObject magisk = json.getJSONObject("magisk");
magiskManager.remoteMagiskVersion = magisk.getDouble("versionCode");
magiskManager.remoteMagiskVersionString = magisk.getString("version");
magiskManager.remoteMagiskVersionCode = magisk.getInt("versionCode");
magiskManager.magiskLink = magisk.getString("link");
magiskManager.releaseNoteLink = magisk.getString("note");
} catch (JSONException ignored) {
}
JSONObject manager = json.getJSONObject("app");
magiskManager.remoteManagerVersionString = manager.getString("version");
magiskManager.remoteManagerVersionCode = manager.getInt("versionCode");
magiskManager.managerLink = manager.getString("link");
} catch (JSONException ignored) {}
return null;
}
@Override
protected void onPostExecute(Void v) {
if (magiskManager.magiskVersion < magiskManager.remoteMagiskVersion
&& showNotification && magiskManager.updateNotification) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(magiskManager);
builder.setSmallIcon(R.drawable.ic_magisk)
.setContentTitle(magiskManager.getString(R.string.magisk_update_title))
.setContentText(magiskManager.getString(R.string.magisk_update_available, magiskManager.remoteMagiskVersion))
.setVibrate(new long[]{0, 100, 100, 100})
.setAutoCancel(true);
Intent intent = new Intent(magiskManager, SplashActivity.class);
intent.putExtra(MagiskManager.INTENT_SECTION, "install");
TaskStackBuilder stackBuilder = TaskStackBuilder.create(magiskManager);
stackBuilder.addParentStack(SplashActivity.class);
stackBuilder.addNextIntent(intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(NOTIFICATION_ID, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) magiskManager.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, builder.build());
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return;
if (showNotification && magiskManager.updateNotification) {
if (BuildConfig.VERSION_CODE < magiskManager.remoteManagerVersionCode) {
Utils.showManagerUpdate(magiskManager);
} else if (magiskManager.magiskVersionCode < magiskManager.remoteMagiskVersionCode) {
Utils.showMagiskUpdate(magiskManager);
}
}
magiskManager.updateCheckDone.trigger();
super.onPostExecute(v);
}
}

View File

@@ -1,15 +1,12 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
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 SerialTask<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(Context 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);
mFilename = Utils.getNameFromUri(context, 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;
}
}
protected boolean unzipAndCheck() throws Exception {
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 doInBackground(Void... voids) {
Logger.dev("FlashZip Running... " + mFilename);
List<String> ret;
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));
magiskManager.shell.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) {
super.onPostExecute(result);
progress.dismiss();
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return;
magiskManager.shell.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);
break;
mList.add(magiskManager.getString(R.string.install_error));
Utils.showUriSnack(getActivity(), mUri);
return;
case 0:
Toast.makeText(magiskManager, magiskManager.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show();
break;
mList.add(magiskManager.getString(R.string.invalid_zip));
return;
case 1:
onSuccess();
// Success
break;
}
}
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();
new LoadModules(magiskManager).exec();
super.onPostExecute(result);
}
}

View File

@@ -1,27 +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 SerialTask<Void, Void, Void> {
public GetBootBlocks(Activity context) {
super(context);
}
@Override
protected Void doInBackground(Void... params) {
magiskManager.blockList = Shell.su("ls /dev/block | grep mmc");
if (magiskManager.bootBlock == null) {
magiskManager.bootBlock = Utils.detectBootImage();
}
return null;
}
@Override
protected void onPostExecute(Void v) {
magiskManager.blockDetectionDone.trigger();
}
}

View File

@@ -1,9 +1,10 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
import java.util.Collections;
@@ -12,12 +13,14 @@ import java.util.List;
public class LoadApps extends ParallelTask<Void, Void, Void> {
public LoadApps(Activity context) {
public LoadApps(Context context) {
super(context);
}
@Override
protected Void doInBackground(Void... voids) {
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return null;
PackageManager pm = magiskManager.getPackageManager();
List<ApplicationInfo> list = pm.getInstalledApplications(0);
for (Iterator<ApplicationInfo> i = list.iterator(); i.hasNext(); ) {
@@ -34,6 +37,8 @@ public class LoadApps extends ParallelTask<Void, Void, Void> {
@Override
protected void onPostExecute(Void v) {
new MagiskHide(activity).list();
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return;
new MagiskHide(magiskManager).list();
}
}

View File

@@ -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 SerialTask<Void, Void, Void> {
public class LoadModules extends ParallelTask<Void, Void, Void> {
public LoadModules(Activity context) {
public LoadModules(Context context) {
super(context);
}
@Override
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(magiskManager.shell, MagiskManager.MAGISK_PATH)) {
Logger.dev("LoadModules: Adding modules from " + path);
Module module;
try {
module = new Module(path);
Module module = new Module(magiskManager.shell, path);
magiskManager.moduleMap.put(module.getId(), module);
} catch (BaseModule.CacheModException ignored) {}
}
@@ -36,6 +37,9 @@ public class LoadModules extends SerialTask<Void, Void, Void> {
@Override
protected void onPostExecute(Void v) {
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return;
magiskManager.moduleLoadDone.trigger();
super.onPostExecute(v);
}
}

View File

@@ -1,9 +1,10 @@
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;
@@ -12,14 +13,15 @@ import com.topjohnwu.magisk.utils.ValueSortedMap;
import com.topjohnwu.magisk.utils.WebService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -27,62 +29,45 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
public static final String ETAG_KEY = "ETag";
private static final String REPO_URL = "https://api.github.com/orgs/Magisk-Modules-Repo/repos";
private static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&page=%d";
private static final String IF_NONE_MATCH = "If-None-Match";
private static final String LINK_KEY = "Link";
private String prefsPath;
private static final int CHECK_ETAG = 0;
private static final int LOAD_NEXT = 1;
private static final int LOAD_PREV = 2;
public LoadRepos(Activity context) {
private List<String> etags;
private ValueSortedMap<String, Repo> cached, fetched;
private RepoDatabaseHelper repoDB;
private SharedPreferences prefs;
public LoadRepos(Context context) {
super(context);
prefsPath = context.getApplicationInfo().dataDir + "/shared_prefs";
}
@Override
protected Void doInBackground(Void... voids) {
Logger.dev("LoadRepos: Loading repos");
SharedPreferences prefs = magiskManager.prefs;
RepoDatabaseHelper dbHelper = new RepoDatabaseHelper(magiskManager);
prefs = getMagiskManager().prefs;
String prefsPath = context.getApplicationInfo().dataDir + "/shared_prefs";
repoDB = new RepoDatabaseHelper(context);
// Legacy data cleanup
File old = new File(prefsPath, "RepoMap.xml");
if (old.exists() || !prefs.getString("repomap", "empty").equals("empty")) {
old.delete();
prefs.edit().remove("version").remove("repomap").remove(ETAG_KEY).apply();
dbHelper.clearRepo();
repoDB.clearRepo();
}
etags = new ArrayList<>(
Arrays.asList(prefs.getString(ETAG_KEY, "").split(",")));
}
Map<String, String> header = new HashMap<>();
// Get cached ETag to add in the request header
String etag = prefs.getString(ETAG_KEY, "");
header.put("If-None-Match", etag);
// Make a request to main URL for repo info
String jsonString = WebService.request(REPO_URL, WebService.GET, null, header, false);
ValueSortedMap<String, Repo> cached = dbHelper.getRepoMap(false), fetched = new ValueSortedMap<>();
if (!TextUtils.isEmpty(jsonString)) {
try {
private void loadJSON(String jsonString) throws Exception {
JSONArray jsonArray = new JSONArray(jsonString);
// If it gets to this point, the response is valid, update ETag
etag = WebService.getLastResponseHeader().get(ETAG_KEY).get(0);
// Maybe bug in Android build tools, sometimes the ETag has crap in it...
etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1);
// Update repo info
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonobject = jsonArray.getJSONObject(i);
String id = jsonobject.getString("description");
String name = jsonobject.getString("name");
String lastUpdate = jsonobject.getString("pushed_at");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
Date updatedDate;
try {
updatedDate = format.parse(lastUpdate);
} catch (ParseException e) {
continue;
}
Date updatedDate = format.parse(lastUpdate);
Repo repo = cached.get(id);
try {
if (repo == null) {
@@ -91,35 +76,119 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
} else {
// Popout from cached
cached.remove(id);
Logger.dev("LoadRepos: Update cached repo " + id);
repo.update(updatedDate);
}
if (repo.getId() != null) {
fetched.put(id, repo);
}
} catch (BaseModule.CacheModException ignored) {}
// Update the database
dbHelper.addRepoMap(fetched);
// The leftover cached are those removed remote, cleanup db
dbHelper.removeRepo(cached);
// Update ETag
prefs.edit().putString(ETAG_KEY, etag).apply();
}
}
} catch (JSONException e) {
private boolean loadPage(int page, String url, int mode) {
Logger.dev("LoadRepos: 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));
header.put(IF_NONE_MATCH, etags.get(page));
}
if (url == null) {
url = String.format(Locale.US, REPO_URL, page + 1);
}
String jsonString = WebService.request(url, WebService.GET, header, true);
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
try {
loadJSON(jsonString);
} catch (Exception e) {
e.printStackTrace();
return false;
}
// Update the ETAG
String newEtag = header.get(ETAG_KEY);
newEtag = newEtag.substring(newEtag.indexOf('\"'), newEtag.lastIndexOf('\"') + 1);
Logger.dev("New ETAG: " + newEtag);
if (page < etags.size()) {
etags.set(page, newEtag);
} else {
etags.add(newEtag);
}
String links = header.get(LINK_KEY);
if (links != null) {
if (mode == CHECK_ETAG || mode == LOAD_NEXT) {
// Try to check next page URL
url = null;
for (String s : links.split(", ")) {
if (s.contains("next")) {
url = s.substring(s.indexOf("<") + 1, s.indexOf(">; "));
break;
}
}
if (url != null) {
loadPage(page + 1, url, LOAD_NEXT);
}
}
magiskManager.repoMap = dbHelper.getRepoMap();
if (mode == CHECK_ETAG || mode == LOAD_PREV) {
// Try to check prev page URL
url = null;
for (String s : links.split(", ")) {
if (s.contains("prev")) {
url = s.substring(s.indexOf("<") + 1, s.indexOf(">; "));
break;
}
}
if (url != null) {
loadPage(page - 1, url, LOAD_PREV);
}
}
}
Logger.dev("LoadRepos: Repo load done");
return true;
}
@Override
protected Void doInBackground(Void... voids) {
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return null;
Logger.dev("LoadRepos: Loading repos");
cached = repoDB.getRepoMap(false);
fetched = new ValueSortedMap<>();
if (!loadPage(0, null, CHECK_ETAG)) {
magiskManager.repoMap = repoDB.getRepoMap();
Logger.dev("LoadRepos: No updates, use DB");
return null;
}
repoDB.addRepoMap(fetched);
repoDB.removeRepo(cached);
// Update ETag
StringBuilder etagBuilder = new StringBuilder();
for (int i = 0; i < etags.size(); ++i) {
if (i != 0) etagBuilder.append(",");
etagBuilder.append(etags.get(i));
}
prefs.edit().putString(ETAG_KEY, etagBuilder.toString()).apply();
magiskManager.repoMap = repoDB.getRepoMap();
Logger.dev("LoadRepos: Done");
return null;
}
@Override
protected void onPostExecute(Void v) {
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return;
magiskManager.repoLoadDone.trigger();
super.onPostExecute(v);
}
}

View File

@@ -1,26 +1,25 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.content.Context;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Shell;
import java.util.List;
public class MagiskHide extends SerialTask<Object, Void, Void> {
public class MagiskHide extends ParallelTask<Object, Void, Void> {
private boolean isList = false;
public MagiskHide() {}
public MagiskHide(Activity context) {
public MagiskHide(Context context) {
super(context);
}
@Override
protected Void doInBackground(Object... params) {
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return null;
String command = (String) params[0];
List<String> ret = Shell.su(MagiskManager.MAGISK_HIDE_PATH + command);
List<String> ret = magiskManager.shell.su("magiskhide --" + command);
if (isList) {
magiskManager.magiskHideList = ret;
}
@@ -29,9 +28,12 @@ public class MagiskHide extends SerialTask<Object, Void, Void> {
@Override
protected void onPostExecute(Void v) {
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return;
if (isList) {
magiskManager.magiskHideDone.trigger();
}
super.onPostExecute(v);
}
public void add(CharSequence packageName) {
@@ -43,17 +45,17 @@ public class MagiskHide extends SerialTask<Object, Void, Void> {
}
public void enable() {
exec("enable; setprop persist.magisk.hide 1");
exec("enable");
}
public void disable() {
exec("disable; setprop persist.magisk.hide 0");
exec("disable");
}
public void list() {
isList = true;
if (magiskManager == null) return;
exec("list");
if (getMagiskManager() == null) return;
exec("ls");
}
}

View File

@@ -1,24 +1,58 @@
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(Activity context) {
activity = context;
magiskManager = Utils.getMagiskManager(context);
public ParallelTask(Context context) {
weakMagiskManager = new WeakReference<>(Utils.getMagiskManager(context));
}
@SafeVarargs
public final void exec(Params... params) {
public ParallelTask(Activity 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 : getMagiskManager().shell;
}
@SuppressWarnings("unchecked")
public void exec(Params... params) {
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
@Override
protected void onPostExecute(Result result) {
if (callback != null) callback.run();
}
public ParallelTask<Params, Progress, Result> setCallBack(Runnable next) {
callback = next;
return this;
}
}

View File

@@ -1,96 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.net.Uri;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils;
import java.io.File;
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()) {
try {
// We might not have busybox yet, unzip with Java
// We shall have complete busybox after Magisk installation
File tempdir = new File(magiskManager.getCacheDir(), "magisk");
ZipUtils.unzip(magiskManager.getContentResolver().openInputStream(mUri), tempdir);
// Running in parallel mode, open new shell
Shell.su(true,
"rm -f /dev/.magisk",
(mBoot != null) ? "echo \"BOOTIMAGE=/dev/block/" + mBoot + "\" >> /dev/.magisk" : "",
"echo \"KEEPFORCEENCRYPT=" + String.valueOf(mEnc) + "\" >> /dev/.magisk",
"echo \"KEEPVERITY=" + String.valueOf(mVerity) + "\" >> /dev/.magisk",
"mkdir -p " + MagiskManager.TMP_FOLDER_PATH,
"cp -af " + tempdir + "/. " + MagiskManager.TMP_FOLDER_PATH + "/magisk",
"mv -f " + tempdir + "/META-INF " + magiskManager.getCacheDir() + "/META-INF",
"rm -rf " + tempdir
);
} catch (Exception e) {
Logger.error("ProcessMagiskZip: Error!");
e.printStackTrace();
return false;
}
return true;
}
return false;
}
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss();
if (result) {
new FlashZip(activity, mUri) {
@Override
protected boolean unzipAndCheck() throws Exception {
// Don't need to check, as it is downloaded in correct form
return true;
}
@Override
protected void onSuccess() {
new SerialTask<Void, Void, Void>(activity) {
@Override
protected Void doInBackground(Void... params) {
Shell.su("setprop magisk.version "
+ String.valueOf(magiskManager.remoteMagiskVersion));
magiskManager.updateCheckDone.trigger();
return null;
}
}.exec();
super.onSuccess();
}
}.exec();
} else {
Utils.showUriSnack(activity, mUri);
}
}
}

View File

@@ -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;
@@ -14,7 +16,6 @@ import com.topjohnwu.magisk.utils.ZipUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
@@ -31,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));
@@ -38,47 +41,31 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
FileInputStream in;
FileOutputStream out;
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");
if (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();
}
out = new FileOutputStream(temp1);
// First remove top folder in Github source zip, Uri -> temp1
ZipUtils.removeTopFolder(activity.getContentResolver().openInputStream(mUri), out);
out.flush();
out.close();
out = new FileOutputStream(temp2);
ZipUtils.removeTopFolder(activity.getContentResolver().openInputStream(mUri), temp1);
// Then sign the zip for the first time, temp1 -> temp2
ZipUtils.signZip(activity, temp1, out, false);
out.flush();
out.close();
ZipUtils.signZip(activity, temp1, temp2, false);
// Adjust the zip to prevent unzip issues, temp2 -> temp2
ZipUtils.adjustZip(temp2);
// Adjust the zip to prevent unzip issues, temp2 -> temp1
ZipUtils.zipAdjust(temp2.getPath(), temp1.getPath());
out = new FileOutputStream(temp1);
// Finally, sign the whole zip file again, temp1 -> temp2
ZipUtils.signZip(activity, temp1, temp2, true);
// Finally, sign the whole zip file again, temp2 -> temp1
ZipUtils.signZip(activity, temp2, out, true);
out.flush();
out.close();
in = new FileInputStream(temp1);
// Write it back to the downloaded zip, temp1 -> Uri
// Write it back to the downloaded zip, temp2 -> Uri
FileInputStream in = new FileInputStream(temp2);
try (OutputStream target = activity.getContentResolver().openOutputStream(mUri)) {
byte[] buffer = new byte[4096];
int length;
@@ -101,16 +88,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);
}
}
}

View File

@@ -1,30 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.os.AsyncTask;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
/**
* This class is only used for running root commands
**/
public abstract class SerialTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
protected Activity activity;
protected MagiskManager magiskManager;
public SerialTask() {}
public SerialTask(Activity context) {
activity = context;
magiskManager = Utils.getMagiskManager(context);
}
@SafeVarargs
public final void exec(Params... params) {
if (!Shell.rootAccess()) return;
executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params);
}
}

View File

@@ -1,8 +1,10 @@
package com.topjohnwu.magisk.components;
import android.support.v7.app.AppCompatActivity;
import android.view.WindowManager;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
public class Activity extends AppCompatActivity {
@@ -10,4 +12,19 @@ public class Activity extends AppCompatActivity {
public MagiskManager getApplicationContext() {
return (MagiskManager) super.getApplicationContext();
}
protected void setFloating() {
boolean isTablet = getResources().getBoolean(R.bool.isTablet);
if (isTablet) {
WindowManager.LayoutParams params = getWindow().getAttributes();
params.height = getResources().getDimensionPixelSize(R.dimen.floating_height);
params.width = getResources().getDimensionPixelSize(R.dimen.floating_width);
params.alpha = 1.0f;
params.dimAmount = 0.6f;
params.flags |= 2;
getWindow().setAttributes(params);
setFinishOnTouchOutside(true);
}
}
}

View File

@@ -0,0 +1,77 @@
package com.topjohnwu.magisk.components;
import android.animation.ValueAnimator;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
public abstract class ExpandableViewHolder extends RecyclerView.ViewHolder {
protected ViewGroup expandLayout;
private ValueAnimator expandAnimator, collapseAnimator;
private static int expandHeight = 0;
public boolean mExpanded = false;
public ExpandableViewHolder(View itemView) {
super(itemView);
setExpandLayout(itemView);
expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (expandHeight == 0) {
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
expandLayout.measure(widthSpec, heightSpec);
expandHeight = expandLayout.getMeasuredHeight();
}
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
expandLayout.setVisibility(View.GONE);
expandAnimator = slideAnimator(0, expandHeight);
collapseAnimator = slideAnimator(expandHeight, 0);
return true;
}
});
}
public void setExpanded(boolean expanded) {
mExpanded = expanded;
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = expanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
}
public void expand() {
if (mExpanded) return;
expandLayout.setVisibility(View.VISIBLE);
expandAnimator.start();
mExpanded = true;
}
public void collapse() {
if (!mExpanded) return;
collapseAnimator.start();
mExpanded = false;
}
public abstract void setExpandLayout(View itemView);
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
}
}

View File

@@ -15,6 +15,7 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VER = 2;
private static final String TABLE_NAME = "repos";
private static final int MIN_TEMPLATE_VER = 3;
public RepoDatabaseHelper(Context context) {
super(context, "repo.db", null, DATABASE_VER);
@@ -45,6 +46,7 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
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();
@@ -60,6 +62,7 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
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() });
}
db.close();
@@ -76,14 +79,14 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
try (Cursor c = db.query(TABLE_NAME, null, null, null, null, null, null)) {
while (c.moveToNext()) {
repo = new Repo(c);
Logger.dev("Load from cache: " + repo.getId());
if (repo.getTemplateVersion() < 3 && filtered) {
if (repo.getTemplateVersion() < MIN_TEMPLATE_VER && filtered) {
Logger.dev("Outdated repo: " + repo.getId());
continue;
}
} else {
// Logger.dev("Load from DB: " + repo.getId());
ret.put(repo.getId(), repo);
}
}
}
db.close();
return ret;
}

View File

@@ -1,23 +1,41 @@
package com.topjohnwu.magisk.database;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.superuser.SuLogEntry;
import com.topjohnwu.magisk.utils.Utils;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SuDatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VER = 1;
private static final String TABLE_NAME = "policies";
public static final String ROOT_ACCESS = "root_access";
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 String POLICY_TABLE = "policies";
private static final String LOG_TABLE = "logs";
private static final String SETTINGS_TABLE = "settings";
private MagiskManager magiskManager;
private PackageManager pm;
public SuDatabaseHelper(Context context) {
super(context, "su.db", null, DATABASE_VER);
magiskManager = Utils.getMagiskManager(context);
pm = context.getPackageManager();
cleanup();
}
@Override
@@ -28,29 +46,107 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 0) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " +
"(uid INT, package_name TEXT, app_name TEXT, policy INT, " +
"until INT, logging INT, notification INT, " +
"PRIMARY KEY(uid))");
createTables(db);
oldVersion = 2;
}
if (oldVersion == 1) {
// We're dropping column app_name, rename and re-construct table
db.execSQL("ALTER TABLE " + POLICY_TABLE + " RENAME TO " + POLICY_TABLE + "_old");
// Create the new tables
createTables(db);
// Migrate old data to new tables
db.execSQL(
"INSERT INTO " + POLICY_TABLE + " SELECT " +
"uid, package_name, policy, until, logging, notification " +
"FROM " + POLICY_TABLE + "_old");
db.execSQL("DROP TABLE " + POLICY_TABLE + "_old");
File oldDB = magiskManager.getDatabasePath("sulog.db");
if (oldDB.exists()) {
migrateLegacyLogList(oldDB, db);
magiskManager.deleteDatabase("sulog.db");
}
++oldVersion;
}
// Currently new database, no upgrading
}
public boolean deletePolicy(int uid) {
private void createTables(SQLiteDatabase db) {
// Policies
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + POLICY_TABLE + " " +
"(uid INT, package_name TEXT, policy INT, " +
"until INT, logging INT, notification INT, " +
"PRIMARY KEY(uid))");
// Logs
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + LOG_TABLE + " " +
"(from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " +
"to_uid INT, action INT, time INT, command TEXT)");
// Settings
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + SETTINGS_TABLE + " " +
"(key TEXT, value INT, PRIMARY KEY(key))");
}
private void cleanup() {
SQLiteDatabase db = getWritableDatabase();
db.delete(TABLE_NAME, "uid=?", new String[] { String.valueOf(uid) });
// Clear outdated policies
db.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) });
}
public void deletePolicy(Policy policy) {
deletePolicy(policy.packageName);
}
public void deletePolicy(String pkg) {
SQLiteDatabase db = getWritableDatabase();
db.delete(POLICY_TABLE, "package_name=?", new String[] { pkg });
db.close();
return getPolicy(uid) == null;
}
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)});
}
public Policy getPolicy(int uid) {
Policy policy = null;
SQLiteDatabase db = getReadableDatabase();
try (Cursor c = db.query(TABLE_NAME, null, "uid=?", new String[] { String.valueOf(uid) }, null, null, null)) {
try (Cursor c = db.query(POLICY_TABLE, null, "uid=?", new String[] { String.valueOf(uid) }, null, null, null)) {
if (c.moveToNext()) {
policy = new Policy(c);
policy = new Policy(c, pm);
}
} catch (PackageManager.NameNotFoundException e) {
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)) {
if (c.moveToNext()) {
policy = new Policy(c, pm);
}
} catch (PackageManager.NameNotFoundException e) {
deletePolicy(pkg);
return null;
}
db.close();
return policy;
@@ -58,28 +154,110 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
public void addPolicy(Policy policy) {
SQLiteDatabase db = getWritableDatabase();
db.replace(TABLE_NAME, null, policy.getContentValues());
db.replace(POLICY_TABLE, null, policy.getContentValues());
db.close();
}
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=?",
new String[] { policy.packageName });
}
public List<Policy> getPolicyList(PackageManager pm) {
List<Policy> ret = new ArrayList<>();
SQLiteDatabase db = getWritableDatabase();
Policy policy;
// Clear outdated policies
db.delete(TABLE_NAME, "until > 0 and until < ?", new String[] { String.valueOf(System.currentTimeMillis()) });
try (Cursor c = db.query(TABLE_NAME, null, null, null, null, null, "app_name ASC")) {
try (Cursor c = db.query(POLICY_TABLE, null, null, null, null, null, null)) {
while (c.moveToNext()) {
policy = new Policy(c);
// Package is uninstalled
if (pm.getPackagesForUid(policy.uid) == null) {
deletePolicy(policy.uid);
try {
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);
continue;
} else {
ret.add(policy);
// No reauth, update to use the new UID
policy.uid = policy.info.uid;
updatePolicy(db, policy);
}
}
ret.add(policy);
} catch (PackageManager.NameNotFoundException e) {
// The app no longer exist, remove from DB
deletePolicy(db, c.getInt(c.getColumnIndex("uid")));
}
}
}
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")) {
while (c.moveToNext()) {
ret.add(new SuLogEntry(c));
}
}
db.close();
return ret;
}
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());
}
}
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();
}
public void clearLogs() {
SQLiteDatabase db = getWritableDatabase();
db.delete(LOG_TABLE, null, null);
db.close();
}
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();
}
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()) {
value = c.getInt(c.getColumnIndex("value"));
}
}
db.close();
return value;
}
}

View File

@@ -1,76 +0,0 @@
package com.topjohnwu.magisk.database;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.superuser.SuLogEntry;
import java.util.ArrayList;
import java.util.List;
public class SuLogDatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VER = 1;
private static final String TABLE_NAME = "logs";
private MagiskManager magiskManager;
public SuLogDatabaseHelper(Context context) {
super(context, "sulog.db", null, DATABASE_VER);
magiskManager = (MagiskManager) context.getApplicationContext();
}
@Override
public void onCreate(SQLiteDatabase db) {
onUpgrade(db, 0, DATABASE_VER);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 0) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " +
"to_uid INT, action INT, time INT, command TEXT)");
}
// Currently new database, no upgrading
}
public void addLog(SuLogEntry log) {
SQLiteDatabase db = getWritableDatabase();
db.insert(TABLE_NAME, null, log.getContentValues());
db.close();
}
public void clearLogs() {
SQLiteDatabase db = getWritableDatabase();
db.delete(TABLE_NAME, null, null);
db.close();
}
public List<SuLogEntry> getLogList() {
return getLogList(null);
}
public List<SuLogEntry> getLogList(int uid) {
return getLogList("uid=" + uid);
}
public List<SuLogEntry> getLogList(String selection) {
List<SuLogEntry> ret = new ArrayList<>();
SQLiteDatabase db = getWritableDatabase();
// Clear outdated logs
db.delete(TABLE_NAME, "time < ?", new String[] { String.valueOf(
System.currentTimeMillis() / 1000 - magiskManager.suLogTimeout * 86400) });
try (Cursor c = db.query(TABLE_NAME, null, selection, null, null, null, "time DESC")) {
while (c.moveToNext()) {
ret.add(new SuLogEntry(c));
}
}
db.close();
return ret;
}
}

View File

@@ -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,29 +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() {
mEnable = !Utils.createFile(mDisableFile);
public void createDisableFile(Shell shell) {
mEnable = false;
Utils.createFile(shell, mDisableFile);
}
public void removeDisableFile() {
mEnable = Utils.removeItem(mDisableFile);
public void removeDisableFile(Shell shell) {
mEnable = true;
Utils.removeItem(shell, mDisableFile);
}
public boolean isEnabled() {
return mEnable;
}
public void createRemoveFile() {
mRemove = Utils.createFile(mRemoveFile);
public void createRemoveFile(Shell shell) {
mRemove = true;
Utils.createFile(shell, mRemoveFile);
}
public void deleteRemoveFile() {
mRemove = !Utils.removeItem(mRemoveFile);
public void deleteRemoveFile(Shell shell) {
mRemove = false;
Utils.removeItem(shell, mRemoveFile);
}
public boolean willBeRemoved() {

View File

@@ -29,14 +29,13 @@ public class Repo extends BaseModule {
}
public void update() throws CacheModException {
Logger.dev("Repo: Re-fetch prop");
String props = WebService.request(getManifestUrl(), WebService.GET, true);
String props = WebService.request(getManifestUrl(), WebService.GET);
String lines[] = props.split("\\n");
parseProps(lines);
Logger.dev("Repo: Fetching prop: " + getId());
}
public void update(Date lastUpdate) throws CacheModException {
Logger.dev("Repo: Local: " + mLastUpdate + " Remote: " + lastUpdate);
if (lastUpdate.after(mLastUpdate)) {
mLastUpdate = lastUpdate;
update();

View File

@@ -3,14 +3,28 @@ package com.topjohnwu.magisk.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import com.topjohnwu.magisk.services.BootupIntentService;
import com.topjohnwu.magisk.services.OnBootIntentService;
import com.topjohnwu.magisk.utils.Utils;
public class BootReceiver extends BroadcastReceiver {
private void startIntentService(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, OnBootIntentService.class));
} else {
context.startService(new Intent(context, OnBootIntentService.class));
}
}
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, BootupIntentService.class));
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Utils.getMagiskManager(context).initSU();
// There is currently no need to start an IntentService onBoot
// startIntentService(context);
}
}
}

View File

@@ -1,6 +1,5 @@
package com.topjohnwu.magisk.receivers;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -13,7 +12,6 @@ import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Utils;
public abstract class DownloadReceiver extends BroadcastReceiver {
public Activity activity;
public String mFilename;
long downloadID;
@@ -21,7 +19,6 @@ public abstract class DownloadReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
activity = (Activity) context;
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {

View File

@@ -0,0 +1,42 @@
package com.topjohnwu.magisk.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
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;
public class ManagerUpdate extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Utils.dlAndReceive(
context,
new DownloadReceiver() {
@Override
public void onDownloadDone(Uri uri) {
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(context,
"com.topjohnwu.magisk.provider", new File(uri.getPath()));
install.setData(content);
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);
context.startActivity(install);
}
}
},
intent.getStringExtra(MagiskManager.INTENT_LINK),
Utils.getLegalFilename("MagiskManager-v" +
intent.getStringExtra(MagiskManager.INTENT_VERSION) + ".apk"));
}
}

View File

@@ -0,0 +1,41 @@
package com.topjohnwu.magisk.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.utils.Utils;
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);
if (policy == null)
return;
switch (intent.getAction()) {
case Intent.ACTION_PACKAGE_REPLACED:
// This will only work pre-O
if (magiskManager.suReauth) {
magiskManager.suDB.deletePolicy(policy);
} else {
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
// Update the UID if available
if (uid > 0) {
policy.uid = uid % 100000;
}
magiskManager.suDB.updatePolicy(policy);
}
break;
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
magiskManager.suDB.deletePolicy(policy);
break;
}
}
}

View File

@@ -1,30 +0,0 @@
package com.topjohnwu.magisk.services;
import android.app.IntentService;
import android.content.Intent;
import android.widget.Toast;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
public class BootupIntentService extends IntentService {
public BootupIntentService() {
super("BootupIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
MagiskManager magiskManager = Utils.getMagiskManager(this);
magiskManager.initSuAccess();
magiskManager.updateMagiskInfo();
if (magiskManager.prefs.getBoolean("magiskhide", false) &&
!magiskManager.disabled && !magiskManager.magiskHideStarted && magiskManager.magiskVersion > 11) {
magiskManager.toast(R.string.start_magiskhide, Toast.LENGTH_LONG);
Shell.su(true, MagiskManager.MAGISK_HIDE_PATH + "enable",
"setprop persist.magisk.hide 1");
}
}
}

View File

@@ -0,0 +1,34 @@
package com.topjohnwu.magisk.services;
import android.app.IntentService;
import android.content.Intent;
import android.os.Build;
import android.support.v7.app.NotificationCompat;
import com.topjohnwu.magisk.R;
public class OnBootIntentService extends IntentService {
private static final int ONBOOT_NOTIFICATION_ID = 3;
public OnBootIntentService() {
super("OnBootIntentService");
}
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.drawable.ic_magisk)
.setContentTitle("onBoot")
.setContentText("Running onBoot operations...");
startForeground(ONBOOT_NOTIFICATION_ID, builder.build());
}
}
@Override
protected void onHandleIntent(Intent intent) {
// Currently nothing to do
}
}

View File

@@ -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();
public boolean onStartJob(JobParameters params) {
Utils.getMagiskManager(this).updateMagiskInfo();
new CheckUpdates(this, true)
.setCallBack(() -> jobFinished(params, false)).exec();
return true;
}

View File

@@ -1,51 +1,57 @@
package com.topjohnwu.magisk.superuser;
import android.content.ContentValues;
import android.content.pm.PackageInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.support.annotation.NonNull;
public class Policy {
public class Policy implements Comparable<Policy>{
public static final int INTERACTIVE = 0;
public static final int DENY = 1;
public static final int ALLOW = 2;
public int uid, policy;
public int uid, policy = INTERACTIVE;
public long until;
public boolean logging = true, notification = true;
public String packageName, appName;
public PackageInfo info;
public ApplicationInfo info;
public Policy(int uid, PackageManager pm) throws PackageManager.NameNotFoundException {
String[] pkgs = pm.getPackagesForUid(uid);
if (pkgs != null && pkgs.length > 0) {
info = pm.getPackageInfo(pkgs[0], 0);
this.uid = uid;
packageName = pkgs[0];
appName = info.applicationInfo.loadLabel(pm).toString();
info = pm.getApplicationInfo(packageName, 0);
appName = info.loadLabel(pm).toString();
} else throw new PackageManager.NameNotFoundException();
}
public Policy(Cursor c) {
public Policy(Cursor c, PackageManager pm) throws PackageManager.NameNotFoundException {
uid = c.getInt(c.getColumnIndex("uid"));
packageName = c.getString(c.getColumnIndex("package_name"));
appName = c.getString(c.getColumnIndex("app_name"));
policy = c.getInt(c.getColumnIndex("policy"));
until = c.getLong(c.getColumnIndex("until"));
logging = c.getInt(c.getColumnIndex("logging")) != 0;
notification = c.getInt(c.getColumnIndex("notification")) != 0;
info = pm.getApplicationInfo(packageName, 0);
appName = info.loadLabel(pm).toString();
}
public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("uid", uid);
values.put("package_name", packageName);
values.put("app_name", appName);
values.put("policy", policy);
values.put("until", until);
values.put("logging", logging ? 1 : 0);
values.put("notification", notification ? 1 : 0);
return values;
}
@Override
public int compareTo(@NonNull Policy policy) {
return appName.toLowerCase().compareTo(policy.appName.toLowerCase());
}
}

View File

@@ -17,7 +17,7 @@ public class RequestActivity extends Activity {
return;
}
getApplicationContext().initSuConfigs();
getApplicationContext().initSUConfig();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setClass(this, SuRequestActivity.class);
startActivity(intent);
finish();

View File

@@ -3,13 +3,12 @@ package com.topjohnwu.magisk.superuser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Process;
import android.widget.Toast;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.database.SuLogDatabaseHelper;
import java.util.Date;
@@ -17,18 +16,29 @@ public class SuReceiver extends BroadcastReceiver {
private static final int NO_NOTIFICATION = 0;
private static final int TOAST = 1;
private static final int NOTIFY_NORMAL_LOG = 0;
private static final int NOTIFY_USER_TOASTS = 1;
private static final int NOTIFY_USER_TO_OWNER = 2;
@Override
public void onReceive(Context context, Intent intent) {
int fromUid, toUid, pid;
int fromUid, toUid, pid, mode;
String command, action;
Policy policy;
MagiskManager magiskManager = (MagiskManager) context.getApplicationContext();
magiskManager.initSUConfig();
if (intent == null) return;
mode = intent.getIntExtra("mode", -1);
if (mode < 0) return;
if (mode == NOTIFY_USER_TO_OWNER) {
magiskManager.toast(R.string.multiuser_hint_owner_request, Toast.LENGTH_LONG);
return;
}
fromUid = intent.getIntExtra("from.uid", -1);
if (fromUid < 0) return;
if (fromUid == Process.myUid()) return; // Don't show anything if it's Magisk Manager
@@ -36,18 +46,16 @@ public class SuReceiver extends BroadcastReceiver {
action = intent.getStringExtra("action");
if (action == null) return;
SuDatabaseHelper suDbHelper = new SuDatabaseHelper(context);
policy = suDbHelper.getPolicy(fromUid);
policy = magiskManager.suDB.getPolicy(fromUid);
if (policy == null) {
try {
policy = new Policy(fromUid, context.getPackageManager());
} catch (Throwable throwable) {
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return;
}
}
magiskManager.initSuConfigs();
SuLogEntry log = new SuLogEntry(policy);
String message;
@@ -64,10 +72,11 @@ public class SuReceiver extends BroadcastReceiver {
return;
}
if (policy.notification && magiskManager.suNotificationType == TOAST)
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
if (policy.notification && magiskManager.suNotificationType == TOAST) {
magiskManager.toast(message, Toast.LENGTH_SHORT);
}
if (policy.logging) {
if (mode == NOTIFY_NORMAL_LOG && policy.logging) {
toUid = intent.getIntExtra("to.uid", -1);
if (toUid < 0) return;
pid = intent.getIntExtra("pid", -1);
@@ -78,8 +87,7 @@ public class SuReceiver extends BroadcastReceiver {
log.fromPid = pid;
log.command = command;
log.date = new Date();
SuLogDatabaseHelper logDbHelper = new SuLogDatabaseHelper(context);
logDbHelper.addLog(log);
magiskManager.suDB.addLog(log);
}
}
}

View File

@@ -21,8 +21,6 @@ import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.utils.CallbackEvent;
import java.io.DataInputStream;
import java.io.IOException;
@@ -30,13 +28,9 @@ import java.io.IOException;
import butterknife.BindView;
import butterknife.ButterKnife;
public class SuRequestActivity extends Activity implements CallbackEvent.Listener<Policy> {
public class SuRequestActivity extends Activity {
private static final int[] timeoutList = {0, -1, 10, 20, 30, 60};
private static final int SU_PROTOCOL_PARAM_MAX = 20;
private static final int SU_PROTOCOL_NAME_MAX = 20;
private static final int SU_PROTOCOL_VALUE_MAX = 256;
private static final int PROMPT = 0;
private static final int AUTO_DENY = 1;
private static final int AUTO_ALLOW = 2;
@@ -54,11 +48,9 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
private PackageManager pm;
private MagiskManager magiskManager;
private int uid;
private boolean hasTimeout;
private Policy policy;
private CountDownTimer timer;
private CallbackEvent.Listener<Policy> self;
private CallbackEvent<Policy> event = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -70,15 +62,12 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
Intent intent = getIntent();
socketPath = intent.getStringExtra("socket");
self = this;
hasTimeout = intent.getBooleanExtra("timeout", true);
new FileObserver(socketPath) {
@Override
public void onEvent(int fileEvent, String path) {
if (fileEvent == FileObserver.DELETE_SELF) {
if (event != null) {
event.trigger();
}
finish();
}
}
@@ -87,8 +76,13 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
new SocketManager(this).exec();
}
void showRequest() {
private boolean cancelTimeout() {
timer.cancel();
deny_btn.setText(getString(R.string.deny));
return false;
}
private void showRequest() {
switch (magiskManager.suResponseType) {
case AUTO_DENY:
handleAction(Policy.DENY, 0);
@@ -100,10 +94,16 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
default:
}
// If not interactive, response directly
if (policy.policy != Policy.INTERACTIVE) {
handleAction();
return;
}
setContentView(R.layout.activity_request);
ButterKnife.bind(this);
appIcon.setImageDrawable(policy.info.applicationInfo.loadIcon(pm));
appIcon.setImageDrawable(policy.info.loadIcon(pm));
appNameView.setText(policy.appName);
packageNameView.setText(policy.packageName);
@@ -120,40 +120,49 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
@Override
public void onFinish() {
deny_btn.setText(getString(R.string.deny_with_str, "(0)"));
event.trigger();
handleAction(Policy.DENY);
}
};
grant_btn.setOnClickListener(v -> handleAction(Policy.ALLOW));
deny_btn.setOnClickListener(v -> handleAction(Policy.DENY));
suPopup.setOnClickListener((v) -> {
grant_btn.setOnClickListener(v -> {
handleAction(Policy.ALLOW);
timer.cancel();
deny_btn.setText(getString(R.string.deny));
});
timeout.setOnTouchListener((v, event) -> {
deny_btn.setOnClickListener(v -> {
handleAction(Policy.DENY);
timer.cancel();
deny_btn.setText(getString(R.string.deny));
return false;
});
suPopup.setOnClickListener(v -> cancelTimeout());
timeout.setOnTouchListener((v, event) -> cancelTimeout());
if (hasTimeout) {
timer.start();
} else {
cancelTimeout();
}
}
@Override
public void onBackPressed() {
event.trigger();
if (policy != null) {
handleAction(Policy.DENY);
}
finish();
}
@Override
public void onTrigger(CallbackEvent<Policy> event) {
Policy policy = event.getResult();
String response = "socket:DENY";
if (policy != null &&policy.policy == Policy.ALLOW ) {
void handleAction() {
String response;
if (policy.policy == Policy.ALLOW) {
response = "socket:ALLOW";
} else {
response = "socket:DENY";
}
try {
socket.getOutputStream().write((response).getBytes());
} catch (Exception ignored) {}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
finish();
}
@@ -163,16 +172,16 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
void handleAction(int action, int time) {
policy.policy = action;
event.trigger(policy);
if (time >= 0) {
policy.until = time == 0 ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
new SuDatabaseHelper(this).addPolicy(policy);
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
magiskManager.suDB.addPolicy(policy);
}
handleAction();
}
private class SocketManager extends ParallelTask<Void, Void, Boolean> {
public SocketManager(Activity context) {
SocketManager(Activity context) {
super(context);
}
@@ -183,40 +192,33 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
socket.connect(new LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM));
DataInputStream is = new DataInputStream(socket.getInputStream());
ContentValues payload = new ContentValues();
for (int i = 0; i < SU_PROTOCOL_PARAM_MAX; i++) {
while (true) {
int nameLen = is.readInt();
if (nameLen > SU_PROTOCOL_NAME_MAX)
throw new IllegalArgumentException("name length too long: " + nameLen);
byte[] nameBytes = new byte[nameLen];
is.readFully(nameBytes);
String name = new String(nameBytes);
if (TextUtils.equals(name, "eof"))
break;
int dataLen = is.readInt();
if (dataLen > SU_PROTOCOL_VALUE_MAX)
throw new IllegalArgumentException(name + " data length too long: " + dataLen);
byte[] dataBytes = new byte[dataLen];
is.readFully(dataBytes);
String data = new String(dataBytes);
payload.put(name, data);
}
if (payload.getAsInteger("uid") == null)
if (payload.getAsInteger("uid") == null) {
return false;
uid = payload.getAsInteger("uid");
}
} catch (IOException e) {
int uid = payload.getAsInteger("uid");
policy = magiskManager.suDB.getPolicy(uid);
if (policy == null) {
policy = new Policy(uid, pm);
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
@@ -225,36 +227,11 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
@Override
protected void onPostExecute(Boolean result) {
if (!result) {
finish();
return;
}
boolean showRequest = false;
event = magiskManager.uidSuRequest.get(uid);
if (event == null) {
showRequest = true;
event = new CallbackEvent<Policy>() {
@Override
public void trigger(Policy result) {
super.trigger(result);
unRegister();
magiskManager.uidSuRequest.remove(uid);
}
};
magiskManager.uidSuRequest.put(uid, event);
}
event.register(self);
try {
if (showRequest) {
policy = new Policy(uid, pm);
if (result) {
showRequest();
} else {
finish();
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
event.trigger();
}
}
}
}

View File

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

View File

@@ -1,114 +0,0 @@
package com.topjohnwu.magisk.utils;
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.util.AttributeSet;
import android.view.View;
import com.github.clans.fab.FloatingActionMenu;
import java.util.List;
/**
* Created by Matteo on 08/08/2015.
*
* Floating Action Menu Behavior for Clans.FloatingActionButton
* https://github.com/Clans/FloatingActionButton/
*
* Use this behavior as your app:layout_behavior attribute in your Floating Action Menu to use the
* FabMenu in a Coordinator Layout.
*
* Remember to use the correct namespace for the fab:
* xmlns:app="http://schemas.android.com/apk/res-auto"
*/
public class FABBehavior extends CoordinatorLayout.Behavior<View> {
private float mTranslationY;
public FABBehavior(Context context, AttributeSet attrs) {
super();
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof Snackbar.SnackbarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
if (dependency instanceof Snackbar.SnackbarLayout) {
updateTranslation(parent, child);
}
return false;
}
@Override
public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {
if (dependency instanceof Snackbar.SnackbarLayout) {
revertTranslation(child);
}
}
private void updateTranslation(CoordinatorLayout parent, View child) {
float translationY = getTranslationY(parent, child);
if (translationY != mTranslationY) {
ViewPropertyAnimatorCompat anim = ViewCompat.animate(child);
anim.cancel();
anim.translationY(translationY).setDuration(100);
mTranslationY = translationY;
}
}
private void revertTranslation(View child) {
if (mTranslationY != 0) {
ViewPropertyAnimatorCompat anim = ViewCompat.animate(child);
anim.cancel();
anim.translationY(0).setDuration(100);
mTranslationY = 0;
}
}
private float getTranslationY(CoordinatorLayout parent, View child) {
float minOffset = 0.0F;
List<View> dependencies = parent.getDependencies(child);
int i = 0;
for (int z = dependencies.size(); i < z; ++i) {
View view = dependencies.get(i);
if (view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(child, view)) {
minOffset = Math.min(minOffset, ViewCompat.getTranslationY(view) - (float) view.getHeight());
}
}
return minOffset;
}
/**
* onStartNestedScroll and onNestedScroll will hide/show the FabMenu when a scroll is detected.
*/
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child,
View directTargetChild, View target, int nestedScrollAxes) {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL ||
super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target,
nestedScrollAxes);
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target,
int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,
dyUnconsumed);
FloatingActionMenu fabMenu = (FloatingActionMenu) child;
if (dyConsumed > 0 && !fabMenu.isMenuButtonHidden()) {
fabMenu.hideMenuButton(true);
} else if (dyConsumed < 0 && fabMenu.isMenuButtonHidden()) {
fabMenu.showMenuButton(true);
}
}
}

View File

@@ -4,37 +4,46 @@ import android.util.Log;
import com.topjohnwu.magisk.MagiskManager;
import java.util.Locale;
public class Logger {
public static final String TAG = "Magisk";
public static final String MAIN_TAG = "Magisk";
public static final String DEBUG_TAG = "MagiskManager";
public static void debug(String msg) {
Log.d(TAG, "DEBUG: " + msg);
public static void debug(String line) {
Log.d(DEBUG_TAG, "DEBUG: " + line);
}
public static void error(String msg) {
Log.e(TAG, "ERROR: " + msg);
public static void debug(String fmt, Object... args) {
debug(String.format(Locale.US, fmt, args));
}
public static void dev(String msg, Object... args) {
public static void error(String line) {
Log.e(MAIN_TAG, "MANAGERERROR: " + line);
}
public static void error(String fmt, Object... args) {
error(String.format(Locale.US, fmt, args));
}
public static void dev(String line) {
if (MagiskManager.devLogging) {
if (args.length == 1 && args[0] instanceof Throwable) {
Log.d(TAG, "DEV: " + msg, (Throwable) args[0]);
} else {
Log.d(TAG, "DEV: " + String.format(msg, args));
}
}
}
public static void dev(String msg) {
if (MagiskManager.devLogging) {
Log.d(TAG, "DEV: " + msg);
Log.d(DEBUG_TAG, line);
}
}
public static void shell(boolean root, String msg) {
public static void dev(String fmt, Object... args) {
dev(String.format(Locale.US, fmt, args));
}
public static void shell(String line) {
if (MagiskManager.shellLogging) {
Log.d(root ? "SU" : "SH", msg);
Log.d(DEBUG_TAG, "SHELL: " + line);
}
}
public static void shell(String fmt, Object... args) {
shell(String.format(Locale.US, fmt, args));
}
}

View File

@@ -1,15 +1,16 @@
package com.topjohnwu.magisk.utils;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.util.Base64;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.safetynet.SafetyNet;
import com.topjohnwu.magisk.R;
import org.json.JSONException;
import org.json.JSONObject;
@@ -19,40 +20,55 @@ import java.security.SecureRandom;
public abstract class SafetyNetHelper
implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
private GoogleApiClient mGoogleApiClient;
private static boolean isRunning = false;
public SafetyNetHelper(Context context) {
mGoogleApiClient = new GoogleApiClient.Builder(context)
private GoogleApiClient mGoogleApiClient;
private Result ret;
protected FragmentActivity mActivity;
public SafetyNetHelper(FragmentActivity activity) {
ret = new Result();
mActivity = activity;
}
// 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)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
isRunning = true;
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult result) {
Logger.dev("SN: Google API fail");
handleResults(-2);
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Logger.dev("SN: Google API Connected");
safetyNetCheck();
ret.errmsg = result.getErrorMessage();
handleResults(ret);
}
@Override
public void onConnectionSuspended(int i) {
Logger.dev("SN: Google API Suspended");
handleResults(-3);
switch (i) {
case CAUSE_NETWORK_LOST:
ret.errmsg = mActivity.getString(R.string.safetyNet_network_loss);
break;
case CAUSE_SERVICE_DISCONNECTED:
ret.errmsg = mActivity.getString(R.string.safetyNet_service_disconnected);
break;
}
handleResults(ret);
}
public void requestTest() {
// Connect Google Service
mGoogleApiClient.connect();
}
private void safetyNetCheck() {
@Override
public void onConnected(@Nullable Bundle bundle) {
Logger.dev("SN: Google API Connected");
// Create nonce
byte[] nonce = new byte[24];
new SecureRandom().nextBytes(nonce);
@@ -68,16 +84,31 @@ public abstract class SafetyNetHelper
Logger.dev("SN: Response: " + json);
try {
JSONObject decoded = new JSONObject(json);
handleResults(decoded.getBoolean("ctsProfileMatch") ? 1 : 0);
} catch (JSONException ignored) {}
ret.ctsProfile = decoded.getBoolean("ctsProfileMatch");
ret.basicIntegrity = decoded.getBoolean("basicIntegrity");
ret.failed = false;
} catch (JSONException e) {
ret.errmsg = mActivity.getString(R.string.safetyNet_res_invalid);
}
} else {
Logger.dev("SN: No response");
handleResults(-1);
ret.errmsg = mActivity.getString(R.string.safetyNet_no_response);
}
// Disconnect
mGoogleApiClient.stopAutoManage(mActivity);
mGoogleApiClient.disconnect();
isRunning = false;
handleResults(ret);
});
}
public abstract void handleResults(int i);
// Callback function to save the results
public abstract void handleResults(Result result);
public static class Result {
public boolean failed = true;
public String errmsg;
public boolean ctsProfile = false;
public boolean basicIntegrity = false;
}
}

View File

@@ -1,9 +1,14 @@
package com.topjohnwu.magisk.utils;
import android.content.Context;
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;
/**
@@ -15,205 +20,149 @@ public class Shell {
// -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted
public static int rootStatus;
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;
try {
rootShell = Runtime.getRuntime().exec("su");
private Shell() {
rootStatus = 1;
} catch (IOException err) {
// No root
rootStatus = 0;
return;
}
Process process = null;
DataOutputStream in = null;
DataInputStream out = null;
rootSTDIN = new DataOutputStream(rootShell.getOutputStream());
rootSTDOUT = new StreamGobbler(rootShell.getInputStream(), rootOutList, true);
rootSTDOUT.start();
// Setup umask and PATH
su("umask 022");
su("PATH=`[ -e /dev/busybox ] && echo /dev/busybox || echo /data/busybox`:$PATH");
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;
return;
}
}
}
public static boolean rootAccess() {
return isInit && 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;
}
return res;
}
// Run with the same shell by default
public static List<String> su(String... commands) {
return su(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>());
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();
STDIN.write(("PATH=`[ -e /dev/busybox ] && echo /dev/busybox || " +
"echo /data/busybox`:$PATH\n").getBytes("UTF-8"));
STDIN.flush();
} catch (IOException err) {
return null;
}
STDOUT.start();
} else {
process = rootShell;
STDIN = rootSTDIN;
STDOUT = rootSTDOUT;
res = rootOutList;
res.clear();
in = new DataOutputStream(process.getOutputStream());
out = new DataInputStream(process.getInputStream());
} catch (IOException e) {
rootStatus = 0;
}
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();
try {
STDIN.close();
} catch (IOException ignore) {
// might be closed already
}
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) {
if (rootAccess()) {
try {
// Process terminated, it means the interactive shell has some issues
process.exitValue();
in.write(("id\n").getBytes("UTF-8"));
in.flush();
String s = new BufferedReader(new InputStreamReader(out)).readLine();
if (s.isEmpty() || !s.contains("uid=0")) {
in.close();
out.close();
process.destroy();
throw new IOException();
}
} catch (IOException e) {
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);
continue;
}
break;
} else {
// 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;
}
break;
}
}
try { STDOUT.join(100); } catch (InterruptedException err) {
rootStatus = -1;
return null;
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) {
return Utils.getMagiskManager(context).shell;
}
public static boolean rootAccess() {
return rootStatus > 0;
}
public List<String> sh(String... commands) {
List<String> res = new ArrayList<>();
if (!isValid) return res;
sh(res, commands);
return res;
}
public void sh_raw(String... commands) {
if (!isValid) return;
synchronized (shellProcess) {
try {
for (String command : commands) {
STDIN.write((command + "\n").getBytes("UTF-8"));
STDIN.flush();
}
} catch (IOException e) {
if (!e.getMessage().contains("EPIPE")) {
Logger.dev("Shell: Root shell error...");
rootStatus = -1;
return null;
e.printStackTrace();
shellProcess.destroy();
isValid = false;
}
} catch(InterruptedException e) {
Logger.dev("Shell: Root shell error...");
rootStatus = -1;
}
}
public void sh(Collection<String> output, String... commands) {
if (!isValid) return;
try {
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(this.STDOUT, output);
out.start();
sh_raw(commands);
sh_raw("echo \'-shell-done-\'");
try { out.join(); } catch (InterruptedException ignored) {}
}
}
public List<String> su(String... commands) {
if (!rootAccess()) return sh();
return sh(commands);
}
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);
@Override
public int size() {
return 0;
}
}
}

View File

@@ -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,28 +15,26 @@ 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) {
reader = new BufferedReader(new InputStreamReader(inputStream));
writer = outputList;
public StreamGobbler(InputStream inputStream, Collection<String> outputList) {
try {
while (inputStream.available() != 0) {
inputStream.skip(inputStream.available());
}
public StreamGobbler(InputStream inputStream, List<String> outputList, boolean root) {
} catch (IOException ignored) {}
reader = new BufferedReader(new InputStreamReader(inputStream));
writer = outputList;
isRoot = root;
}
@Override
@@ -43,10 +43,10 @@ public class StreamGobbler extends Thread {
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

View File

@@ -3,25 +3,35 @@ package com.topjohnwu.magisk.utils;
import android.Manifest;
import android.app.Activity;
import android.app.DownloadManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
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.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.NotificationCompat;
import android.text.TextUtils;
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.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.List;
@@ -30,59 +40,50 @@ public class Utils {
public static boolean isDownloading = false;
public static boolean itemExist(String path) {
String command = "if [ -e " + path + " ]; then echo true; else echo false; fi";
List<String> ret = Shell.su(command);
private static final int MAGISK_UPDATE_NOTIFICATION_ID = 1;
private static final int APK_UPDATE_NOTIFICATION_ID = 2;
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 boolean commandExists(String s) {
String command = "if [ -z $(which " + s + ") ]; then echo false; else echo true; fi";
List<String> ret = Shell.sh(command);
return isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(0));
}
public static boolean 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";
List<String> ret = Shell.su(command);
return isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(0));
String command = "mkdir -p " + folder + " 2>/dev/null; touch " + path + " 2>/dev/null;";
shell.su_raw(command);
}
public static boolean removeItem(String path) {
String command = "rm -rf " + path + " 2>/dev/null; if [ -e " + path + " ]; then echo false; else echo true; fi";
List<String> ret = Shell.su(command);
return isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(0));
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) {
if (isDownloading)
return;
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
Toast.makeText(context, R.string.permissionNotGranted, Toast.LENGTH_LONG).show();
return;
}
File file = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/" + filename);
if ((!file.getParentFile().exists() && !file.getParentFile().mkdirs()) || (file.exists() && !file.delete())) {
if ((!file.getParentFile().exists() && !file.getParentFile().mkdirs())
|| (file.exists() && !file.delete())) {
Toast.makeText(context, R.string.permissionNotGranted, Toast.LENGTH_LONG).show();
return;
}
@@ -98,7 +99,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) {
@@ -107,21 +108,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);
}
@@ -144,12 +130,12 @@ public class Utils {
return (MagiskManager) context.getApplicationContext();
}
public static void checkSafetyNet(MagiskManager magiskManager) {
new SafetyNetHelper(magiskManager) {
public static void checkSafetyNet(FragmentActivity activity) {
new SafetyNetHelper(activity) {
@Override
public void handleResults(int i) {
magiskManager.SNCheckResult = i;
magiskManager.safetyNetDone.trigger();
public void handleResults(Result result) {
getMagiskManager(mActivity).SNCheckResult = result;
getMagiskManager(mActivity).safetyNetDone.trigger();
}
}.requestTest();
}
@@ -185,4 +171,60 @@ public class Utils {
Snackbar.LENGTH_LONG)
.setAction(R.string.ok, (v)->{}).show();
}
public static boolean checkNetworkStatus(Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
public static boolean checkBits(int bits, int... masks) {
for (int mask : masks) {
if ((bits & mask) == 0)
return false;
}
return true;
}
public static void showMagiskUpdate(MagiskManager magiskManager) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(magiskManager);
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);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(MAGISK_UPDATE_NOTIFICATION_ID,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) magiskManager.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(MAGISK_UPDATE_NOTIFICATION_ID, builder.build());
}
public static void showManagerUpdate(MagiskManager magiskManager) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(magiskManager);
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(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);
NotificationManager notificationManager =
(NotificationManager) magiskManager.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(APK_UPDATE_NOTIFICATION_ID, builder.build());
}
}

View File

@@ -1,13 +1,9 @@
package com.topjohnwu.magisk.utils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
@@ -18,8 +14,6 @@ public class WebService {
public final static int GET = 1;
public final static int POST = 2;
private static Map<String, List<String>> responseHeader;
/**
* Making web service call
*
@@ -27,11 +21,11 @@ public class WebService {
* @requestmethod - http request method
*/
public static String request(String url, int method) {
return request(url, method, null, null, false);
return request(url, method, null, true);
}
public static String request(String url, int method, boolean newline) {
return request(url, method, null, null, newline);
return request(url, method, null, newline);
}
/**
@@ -44,8 +38,7 @@ public class WebService {
* @newline - true to append a newline each line
*/
public static String request(String urlAddress, int method,
Map<String, String> params, Map<String, String> header,
boolean newline) {
Map<String, String> header, boolean newline) {
Logger.dev("WebService: Service call " + urlAddress);
URL url;
StringBuilder response = new StringBuilder();
@@ -69,32 +62,6 @@ public class WebService {
}
}
if (params != null) {
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
StringBuilder result = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (first) {
first = false;
} else {
result.append("&");
}
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
writer.write(result.toString());
writer.flush();
writer.close();
os.close();
}
int responseCode = conn.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
@@ -107,9 +74,13 @@ public class WebService {
response.append(line);
}
}
responseHeader = conn.getHeaderFields();
} else {
responseHeader = null;
if (header != null) {
header.clear();
for (Map.Entry<String, List<String>> entry : conn.getHeaderFields().entrySet()) {
List<String> l = entry.getValue();
header.put(entry.getKey(), l.get(l.size() - 1));
}
}
}
} catch (Exception e) {
e.printStackTrace();
@@ -118,8 +89,4 @@ public class WebService {
return response.toString();
}
public static Map<String, List<String>> getLastResponseHeader() {
return responseHeader;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,58 +3,17 @@
//
#include <jni.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "zipadjust.h"
JNIEXPORT jbyteArray JNICALL
Java_com_topjohnwu_magisk_utils_ZipUtils_zipAdjust___3BI(JNIEnv *env, jclass type,
jbyteArray jbytes, jint size) {
fin = (*env)->GetPrimitiveArrayCritical(env, jbytes, NULL);
insize = (size_t) size;
zipadjust(0);
(*env)->ReleasePrimitiveArrayCritical(env, jbytes, fin, 0);
jbyteArray ret = (*env)->NewByteArray(env, outsize);
(*env)->SetByteArrayRegion(env, ret, 0, outsize, (const jbyte*) fout);
free(fout);
return ret;
}
JNIEXPORT void JNICALL
Java_com_topjohnwu_magisk_utils_ZipUtils_zipAdjust__Ljava_lang_String_2(JNIEnv *env, jclass type, jstring name) {
const char *filename = (*env)->GetStringUTFChars(env, name, NULL);
int fd = open(filename, O_RDONLY);
if (fd < 0)
return;
Java_com_topjohnwu_magisk_utils_ZipUtils_zipAdjust(JNIEnv *env, jclass type, jstring filenameIn_,
jstring filenameOut_) {
const char *filenameIn = (*env)->GetStringUTFChars(env, filenameIn_, 0);
const char *filenameOut = (*env)->GetStringUTFChars(env, filenameOut_, 0);
// Load the file to memory
insize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
fin = malloc(insize);
read(fd, fin, insize);
zipadjust(0);
close(fd);
// Open file for output
fd = open(filename, O_WRONLY | O_TRUNC);
if (fd < 0)
return;
(*env)->ReleaseStringUTFChars(env, name, filename);
// Write back to file
lseek(fd, 0, SEEK_SET);
write(fd, fout, outsize);
close(fd);
free(fin);
free(fout);
// TODO
zipadjust(filenameIn, filenameOut, 0);
(*env)->ReleaseStringUTFChars(env, filenameIn_, filenameIn);
(*env)->ReleaseStringUTFChars(env, filenameOut_, filenameOut);
}

View File

@@ -1,10 +1,14 @@
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <zlib.h>
#include <unistd.h>
#include "zipadjust.h"
size_t insize = 0, outsize = 0, alloc = 0;
unsigned char *fin = NULL, *fout = NULL;
#ifndef O_BINARY
#define O_BINARY 0
#define O_TEXT 0
#endif
#pragma pack(1)
struct local_header_struct {
@@ -82,41 +86,43 @@ static int xerror(char* message) {
return 0;
}
static int xseekread(off_t offset, void* buf, size_t bytes) {
memcpy(buf, fin + offset, bytes);
static int xseekread(int fd, off_t offset, void* buf, size_t bytes) {
if (lseek(fd, offset, SEEK_SET) == (off_t)-1) return xerror("Seek failed");
if (read(fd, buf, bytes) != bytes) return xerror("Read failed");
return 1;
}
static int xseekwrite(off_t offset, const void* buf, size_t bytes) {
if (offset + bytes > outsize) outsize = offset + bytes;
if (outsize > alloc) {
fout = realloc(fout, outsize);
alloc = outsize;
}
memcpy(fout + offset, buf, bytes);
static int xseekwrite(int fd, off_t offset, void* buf, size_t bytes) {
if (lseek(fd, offset, SEEK_SET) == (off_t)-1) return xerror("Seek failed");
if (write(fd, buf, bytes) != bytes) return xerror("Write failed");
return 1;
}
static int xfilecopy(off_t offsetIn, off_t offsetOut, size_t bytes) {
unsigned int CHUNK = 256 * 1024;
unsigned char* buf = malloc(CHUNK);
static int xfilecopy(int fdIn, int fdOut, off_t offsetIn, off_t offsetOut, size_t bytes) {
if ((offsetIn != (off_t)-1) && (lseek(fdIn, offsetIn, SEEK_SET) == (off_t)-1)) return xerror("Seek failed");
if ((offsetOut != (off_t)-1) && (lseek(fdOut, offsetOut, SEEK_SET) == (off_t)-1)) return xerror("Seek failed");
int CHUNK = 256 * 1024;
void* buf = malloc(CHUNK);
if (buf == NULL) return xerror("malloc failed");
size_t left = bytes;
while (left > 0) {
size_t wanted = (left < CHUNK) ? left : CHUNK;
xseekread(offsetIn, buf, wanted);
xseekwrite(offsetOut, buf, wanted);
offsetIn += wanted;
offsetOut += wanted;
left -= wanted;
size_t r = read(fdIn, buf, wanted);
if (r <= 0) return xerror("Read failed");
if (write(fdOut, buf, r) != r) return xerror("Write failed");
left -= r;
}
free(buf);
return 1;
}
static int xdecompress(off_t offsetIn, off_t offsetOut, size_t bytes) {
unsigned int CHUNK = 256 * 1024;
static int xdecompress(int fdIn, int fdOut, off_t offsetIn, off_t offsetOut, size_t bytes) {
if ((offsetIn != (off_t)-1) && (lseek(fdIn, offsetIn, SEEK_SET) == (off_t)-1)) return xerror("Seek failed");
if ((offsetOut != (off_t)-1) && (lseek(fdOut, offsetOut, SEEK_SET) == (off_t)-1)) return xerror("Seek failed");
int CHUNK = 256 * 1024;
int ret;
unsigned have;
@@ -133,12 +139,9 @@ static int xdecompress(off_t offsetIn, off_t offsetOut, size_t bytes) {
if (ret != Z_OK) return xerror("ret != Z_OK");
do {
strm.avail_in = insize - offsetIn;
strm.avail_in = read(fdIn, in, CHUNK);
if (strm.avail_in == 0) break;
strm.avail_in = (strm.avail_in > CHUNK) ? CHUNK : strm.avail_in;
xseekread(offsetIn, in, strm.avail_in);
strm.next_in = in;
offsetIn += strm.avail_in;
do {
strm.avail_out = CHUNK;
@@ -156,8 +159,10 @@ static int xdecompress(off_t offsetIn, off_t offsetOut, size_t bytes) {
}
have = CHUNK - strm.avail_out;
xseekwrite(offsetOut, out, have);
offsetOut += have;
if (write(fdOut, out, have) != have) {
(void)inflateEnd(&strm);
return xerror("Write failed");
}
} while (strm.avail_out == 0);
} while (ret != Z_STREAM_END);
(void)inflateEnd(&strm);
@@ -165,9 +170,15 @@ static int xdecompress(off_t offsetIn, off_t offsetOut, size_t bytes) {
return ret == Z_STREAM_END ? 1 : 0;
}
int zipadjust(int decompress) {
int zipadjust(const char* filenameIn, const char* filenameOut, int decompress) {
int ok = 0;
int fin = open(filenameIn, O_RDONLY | O_BINARY);
if (fin > 0) {
unsigned int size = lseek(fin, 0, SEEK_END);
lseek(fin, 0, SEEK_SET);
LOGD("%d bytes\n", size);
char filename[1024];
central_footer_t central_footer;
@@ -176,18 +187,18 @@ int zipadjust(int decompress) {
uint32_t central_directory_out_size = 0;
int i;
for (i = insize - 4; i >= 0; i--) {
for (i = size - 4; i >= 0; i--) {
uint32_t magic = 0;
if (!xseekread(i, &magic, sizeof(uint32_t))) return 0;
if (!xseekread(fin, i, &magic, sizeof(uint32_t))) return 0;
if (magic == MAGIC_CENTRAL_FOOTER) {
LOGD("central footer @ %08X\n", i);
if (!xseekread(i, &central_footer, sizeof(central_footer_t))) return 0;
if (!xseekread(fin, i, &central_footer, sizeof(central_footer_t))) return 0;
central_header_t central_header;
if (!xseekread(central_footer.central_directory_offset, &central_header, sizeof(central_header_t))) return 0;
if (!xseekread(fin, central_footer.central_directory_offset, &central_header, sizeof(central_header_t))) return 0;
if ( central_header.signature == MAGIC_CENTRAL_HEADER ) {
central_directory_in_position = central_footer.central_directory_offset;
central_directory_in_size = insize - central_footer.central_directory_offset;
central_directory_in_size = size - central_footer.central_directory_offset;
LOGD("central header @ %08X (%d)\n", central_footer.central_directory_offset, central_footer.central_directory_size);
break;
}
@@ -198,13 +209,12 @@ int zipadjust(int decompress) {
unsigned char* central_directory_in = (unsigned char*)malloc(central_directory_in_size);
unsigned char* central_directory_out = (unsigned char*)malloc(central_directory_in_size);
if (!xseekread(central_directory_in_position, central_directory_in, central_directory_in_size)) return 0;
if (!xseekread(fin, central_directory_in_position, central_directory_in, central_directory_in_size)) return 0;
memset(central_directory_out, 0, central_directory_in_size);
fout = (unsigned char*) malloc(insize);
alloc = insize;
unlink(filenameOut);
int fout = open(filenameOut, O_CREAT | O_WRONLY | O_BINARY, 0644);
if (fout > 0) {
uintptr_t central_directory_in_index = 0;
uintptr_t central_directory_out_index = 0;
@@ -222,7 +232,7 @@ int zipadjust(int decompress) {
LOGD("%s (%d --> %d) [%08X] (%d)\n", filename, central_header->size_uncompressed, central_header->size_compressed, central_header->crc32, central_header->length_extra + central_header->length_comment);
local_header_t local_header;
if (!xseekread(central_header->offset, &local_header, sizeof(local_header_t))) return 0;
if (!xseekread(fin, central_header->offset, &local_header, sizeof(local_header_t))) return 0;
// save and update to next index before we clobber the data
uint16_t compression_method_old = central_header->compression_method;
@@ -247,15 +257,15 @@ int zipadjust(int decompress) {
local_header.size_compressed = central_header->size_compressed;
local_header.length_extra = 0;
if (!xseekwrite(out_index, &local_header, sizeof(local_header_t))) return 0;
if (!xseekwrite(fout, out_index, &local_header, sizeof(local_header_t))) return 0;
out_index += sizeof(local_header_t);
if (!xseekwrite(out_index, &filename[0], central_header->length_filename)) return 0;
if (!xseekwrite(fout, out_index, &filename[0], central_header->length_filename)) return 0;
out_index += central_header->length_filename;
if (decompress && (compression_method_old == 8)) {
if (!xdecompress(offset_old + sizeof(local_header_t) + central_header->length_filename + length_extra_old, out_index, size_compressed_old)) return 0;
if (!xdecompress(fin, fout, offset_old + sizeof(local_header_t) + central_header->length_filename + length_extra_old, out_index, size_compressed_old)) return 0;
} else {
if (!xfilecopy(offset_old + sizeof(local_header_t) + central_header->length_filename + length_extra_old, out_index, size_compressed_old)) return 0;
if (!xfilecopy(fin, fout, offset_old + sizeof(local_header_t) + central_header->length_filename + length_extra_old, out_index, size_compressed_old)) return 0;
}
out_index += local_header.size_compressed;
@@ -267,16 +277,21 @@ int zipadjust(int decompress) {
central_footer.central_directory_size = central_directory_out_size;
central_footer.central_directory_offset = out_index;
central_footer.length_comment = 0;
if (!xseekwrite(out_index, central_directory_out, central_directory_out_size)) return 0;
if (!xseekwrite(fout, out_index, central_directory_out, central_directory_out_size)) return 0;
out_index += central_directory_out_size;
if (!xseekwrite(out_index, &central_footer, sizeof(central_footer_t))) return 0;
if (!xseekwrite(fout, out_index, &central_footer, sizeof(central_footer_t))) return 0;
LOGD("central header @ %08X (%d)\n", central_footer.central_directory_offset, central_footer.central_directory_size);
LOGD("central footer @ %08X\n", out_index);
close(fout);
ok = 1;
}
free(central_directory_in);
free(central_directory_out);
close(fin);
}
return ok;
}

View File

@@ -3,10 +3,7 @@
#include <android/log.h>
int zipadjust(int decompress);
extern size_t insize, outsize, alloc;
extern unsigned char *fin, *fout;
int zipadjust(const char* filenameIn, const char* filenameOut, int decompress);
#define LOG_TAG "zipadjust"

Binary file not shown.

Binary file not shown.

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

View File

@@ -1,251 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="@+id/install_info_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="6dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">
<TextView
android:id="@+id/install_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="5dp"
android:textStyle="bold" />
<TextView
android:id="@+id/current_version_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="5dp"
android:textStyle="bold" />
</LinearLayout>
</android.support.v7.widget.CardView>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:maxWidth="400dp"
android:minWidth="400dp">
<android.support.v7.widget.CardView
android:id="@+id/bootimage_card"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="6dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true"
android:layout_width="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:paddingBottom="10dp"
android:text="@string/boot_image_title"
android:textStyle="bold" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="15dp"
android:layout_marginStart="15dp">
<Spinner
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/block_spinner"
android:layout_weight="1" />
<Button
android:text="@string/detect_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/detect_bootimage"/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/install_option_card"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="6dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true"
android:layout_width="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:paddingBottom="10dp"
android:text="@string/advanced_settings_title"
android:textStyle="bold" />
<CheckBox
android:text="@string/keep_force_encryption"
android:id="@+id/keep_force_enc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="25dp"
android:layout_marginStart="25dp" />
<CheckBox
android:text="@string/keep_dm_verity"
android:id="@+id/keep_verity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="25dp"
android:layout_marginStart="25dp" />
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/install_button"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="6dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true"
android:layout_width="match_parent"
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_marginEnd="25dp"
android:layout_marginStart="25dp">
<ImageView
android:layout_width="50dp"
android:layout_height="wrap_content"
app:srcCompat="@mipmap/ic_launcher"
android:id="@+id/imageView"
android:layout_weight="0"
android:layout_marginEnd="20dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/install_text"
android:ems="10"
android:gravity="center"
android:layout_weight="1"
android:textStyle="bold"
android:textAllCaps="false"
android:textSize="20sp"
android:fontFamily="sans-serif" />
<FrameLayout
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_weight="0"
android:layout_marginStart="20dp">
</FrameLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/uninstall_button"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="6dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true"
android:layout_width="match_parent"
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/uninstall"
android:ems="10"
android:gravity="center"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:textStyle="bold"
android:textAllCaps="false"
android:textSize="20sp"
android:fontFamily="sans-serif" />
</android.support.v7.widget.CardView>
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

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

View File

@@ -20,8 +20,10 @@
android:id="@+id/txtLog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:padding="8dp"
android:textIsSelectable="true"/>
android:textIsSelectable="true"
android:textSize="10sp" />
<ProgressBar
android:id="@+id/progressBar"

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fab="http://schemas.android.com/apk/res-auto"
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="fill_parent"
@@ -22,7 +22,8 @@
android:layout_height="match_parent"
android:clipToPadding="false"
android:dividerHeight="@dimen/card_divider_space"
fab:layoutManager="android.support.v7.widget.LinearLayoutManager" />
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
<TextView
android:id="@+id/empty_rv"
@@ -36,39 +37,16 @@
android:textStyle="italic"
android:visibility="gone" />
<com.github.clans.fab.FloatingActionMenu
android:id="@+id/fabmenu"
android:layout_width="500dp"
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginEnd="113dp"
android:layout_marginBottom="10dp"
fab:layout_behavior=".utils.FABBehavior"
fab:menu_fab_size="normal"
fab:menu_showShadow="true"
fab:menu_shadowColor="#66000000"
fab:menu_shadowRadius="4dp"
fab:menu_shadowXOffset="1dp"
fab:menu_shadowYOffset="3dp"
fab:menu_colorNormal="?android:colorAccent"
fab:menu_colorPressed="?attr/colorAccentFallback"
fab:menu_animationDelayPerItem="50"
fab:menu_icon="@drawable/ic_add"
fab:menu_buttonSpacing="0dp"
fab:menu_labels_position="left" >
<com.github.clans.fab.FloatingActionButton
android:id="@+id/fab"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_archive"
fab:fab_colorNormal="?android:colorAccent"
fab:fab_colorPressed="?attr/colorAccentFallback"
fab:fab_size="mini"
fab:fab_label="@string/fab_flash_zip" />
</com.github.clans.fab.FloatingActionMenu>
android:layout_margin="@dimen/fab_padding"
android:elevation="6dp"
android:src="@drawable/ic_add"
tools:fabSize="normal"
tools:pressedTranslationZ="12dp" />
</android.support.design.widget.CoordinatorLayout>

View File

@@ -1,196 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="@+id/magiskStatusView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="6dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/magisk_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold"/>
<FrameLayout
android:id="@+id/magisk_status_container"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="?android:attr/selectableItemBackground"
android:foregroundGravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/magisk_status_icon"
android:layout_width="84dp"
android:layout_height="84dp"
android:layout_gravity="center"/>
<ProgressBar
android:id="@+id/magisk_check_updates_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
<TextView
android:id="@+id/magisk_update_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold"
android:text="@string/checking_for_updates" />
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/rootStatusView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="6dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/root_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold"/>
<FrameLayout
android:id="@+id/root_status_container"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="?android:attr/selectableItemBackground"
android:foregroundGravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/root_status_icon"
android:layout_width="84dp"
android:layout_height="84dp"
android:layout_gravity="center" />
</FrameLayout>
<TextView
android:id="@+id/root_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/safetyNetView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="6dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:id="@+id/safetyNet_container"
android:layout_width="match_parent"
android:layout_height="100dp"
android:foregroundGravity="center"
android:orientation="vertical"
android:background="@color/grey500">
<ImageView
android:id="@+id/safetyNet_icon"
android:layout_width="84dp"
android:layout_height="84dp"
android:layout_gravity="center"
android:src="@drawable/ic_safetynet"/>
<ProgressBar
android:id="@+id/safetyNet_check_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"/>
</FrameLayout>
<TextView
android:id="@+id/safetyNet_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold"
android:text="@string/safetyNet_check_text" />
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>

View 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" />

View File

@@ -6,15 +6,9 @@
android:id="@+id/main_group">
<item
android:id="@+id/status"
android:icon="@drawable/ic_device_information"
android:title="@string/status"/>
<item
android:id="@+id/install"
android:id="@+id/magisk"
android:icon="@drawable/ic_magisk"
android:title="@string/install"
android:visible="false"/>
android:title="@string/magisk"/>
<item
android:id="@+id/superuser"

View File

@@ -6,18 +6,52 @@
<string name="navigation_drawer_close">إغلاق درج التنقل</string>
<string name="modules">الإضافات</string>
<string name="downloads">التنزيلات</string>
<string name="superuser">Superuser</string>
<string name="log">السجل</string>
<string name="settings">الإعدادات</string>
<string name="status">الحالة</string>
<string name="install">التثبيت</string>
<!--Magisk Fragment-->
<!--Status Fragment-->
<string name="magisk_version">المثبت Magisk v%1$s</string>
<string name="magisk_version_error">هل قمت بتثبيت Magisk؟</string>
<string name="magisk_version_core_only">المثبت Magisk v%1$s (الوضع الأساسي فقط)</string>
<string name="magisk_version_error">Magisk غير مثبت</string>
<string name="magisk_update_available">Magisk v%1$.1f تحديث!</string>
<string name="cannot_check_updates">لا يمكن التحقق من التحديثات</string>
<string name="up_to_date">أحدث إصدار من %1$s مثبت</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="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="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، لا يوجد إنترنت؟</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>
<!--Root Fragment-->
<!--Install Fragment-->
<string name="auto_detect">(تلقائي) %1$s</string>
<string name="cannot_auto_detect">(لا يمكن الكشف التلقائي)</string>
<string name="boot_image_title">موقع ملف الإقلاع</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>
<!--Module Fragment-->
<string name="no_info_provided">(لم يتم توفير أي معلومات)</string>
@@ -27,7 +61,7 @@
<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="author">انشئ بواسطة %1$s</string>
<string name="fab_flash_zip">تثبيت الملف المضغوط للإضافة</string>
<!--Repo Fragment-->
@@ -58,61 +92,119 @@
<!--Toasts, Dialogs-->
<string name="permissionNotGranted">أن هذه الميزة لا تعمل دون الحصول على إذن الكتابة على التخزين الخارجي.</string>
<string name="no_thanks">لا شكراً</string>
<string name="yes">نعم</string>
<string name="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_install">التنزيل &amp; التثبيت</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="reboot_title">التثبيت نجح!</string>
<string name="reboot_msg">هل تريد إعادة التشغيل الآن؟</string>
<string name="reboot">إعادة التشغيل</string>
<string name="zip_install_progress_title">تثبيت</string>
<string name="copying_msg">نسخ الملف المضغوط إلى دليل مؤقت</string>
<string name="zip_install_progress_title">التثبيت</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>
<!--URL Templates-->
<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, تم التعامل معها بالفعل من قبل MagiskHide بشكل افتراضي</string>
<string name="start_magiskhide">بدءا إخفاء Magisk …</string>
<string name="no_magisksu_title">لا تستخدم MagiskSU!</string>
<string name="no_magisksu_msg">غير مروت بأستخدام MagiskSU, إستخدام Magisk أخفاء لوحده قد لا يكون كافياً!\nانه غير معتمدة رسمياً, وأنت بحاجه إلى أدوات اضافيه (مثلاً suhide) لتخطي SafetyNet.</string>
<string name="understand">أنا أفهم</string>
<string name="process_error">خطأ في العملية</string>
<string name="internal_storage">يتم تخزين الملف المضغوط في:\n[التخزين الداخلي]%1$s</string>
<string name="zip_process_title">معالجة</string>
<string name="manual_boot_image">يرجى تحديد ملف الإقلاع يدوياً!</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_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_magiskhide_summary">إخفاء Magisk من مختلف حالات الإكتشاف</string>
<string name="settings_busybox_title">تمكين BusyBox</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">ربط تحميل Magisk\'s المدمج في busybox إلى xbin</string>
<string name="settings_hosts_title">تمكين المضيفين(الهوست) لـ systemless</string>
<string name="settings_hosts_summary">Systemless يدعم تطبيقات حجب الإعلانات</string>
<string name="settings_development_category">التطوير</string>
<string name="settings_su_app_adb">التطبيقات و ADB</string>
<string name="settings_su_app">التطبيقات فقط</string>
<string name="settings_su_adb">ADB فقط</string>
<string name="settings_su_disable">معطل</string>
<string name="settings_su_request_10">10 ثواني</string>
<string name="settings_su_request_20">20 ثانية</string>
<string name="settings_su_request_30">30 ثانية</string>
<string name="settings_su_request_60">60 ثانية</string>
<string name="superuser_access">Superuser صلاحيات</string>
<string name="auto_response">استجابة تلقائية</string>
<string name="request_timeout">مهلة الطلب</string>
<string name="superuser_notification">Superuser إشعارات</string>
<string name="request_timeout_summary">%1$s ثانية</string>
<string name="multiuser_mode">وضع تعدد المستخدمين</string>
<string name="settings_owner_only">مالك الجهاز فقط</string>
<string name="settings_owner_manage">إدارة مالك الجهاز</string>
<string name="settings_user_independent">مستخدم مستقل</string>
<string name="owner_only_summary">المالك فقط لديه صلاحيات الروت</string>
<string name="owner_manage_summary">يمكن للمالك فقط إدارة صلاحيات الروت وتلقي مطالبات الطلب</string>
<string name="user_indepenent_summary">كل مستخدم لديه قواعد روت منفصلة خاصة به</string>
<string name="multiuser_hint_owner_request">تم إرسال طلب إلى مالك الجهاز. يرجى التبديل إلى المالك ومنح الإذن</string>
<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_reboot_toast">إعادة التشغيل لتطبيق الإعدادات</string>
<string name="auto_detect">(تلقائي) %1$s</string>
<string name="checking_for_updates">البحث عن تحديثات…</string>
<string name="install">التثبيت</string>
<string name="not_rooted">غير مروت</string>
<string name="proper_root">مروت فعلاً</string>
<string name="advanced_settings_title">إعدادات متقدمة</string>
<string name="boot_image_title">موقع ملف الإقلاع</string>
<string name="checking_safetyNet_status">التحقق من حالة SafetyNet...</string>
<string name="copying_msg">نسخ الملف المضغوط إلى دليل مؤقت</string>
<string name="detect_button">تحقق</string>
<string name="downloading_toast">جاري التنزيل %1$s</string>
<string name="install_magisk_title">تثبيت Magisk الإصدار: %1$s</string>
<string name="keep_force_encryption">إبقاء التشفير القوى</string>
<string name="keep_dm_verity">إبقاء dm-verity</string>
<string name="root_error">مروت لكن لا يوجد إذن الروت، غير مسموح به؟</string>
<string name="root_info_warning">وظائف محدودة إلى حد كبير</string>
<string name="safetyNet_error">تعذر التحقق من SafetyNet، لا يوجد إنترنت؟</string>
<string name="safetyNet_pass">SafetyNet تخطى</string>
<string name="safetyNet_fail">فشل SafetyNet: عدم تطابق التشكيل الجانبي CTS</string>
<string name="status">الحالة</string>
<!--Superuser-->
<string name="su_request_title">Superuser طلبات</string>
<string name="deny_with_str">رفض%1$s</string>
<string name="deny">رفض</string>
<string name="prompt">طلب</string>
<string name="grant">سماح</string>
<string name="su_warning">منح حق الوصول الكامل إلى جهازك.\nرفض إذا كنت غير متأكد!</string>
<string name="forever">للابد</string>
<string name="once">مره</string>
<string name="tenmin">10 دقائق</string>
<string name="twentymin">20 دقائق</string>
<string name="thirtymin">30 دقائق</string>
<string name="sixtymin">60 دقائق</string>
<string name="su_allow_toast">%1$s يتم منح صلاحيات Superuser</string>
<string name="su_deny_toast">%1$s يتم رفض صلاحيات Superuser</string>
<string name="no_apps_found">لا توجد تطبيقات</string>
<string name="su_snack_grant">Superuser الصلاحيات لـ %1$s تم منحها</string>
<string name="su_snack_deny">Superuser الصلاحيات لـ %1$s تم رفضها</string>
<string name="su_snack_notif_on">الإشعارات لـ %1$s تم تفعيلها</string>
<string name="su_snack_notif_off">الإشعارات لـ %1$s تم تعطيلها</string>
<string name="su_snack_log_on">السجلات لـ %1$s تم تفعيلها</string>
<string name="su_snack_log_off">السجلات لـ %1$s تم تعطيلها</string>
<string name="su_snack_revoke">%1$s الصلاحيات سحبت</string>
<string name="su_revoke_title">سحب؟</string>
<string name="su_revoke_msg">تأكيد لسحب صلاحيات %1$s ?</string>
<string name="toast">نخب</string>
<string name="none">بدون</string>
<!--Superuser logs-->
<string name="pid">PID:\u0020</string>
<string name="target_uid">الهدف UID:\u0020</string>
<string name="command">الأمر:\u0020</string>
</resources>

View File

@@ -17,7 +17,7 @@
<string name="magisk_version_error">Magisk není nainstalován</string>
<string name="checking_for_updates">Kontrola aktualizací…</string>
<string name="magisk_update_available">Magisk v%1$.1f je dostupný!</string>
<string name="magisk_update_available">Magisk v%1$s je dostupný!</string>
<string name="cannot_check_updates">Nelze zkontrolovat aktualizace. Jste připojeni k Internetu?</string>
<string name="up_to_date">Poslední verze z %1$s nainstalovaných</string>
<string name="root_error">Zařízení s rootem ale chybí root povolení, máte jej zpřístupněno?</string>
@@ -27,7 +27,7 @@
<string name="checking_safetyNet_status">Kontrola stavu SafetyNet…</string>
<string name="safetyNet_connection_failed">Nelze se spojit s Google API</string>
<string name="safetyNet_connection_suspended">Spojení s Google API bylo přerušeno</string>
<string name="safetyNet_error">Nelze zkontrolovat SafetyNet. Jste připojeni k Internetu?</string>
<string name="safetyNet_no_response">Nelze zkontrolovat SafetyNet. Jste připojeni k Internetu?</string>
<string name="safetyNet_fail">SafetyNet dopadl neúspěšně: CTS profile mismatch</string>
<string name="safetyNet_pass">SafetyNet Schváleno</string>
<string name="root_info_warning">Funkčnost omezena</string>
@@ -190,6 +190,5 @@
<string name="pid">PID:\u0020</string>
<string name="target_uid">Cílové UID:\u0020</string>
<string name="command">Příkaz:\u0020</string>
<string name="settings_core_only_summary"></string>
</resources>

View File

@@ -8,19 +8,20 @@
<string name="navigation_drawer_close">Navigationsmenü schließen</string>
<string name="modules">Module</string>
<string name="downloads">Download</string>
<string name="downloads">Downloads</string>
<string name="superuser">Superuser</string>
<string name="log">Log</string>
<string name="settings">Einstellungen</string>
<string name="status">Übersicht</string>
<string name="status">Status</string>
<string name="install">Installieren</string>
<!--Status Fragment-->
<string name="magisk_version">Magisk %1$s ist installiert</string>
<string name="magisk_version_core_only">Magisk %1$s ist installiert (nur Kernfunktionen)</string>
<string name="magisk_version_error">Magisk ist nicht installiert</string>
<string name="checking_for_updates">Suche nach Updates…</string>
<string name="magisk_update_available">Magisk %1$.1f ist verfügbar!</string>
<string name="magisk_update_available">Magisk %1$s ist verfügbar!</string>
<string name="cannot_check_updates">Updatesuche fehlgeschlagen.\nIst eine Internetverbindung verfügbar?</string>
<string name="up_to_date">Die neueste Version von %1$s ist bereits installiert</string>
<string name="root_error">Gerootet, aber keine root-Rechte. Wurde der root-Zugriff verweigert?</string>
@@ -28,11 +29,15 @@
<string name="proper_root">Ordnungsgemäß gerootet</string>
<string name="safetyNet_check_text">SafetyNet-Status abfragen</string>
<string name="checking_safetyNet_status">Prüfe SafetyNet-Status…</string>
<string name="safetyNet_check_success">SafetyNet-Test erfolgreich</string>
<string name="safetyNet_connection_failed">Verbindung zur Google-API fehlgeschlagen</string>
<string name="safetyNet_connection_suspended">Verbindung zur Google-API wurde ausgesetzt</string>
<string name="safetyNet_error">SafetyNet-Status konnte nicht geprüft werden. Ist eine Internetverbindung verfügbar?</string>
<string name="safetyNet_no_response">SafetyNet-Status konnte nicht geprüft werden. Ist eine Internetverbindung verfügbar?</string>
<string name="safetyNet_fail">SafetyNet nicht bestanden: \"CTS profile mismatch\"</string>
<string name="safetyNet_pass">SafetyNet bestanden</string>
<string name="safetyNet_network_loss">Netzwerkverbindung verloren</string>
<string name="safetyNet_service_disconnected">Der Dienst wurde beendet</string>
<string name="safetyNet_res_invalid">Die Antwort ist ungültig</string>
<string name="root_info_warning">Funktionalität stark eingeschränkt</string>
<!--Install Fragment-->
@@ -125,6 +130,8 @@
<string name="internal_storage">Die zip-Datei ist gespeichert unter:\n[Interner Speicher]%1$s</string>
<string name="zip_process_title">Verarbeite</string>
<string name="manual_boot_image">Bitte Boot-Image auswählen!</string>
<string name="manager_update_title">Update für Magisk Manager verfügbar!</string>
<string name="manager_download_install">Herunterladen und installieren</string>
<!--Settings Activity -->
<string name="settings_general_category">Allgemein</string>
@@ -135,6 +142,8 @@
<string name="settings_clear_cache_title">Repo-Cache löschen</string>
<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 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>
@@ -154,6 +163,25 @@
<string name="request_timeout">Zeitlimit für Anfrage</string>
<string name="superuser_notification">Superuser-Benachrichtigung</string>
<string name="request_timeout_summary">%1$s Sekunden</string>
<string name="settings_su_reauth_title">Nach Updates erneut authentifizieren</string>
<string name="settings_su_reauth_summary">Superuser-Zugriff nach App-Updates erneut abfragen</string>
<string name="multiuser_mode">Mehrbenutzermodus</string>
<string name="settings_owner_only">Nur der Gerätebesitzer</string>
<string name="settings_owner_manage">Durch Gerätebesitzer verwaltet</string>
<string name="settings_user_independent">User Independent</string>
<string name="owner_only_summary">Nur der Besitzer hat root-Zugriff</string>
<string name="owner_manage_summary">Nur der Besitzer verwaltet den root-Zugriff und erhält Zugriffs-Anfragen</string>
<string name="user_indepenent_summary">Jeder Nutzer hat seine eingenen root-Regeln</string>
<string name="multiuser_hint_owner_request">Eine Anfrage wurde an den Gerätebesitzer gesendet. Bitte wechsle zum Bersitzerkonto und gewähre die Rechte</string>
<string name="mount_namespace_mode">Namensraum-Modus</string>
<string name="settings_ns_global">Globaler Namensraum</string>
<string name="settings_ns_requester">Geerbter Namensraum</string>
<string name="settings_ns_isolate">Isolierter Namensraum</string>
<string name="global_summary">Alle root-Sitzungen benutzen den global angelegten Namensraum</string>
<string name="requester_summary">Root-Sitzungen erben den Namensraum des Abfragenden</string>
<string name="isolate_summary">Jede root-Sitzung hat ihren isolierten Namensraum</string>
<string name="settings_development_category">Entwickler</string>
<string name="settings_developer_logging_title">Erweiterte Fehlerprotokolle</string>

View File

@@ -0,0 +1,220 @@
<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>
<!--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">Κατέβασμα &amp; Εγκατάσταση</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>
<!--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_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>

View File

@@ -17,7 +17,7 @@
<string name="magisk_version_error">Magisk no está instalado</string>
<string name="checking_for_updates">Comprobando actualizaciones…</string>
<string name="magisk_update_available">¡Disponible Magisk v%1$.1f!</string>
<string name="magisk_update_available">¡Disponible Magisk v%1$s!</string>
<string name="cannot_check_updates">No se pueden comprobar actualizaciones ¿No tiene internet?</string>
<string name="up_to_date">Última versión de %1$s instalada</string>
<string name="root_error">Rooteado pero sin permiso root, ¿No lo permitiste?</string>
@@ -27,14 +27,14 @@
<string name="checking_safetyNet_status">Comprobando estado de SafetyNet…</string>
<string name="safetyNet_connection_failed">No puede conectar con la API de Google</string>
<string name="safetyNet_connection_suspended">La conexión con la API de Google API fue suspendida</string>
<string name="safetyNet_error">No puede comprobar SafetyNet, ¿No tiene internet?</string>
<string name="safetyNet_fail">SafetyNet falló: No coincide el perfil CTS</string>
<string name="safetyNet_pass">SafetyNet pasó</string>
<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="root_info_warning">Funcionalidad enormemente limitada</string>
<!--Install Fragment-->
<string name="auto_detect">(Auto) %1$s</string>
<string name="boot_image_title">Ubicación de imagen boot</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>
<string name="keep_force_encryption">Mantener cifrado forzado</string>
@@ -49,9 +49,9 @@
<string name="no_modules_found">No se han encontrado módulos</string>
<string name="update_file_created">El módulo se actualizará en el siguiente reinicio</string>
<string name="remove_file_created">El módulo se eliminará en el siguiente reinicio</string>
<string name="remove_file_deleted">El módulo no se eliminirá en el siguiente reinicio</string>
<string name="remove_file_deleted">El módulo no se eliminará en el siguiente reinicio</string>
<string name="disable_file_created">El módulo se desactivará en el siguiente reinicio</string>
<string name="disable_file_removed">El móodulo se activará en el siguiente reinicio</string>
<string name="disable_file_removed">El módulo se activará en el siguiente reinicio</string>
<string name="author">Creado por %1$s</string>
<string name="fab_flash_zip">Flashear el zip del módulo</string>
@@ -64,7 +64,7 @@
<string name="menuSaveToSd">Guardar en la SD</string>
<string name="menuReload">Recargar</string>
<string name="menuClearLog">Limpiar registro ahora</string>
<string name="logs_cleared">Registro Limpiado correctamente</string>
<string name="logs_cleared">Registro limpiado correctamente</string>
<string name="log_is_empty">El registro está vacio</string>
<string name="logs_save_failed">No se ha podido escribir el registro en la tarjeta SD:</string>
@@ -73,7 +73,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"><![CDATA[Gawenda, netizen, <a href="https://github.com/DeicPro">Deiki</a>]]></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>
@@ -83,8 +83,8 @@
<!--Toasts, Dialogs-->
<string name="permissionNotGranted">Esta opción no funcionará sin permiso de escritura en la memoria externa.</string>
<string name="no_thanks">No gracias</string>
<string name="yes">Si</string>
<string name="ok">Vale</string>
<string name="yes">Sí</string>
<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>
@@ -113,21 +113,23 @@
<string name="start_magiskhide">Iniciando MagiskHide …</string>
<string name="no_magisksu_title">¡No está usando MagiskSU!</string>
<string name="no_magisksu_msg">No estás rooteado con MagiskSU, ¡Usando MagiskHide por si mismo podría no ser suficiente!\nNo está oficialmente soportado, y necesitaria herramientas adiccionales (ej. suhide) para pasar Safety Net.</string>
<string name="understand">Entiendo</string>
<string name="understand">Entendido</string>
<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="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="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,6 +146,25 @@
<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>
@@ -154,7 +175,7 @@
<!--Superuser-->
<string name="su_request_title">Petición de superusuario</string>
<string name="deny_with_str">Denegar%1$s</string>
<string name="deny">Denegrar</string>
<string name="deny">Denegar</string>
<string name="prompt">Preguntar</string>
<string name="grant">Permitir</string>
<string name="su_warning">Permite acceso total a tu dispositivo.\n¡Denegar si no está seguro!</string>
@@ -169,13 +190,13 @@
<string name="no_apps_found">No se encontraron aplicaciones</string>
<string name="su_snack_grant">Derechos de superusuario para %1$s permitidos</string>
<string name="su_snack_deny">Derechos de superusuario para %1$s denegados</string>
<string name="su_snack_notif_on">Noticiaciones de %1$s habilitadas</string>
<string name="su_snack_notif_on">Notificaciones de %1$s habilitadas</string>
<string name="su_snack_notif_off">Notificaciones de %1$s deshabilitadas</string>
<string name="su_snack_log_on">Registros de %1$s habilitados</string>
<string name="su_snack_log_off">Registros de %1$s deshabilitados</string>
<string name="su_snack_revoke">Anulados derechos de %1$s</string>
<string name="su_revoke_title">¿Anular?</string>
<string name="su_revoke_msg">¿Confirmar para anular derechos de %1$s?</string>
<string name="su_revoke_title">¿Revocar?</string>
<string name="su_revoke_msg">¿Confirmar para revocar derechos de %1$s?</string>
<string name="toast">Aviso</string>
<string name="none">Nada</string>

View File

@@ -15,7 +15,7 @@
<string name="magisk_version_core_only">Magisk v%1$s installée (Mode Core uniquement)</string>
<string name="magisk_version_error">Magisk non installé</string>
<string name="checking_for_updates">Vérification de mises à jour…</string>
<string name="magisk_update_available">Magisk v%1$.1f disponible !</string>
<string name="magisk_update_available">Magisk v%1$s disponible !</string>
<string name="cannot_check_updates">Impossible de vérifier les mises à jour, pas d\'Internet ?</string>
<string name="up_to_date">Dernière version %1$s installée</string>
<string name="root_error">Rooté mais aucune permission root, non acceptée ?</string>
@@ -25,7 +25,7 @@
<string name="checking_safetyNet_status">Vérification de l\'état de SafetyNet…</string>
<string name="safetyNet_connection_failed">Impossible de se connecter à l\'API Google</string>
<string name="safetyNet_connection_suspended">La connexion à l\'API Google a été suspendue</string>
<string name="safetyNet_error">Impossible de contrôler SafetyNet, pas d\'Internet?</string>
<string name="safetyNet_no_response">Impossible de contrôler SafetyNet, pas d\'Internet?</string>
<string name="safetyNet_fail">Échec SafetyNet: erreur de profil CTS</string>
<string name="safetyNet_pass">SafetyNet réussi</string>
<string name="root_info_warning">Fonctionnalités largement limitées</string>
@@ -123,10 +123,10 @@
<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">Relier le busybox de Magisk à xbin</string>
<string name="settings_busybox_summary">Monter le busybox de Magisk sur xbin</string>
<string name="settings_hosts_title">Hosts systemless</string>
<string name="settings_hosts_summary">Support hosts systemless pour les applications type Adblock</string>
<string name="settings_su_app_adb">Applications et ADB</string>

View File

@@ -2,55 +2,59 @@
<!--Universal-->
<!--Welcome Activity-->
<string name="navigation_drawer_open">Apri drawer di navigazione</string>
<string name="navigation_drawer_close">Chiudi drawer di navigazione</string>
<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="downloads">Downloads</string>
<string name="log">Log</string>
<string name="settings">Impostazioni</string>
<string name="downloads">Download</string>
<string name="superuser">Superuser</string>
<string name="log">Registro eventi</string>
<string name="settings">Impostazioni</string>
<string name="status">Stato</string>
<string name="install">Installa</string>
<!--Status Fragment-->
<string name="magisk_version">Versione Magisk: v%1$s</string>
<string name="magisk_version_error">Hai installato Magisk?</string>
<string name="checking_for_updates">Controlla aggiornamenti…</string>
<string name="magisk_update_available">Magisk v%1$.1f update!</string>
<string name="magisk_version_core_only">Versione Magisk v%1$s (modo core)</string>
<string name="magisk_version_error">Magisk non installato</string>
<string name="checking_for_updates">Controllo aggiornamenti…</string>
<string name="magisk_update_available">È disponibile Magisk v%1$s!</string>
<string name="cannot_check_updates">Impossibile controllare aggiornamenti</string>
<string name="up_to_date">L\'ultima versione di %1$s è installata</string>
<string name="root_error">Rootato ma senza permessi, non autorizzato?</string>
<string name="up_to_date">La versione di %1$s è aggiornata</string>
<string name="root_error">Rootato ma senza permessi. Non sei autorizzato?</string>
<string name="not_rooted">Non rootato</string>
<string name="proper_root">Rootato correttamente</string>
<string name="safetyNet_check_text">Tap per avviare controllo SafetyNet</string>
<string name="checking_safetyNet_status">Controllo SafetyNet</string>
<string name="safetyNet_check_text">Tocca per avviare controllo SafetyNet</string>
<string name="checking_safetyNet_status">Controllo stato SafetyNet</string>
<string name="safetyNet_check_success">Controllo SafetyNet OK</string>
<string name="safetyNet_connection_failed">Impossibile collegarsi alle API Google</string>
<string name="safetyNet_connection_suspended">Connessione alle API Google sospesa</string>
<string name="safetyNet_error">Impossibile controllare SafetyNet, no Internet?</string>
<string name="safetyNet_fail">Errore SafetyNet: il profilo CTS non corrisponde</string>
<string name="safetyNet_pass">SafetyNet corretto</string>
<string name="safetyNet_no_response">Impossibile controllare SafetyNet. Nessuna connessione internet?</string>
<string name="safetyNet_fail">Errore SafetyNet. Il profilo CTS non corrisponde</string>
<string name="safetyNet_pass">Controllo SafetyNet OK</string>
<string name="safetyNet_network_loss">persa conenssioen di rete</string>
<string name="safetyNet_service_disconnected">Ils ervizio è stato terminato</string>
<string name="safetyNet_res_invalid">La risposta non è valida</string>
<string name="root_info_warning">Funzionalità molto limitata</string>
<!--Install Fragment-->
<string name="auto_detect">(Auto) %1$s</string>
<string name="cannot_auto_detect">(Cannot auto detect)</string>
<string name="boot_image_title">Immagine Boot</string>
<string name="detect_button">Identifica</string>
<string name="advanced_settings_title">Impostazioni Avanzate</string>
<string name="auto_detect">%1$s (auto)</string>
<string name="cannot_auto_detect">(impossibile rilevare automaticamente)</string>
<string name="boot_image_title">Percorso immagine boot</string>
<string name="detect_button">Rileva</string>
<string name="advanced_settings_title">Impostazioni avanzate</string>
<string name="keep_force_encryption">Mantieni crittografia forzata</string>
<string name="keep_dm_verity">Mantieni dm-verity</string>
<string name="current_magisk_title">Versione Magisk installata: %1$s</string>
<string name="install_magisk_title">Ultima versione Magisk: %1$s</string>
<string name="install_magisk_title">Versione Magisk aggiornata: %1$s</string>
<string name="uninstall">Disinstalla</string>
<string name="reboot_countdown">Riavvio in %1$d</string>
<string name="reboot_countdown">Riavvio tra %1$d</string>
<string name="uninstall_magisk_title">Disinstalla Magisk</string>
<string name="uninstall_magisk_msg">Questo rimuoverà tutti i moduli, MagiskSU, e potenzialmente crittografare i dati, se non crittografati/nVuoi continuare?</string>
<string name="version_none">(None)</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>
<!--Module Fragment-->
<string name="no_info_provided">(Nessuna informazione)</string>
<string name="no_info_provided">(nessuna informazione)</string>
<string name="no_modules_found">Nessun modulo trovato</string>
<string name="update_file_created">Il modulo sarà aggiornato al prossimo riavvio</string>
<string name="remove_file_created">Il modulo sarà rimosso al prossimo riavvio</string>
@@ -58,7 +62,7 @@
<string name="disable_file_created">Il modulo sarà disattivato al prossimo riavvio</string>
<string name="disable_file_removed">Il modulo sarà abilitato al prossimo riavvio</string>
<string name="author">Creato da: %1$s</string>
<string name="fab_flash_zip">Flash Modulo Zip</string>
<string name="fab_flash_zip">Flasha modulo ZIP</string>
<!--Repo Fragment-->
<string name="update_available">Aggiornamento disponibile</string>
@@ -68,80 +72,81 @@
<!--Log Fragment-->
<string name="menuSaveToSd">Salva nella SD</string>
<string name="menuReload">Ricarica</string>
<string name="menuClearLog">Cancella log</string>
<string name="logs_cleared">Log creato con successo</string>
<string name="log_is_empty">Il log è vuoto</string>
<string name="logs_save_failed">Impossibile scrivere il log sulla SD</string>
<string name="menuClearLog">Azzera registro eventi</string>
<string name="logs_cleared">Registro eventi creato correttamente</string>
<string name="log_is_empty">Il registro eventi è vuoto</string>
<string name="logs_save_failed">Impossibile scrivere registro eventi nella SD</string>
<!--About Activity-->
<string name="about">Informazioni</string>
<string name="app_developers">Sviluppatori</string>
<string name="app_developers_"><![CDATA[App creata da <a href="https://github.com/topjohnwu">topjohnwu</a> in collaborazione con <a href="https://github.com/d8ahazard">Digitalhigh</a> e <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
<string name="app_changelog">Changelog</string>
<string name="translators">Fabb2303</string>
<string name="app_version">Versione App</string>
<string name="app_changelog">Novità</string>
<string name="translators">Fabb2303 - bovirus</string>
<string name="app_version">Versione app</string>
<string name="app_source_code">Codice sorgente</string>
<string name="donation">Donazione</string>
<string name="app_translators">Traduttori App</string>
<string name="support_thread">Thread di supporto</string>
<string name="donation">Dona</string>
<string name="app_translators">Traduttori app</string>
<string name="support_thread">Supporto app</string>
<!--Toasts, Dialogs-->
<string name="permissionNotGranted">Questa funzione non funziona senza il permesso di scrivere sulla memoria di archiviazione esterna</string>
<string name="permissionNotGranted">Questa funzione non sarà operativa senza il permesso di scrittura nella memoria di archiviazione esterna</string>
<string name="no_thanks">No grazie</string>
<string name="yes"></string>
<string name="ok">OK</string>
<string name="close">Chiuso</string>
<string name="close">Chiudi</string>
<string name="repo_install_title">Installazione %1$s</string>
<string name="repo_install_msg">Vuoi installare %1$s ?</string>
<string name="download_install">Scarica e installa</string>
<string name="download">Download</string>
<string name="goto_install">Valla alla sezione \"Install\"</string>
<string name="goto_install">Vai alla sezione \"Installa\"</string>
<string name="download_file_error">Errore nel download del file</string>
<string name="install_error">Errore di installazione!</string>
<string name="invalid_zip">Lo zip non è un Modulo Magisk!!</string>
<string name="invalid_zip">Lo ZIP non è un modulo Magisk!!</string>
<string name="reboot_title">Installazione completata</string>
<string name="reboot_msg">Vuoi riavviare ora?</string>
<string name="reboot">Riavvia</string>
<string name="copying_msg">Copia Zip in una directory temporanea</string>
<string name="copying_msg">Copia file ZIP in una cartella temporanea</string>
<string name="zip_install_progress_title">Installazione</string>
<string name="zip_unzip_msg">Unzip zip file …</string>
<string name="zip_process_msg">Elaborazione file Zip </string>
<string name="zip_install_progress_msg">Installazione %1$s </string>
<string name="zip_unzip_msg">Decompressione file ZIP</string>
<string name="zip_process_msg">Elaborazione file ZIP</string>
<string name="zip_install_progress_msg">Installazione di %1$s…</string>
<string name="no_magisk_title">Magisk non installato!</string>
<string name="no_magisk_msg">Vuoi scaricare ed installare Magisk?</string>
<string name="downloading_toast">Download %1$s</string>
<string name="magisk_update_title">Nuovo aggiornamento Magisk disponibile!</string>
<string name="downloading_toast">Download di %1$s</string>
<string name="magisk_update_title">Disponibile nuovo aggiornamento Magisk!</string>
<string name="settings_reboot_toast">Riavvia per applicare</string>
<string name="release_notes">Note di Rilascio</string>
<string name="repo_cache_cleared">Cache Repo cancellata</string>
<string name="safetyNet_hide_notice">Quest\'app usa SafetyNet\nè già gestita da Magisk Hide</string>
<string name="start_magiskhide">Avvio MagiskHide </string>
<string name="release_notes">Note di rilascio</string>
<string name="repo_cache_cleared">Cache reposititory azzerata</string>
<string name="safetyNet_hide_notice">Quest\'app usa SafetyNet\ned è già gestita da MagiskHide</string>
<string name="start_magiskhide">Avvio MagiskHide…</string>
<string name="no_magisksu_title">MagiskSU non in uso!</string>
<string name="no_magisksu_msg">You are not rooted with MagiskSU, using MagiskHide itself might not be enough!\nIt\'s not officially supported, and you would need additional tools (e.g suhide) to pass Safety Net.</string>
<string name="understand">Capisco</string>
<string name="process_error">Errore di processo</string>
<string name="internal_storage">Lo zip si trova in:\n[Internal Storage]%1$s</string>
<string name="no_magisksu_msg">Non hai rootato con MagiskSU. L\'uso del solo MagiskHide potrebbe non essere suffciiente!\nNon è ufficialmente supportato, e potrebbe richiedere altri strumenti (es. suhide) per passare il test Safety Net.</string>
<string name="understand">Accetto</string>
<string name="process_error">Errore di elaborazione</string>
<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="manual_boot_image">Seleziona manualmente l\'immagine di boot!</string>
<!--Settings Activity -->
<string name="settings_general_category">General</string>
<string name="settings_dark_theme_title">Tema Scuro</string>
<string name="settings_dark_theme_summary">Abilita Tema Scuro</string>
<string name="settings_notification_title">Notifica Aggiornamento</string>
<string name="settings_notification_summary">Mostra notifiche quando sono diponibili nuovi aggiornamenti</string>
<string name="settings_clear_cache_title">Pulisci Cache Repo</string>
<string name="settings_clear_cache_summary">Clear the cached information for online repos, forces the app to refresh online</string>
<string name="settings_general_category">Generale</string>
<string name="settings_dark_theme_title">Tema scuro</string>
<string name="settings_dark_theme_summary">Abilita tema scuro</string>
<string name="settings_notification_title">Notifica aggiornamenti</string>
<string name="settings_notification_summary">Visualizza notifica quando sono diponibili aggiornamenti</string>
<string name="settings_clear_cache_title">Azzera cache repository</string>
<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_magiskhide_summary">Hide Magisk from various detections</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, 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">Bind mount Magisk\'s built-in busybox to xbin</string>
<string name="settings_hosts_title">Systemless hosts</string>
<string name="settings_hosts_summary">Systemless hosts support for Adblock apps</string>
<string name="settings_busybox_summary">Collega il mount della busybox interna di Magisk a xbin</string>
<string name="settings_hosts_title">Host systemless</string>
<string name="settings_hosts_summary">Supporto host systemless per app blocco pubblicità</string>
<string name="settings_su_app_adb">Apps e ADB</string>
<string name="settings_su_app">Solo Apps</string>
<string name="settings_su_app_adb">App e ADB</string>
<string name="settings_su_app">Solo app</string>
<string name="settings_su_adb">Solo ADB</string>
<string name="settings_su_disable">Disabilitato</string>
<string name="settings_su_request_10">10 secondi</string>
@@ -149,22 +154,33 @@
<string name="settings_su_request_30">30 secondi</string>
<string name="settings_su_request_60">60 secondi</string>
<string name="superuser_access">Accesso Superuser</string>
<string name="auto_response">Risposta Automatica</string>
<string name="request_timeout">Timeout richiesto</string>
<string name="auto_response">Risposta automatica</string>
<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_summary">Ri-autentifica permessi superuser dopo aggiornamento applicazione</string>
<string name="settings_development_category">App Development</string>
<string name="settings_developer_logging_title">Abilita Debug Log Avanzato</string>
<string name="settings_developer_logging_summary">Check this to enable verbose logging</string>
<string name="settings_shell_logging_title">Abilita comandi shell debug log</string>
<string name="settings_shell_logging_summary">Check this to enable logging all shell commands and its output</string>
<string name="multiuser_mode">Modo multiutente</string>
<string name="settings_owner_only">Solo proprietario dispositivo</string>
<string name="settings_owner_manage">gestito da propietario utente</string>
<string name="settings_user_independent">Utente indipendente</string>
<string name="owner_only_summary">Solo proprietario che ha accesso root</string>
<string name="owner_manage_summary">Solo il propietario può gestire accesso root e ricevere richieste</string>
<string name="user_indepenent_summary">Ogni utente ha le sue regole di root separate</string>
<string name="multiuser_hint_owner_request">Una richiestà è stata inviata al propietario dipositivo. Accedi come propietario dispositivo e concedi i permessi.</string>
<string name="settings_development_category">Sviluppo app</string>
<string name="settings_developer_logging_title">Abilita registro eventi avanzato debug</string>
<string name="settings_developer_logging_summary">Spunta questo per abilitare il registro eventi dettagliato</string>
<string name="settings_shell_logging_title">Abilita registro eventi debug comandi shell</string>
<string name="settings_shell_logging_summary">Spunta questo per abilitare il registro eventi dettagliato dei comandi shell e dei relativi risultati</string>
<!--Superuser-->
<string name="su_request_title">Richiesta Superuser</string>
<string name="deny_with_str">Nega%1$s</string>
<string name="deny_with_str">Nega %1$s</string>
<string name="deny">Nega</string>
<string name="prompt">Prompt</string>
<string name="prompt">Richiedi</string>
<string name="grant">Concedi</string>
<string name="su_warning">Concede il pieno accesso al dispositivo.\nNega se non sei sicuro</string>
<string name="forever">Sempre</string>
@@ -173,24 +189,24 @@
<string name="twentymin">20 minuti</string>
<string name="thirtymin">30 minuti</string>
<string name="sixtymin">60 minuti</string>
<string name="su_allow_toast">%1$s ha ottenuto i permessi Superuser</string>
<string name="su_deny_toast">%1$s non ha ottenuto i permessi Superuser</string>
<string name="su_allow_toast">%1$s HA ottenuto i permessi Superuser</string>
<string name="su_deny_toast">%1$s NON ha ottenuto i permessi Superuser</string>
<string name="no_apps_found">Nessuna app trovata</string>
<string name="su_snack_grant">Permessi Superuser per %1$s ottenuti</string>
<string name="su_snack_deny">Permessi Superuser per %1$s non ottenuti</string>
<string name="su_snack_grant"> %1$s HA ottenuto i permessi Superuser</string>
<string name="su_snack_deny"> %1$s NON ha ottenuto i permessi Superuser</string>
<string name="su_snack_notif_on">Notifiche per %1$s abilitate</string>
<string name="su_snack_notif_off">Notifiche per %1$s disabilitate</string>
<string name="su_snack_log_on">Log per %1$s è abilitato</string>
<string name="su_snack_log_off">Log per %1$s è disabilitato</string>
<string name="su_snack_revoke">%1$s rights are revoked</string>
<string name="su_revoke_title">Revoke?</string>
<string name="su_revoke_msg">Confirm to revoke %1$s rights?</string>
<string name="su_snack_log_on">Registro eventi abilitato per %1$s</string>
<string name="su_snack_log_off">Registro eventi NON abilitato per %1$s</string>
<string name="su_snack_revoke">I diritti di %1$s sono stati revocati</string>
<string name="su_revoke_title">Revocare?</string>
<string name="su_revoke_msg">Confermi la revoca dei diritti di %1$s?</string>
<string name="toast">Toast</string>
<string name="none">Nessuno</string>
<!--Superuser logs-->
<string name="pid">PID:\u0020</string>
<string name="target_uid">Target UID:\u0020</string>
<string name="command">Command:\u0020</string>
<string name="target_uid">UID destinazione:\u0020</string>
<string name="command">Comando:\u0020</string>
</resources>

View File

@@ -0,0 +1,197 @@
<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="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">更新を確認できませんでした。インターネットに接続されていますか?</string>
<string name="up_to_date">最新の %1$s がインストール済です</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 Statusをチェック中…</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 Failed: CTSプロファイルが不一致</string>
<string name="safetyNet_pass">SafetyNet Passed</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>
<!--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">モジュールの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">神楽坂桜Sakura_Sa233#Twitter/ hota (@lindwurm)</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">ダウンロード &amp; インストール</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">リポジトリキャッシュを消去しました</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にrootされていません。MagiskHideを使用するだけでは十分ではありません。\nそれは正式にサポートされておらず、あなたはSafetyNetを通過するために追加ツール例えばsuhideが必要です。</string>
<string name="understand">了解</string>
<string name="process_error">プロセスエラー</string>
<string name="internal_storage">zipは:\n[Internal Storage]%1$sに保存されます</string>
<string name="zip_process_title">処理</string>
<string name="manual_boot_image">ブートイメージを手動で選択してください!</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_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">Magiskに搭載するBusyBoxをxbinにバインドする</string>
<string name="settings_hosts_title">Systemless hosts</string>
<string name="settings_hosts_summary">AdblockのためのSystemless hostsサポート</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_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>
<!--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">トースト通知</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>

View File

@@ -14,10 +14,11 @@
<!--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$.1f 사용 가능!</string>
<string name="magisk_update_available">Magisk v%1$s 사용 가능!</string>
<string name="cannot_check_updates">업데이트를 확인할 수 없음. 인터넷 연결을 확인하세요.</string>
<string name="up_to_date">최신 버전의 %1$s 설치됨</string>
<string name="root_error">루팅은 되어 있으나 루트 권한을 얻을 수 없음. 루트 권한 허용 상태를 확인하세요.</string>
@@ -27,13 +28,14 @@
<string name="checking_safetyNet_status">SafetyNet 상태 확인 중…</string>
<string name="safetyNet_connection_failed">Google API에 연결할 수 없음</string>
<string name="safetyNet_connection_suspended">Google API에 대한 연결이 일시 중지됨</string>
<string name="safetyNet_error">SafetyNet 체크 실패. 인터넷 연결을 확인하세요.</string>
<string name="safetyNet_no_response">SafetyNet 체크 실패. 인터넷 연결을 확인하세요.</string>
<string name="safetyNet_fail">SafetyNet 실패: CTS 프로필 불일치</string>
<string name="safetyNet_pass">SafetyNet 통과</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">부트 이미지 위치</string>
<string name="detect_button">감지</string>
<string name="advanced_settings_title">고급 설정</string>
@@ -43,6 +45,9 @@
<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>
<!--Module Fragment-->
<string name="no_info_provided">(제공된 정보 없음)</string>
@@ -115,19 +120,25 @@
<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">부트 이미지를 직접 선택해 주세요!</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_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">xbin 디렉터리에 Magisk의 빌트인 busybox를 바인드합니다.</string>
<string name="settings_hosts_title">시스템리스 hosts</string>
<string name="settings_hosts_summary">애드블록에서 사용하는 시스템리스 hosts를 지원합니다.</string>
<string name="settings_hosts_title">systemless hosts</string>
<string name="settings_hosts_summary">광고 차단 앱에서 사용하는 systemless hosts를 지원합니다.</string>
<string name="settings_su_app_adb">앱 및 ADB</string>
<string name="settings_su_app">앱만</string>

View File

@@ -2,97 +2,219 @@
<!--Universal-->
<!--Welcome Activity-->
<string name="navigation_drawer_open">Open navigatie</string>
<string name="navigation_drawer_close">Sluit navigatie</string>
<string name="navigation_drawer_open">Navigatielade openen</string>
<string name="navigation_drawer_close">Navigatielade sluiten</string>
<string name="modules">Modules</string>
<string name="downloads">Downloads</string>
<string name="superuser">Superuser</string>
<string name="log">Log</string>
<string name="settings">Instellingen</string>
<string name="status">Status</string>
<string name="install">Installeren</string>
<!--Magisk Fragment-->
<string name="magisk_version">Geïnstalleerde Magisk: v%1$s</string>
<string name="magisk_version_error">Heb jij Magisk wel geïnstalleerd?</string>
<!--Status Fragment-->
<string name="magisk_version">Magisk v%1$s geïnstalleerd</string>
<string name="magisk_version_core_only">Magisk v%1$s geïnstalleerd (basismodus)</string>
<string name="magisk_version_error">Magisk niet geïnstalleerd</string>
<string name="magisk_update_available">Magisk v%1$.1f update!</string>
<string name="cannot_check_updates">Kan niet controleren op updates.</string>
<string name="up_to_date">Nieuwste versie van %1$s geïnstalleerd</string>
<string name="checking_for_updates">Controleren op updates…</string>
<string name="magisk_update_available">Magisk v%1$s beschikbaar!</string>
<string name="cannot_check_updates">Kan niet controleren op updates. Geen internet?</string>
<string name="up_to_date">Laatste versie van %1$s geïnstalleerd</string>
<string name="root_error">Geroot, maar geen root-permissie. Niet toegestaan?</string>
<string name="not_rooted">Niet geroot</string>
<string name="proper_root">Correct geroot</string>
<string name="safetyNet_check_text">Tik om SafetyNet controle te starten</string>
<string name="checking_safetyNet_status">SafetyNet status controleren…</string>
<string name="safetyNet_check_success">SafetyNet controle succesvol</string>
<string name="safetyNet_connection_failed">Kan niet verbinden met Google API</string>
<string name="safetyNet_connection_suspended">Verbinding met Google API was geschorst</string>
<string name="safetyNet_no_response">Kan SafetyNet niet controleren. Geen internet?</string>
<string name="safetyNet_fail">SafetyNet gefaald</string>
<string name="safetyNet_pass">SafetyNet geslaagd</string>
<string name="safetyNet_network_loss">Netwerkverbinding verloren</string>
<string name="safetyNet_service_disconnected">Service is beëindigd</string>
<string name="safetyNet_res_invalid">Reactie is ongeldig</string>
<string name="root_info_warning">Functionaliteit zeer beperkt</string>
<!--Root Fragment-->
<!--Install Fragment-->
<string name="auto_detect">(Auto) %1$s</string>
<string name="cannot_auto_detect">(Kan niet auto-detecteren)</string>
<string name="boot_image_title">Boot image locatie</string>
<string name="detect_button">Detecteren</string>
<string name="advanced_settings_title">Geavanceerde instellingen</string>
<string name="keep_force_encryption">Behoud afgedwongen versleuteling</string>
<string name="keep_dm_verity">Behoud dm-verity</string>
<string name="current_magisk_title">Geïnstalleerde Magisk versie: %1$s</string>
<string name="install_magisk_title">Recentste Magisk versie: %1$s</string>
<string name="uninstall">Deïnstalleren</string>
<string name="reboot_countdown">Herstarten in %1$d</string>
<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>
<!--Module Fragment-->
<string name="no_info_provided">(Geen informatie gegeven)</string>
<string name="no_info_provided">(Geen info verstrekt)</string>
<string name="no_modules_found">Geen modules gevonden</string>
<string name="update_file_created">Module wordt geüpdatet bij de volgende reboot.</string>
<string name="remove_file_created">Module wordt verwijderd bij de volgende reboot.</string>
<string name="remove_file_deleted">Module wordt niet verwijderd bij de volgende reboot.</string>
<string name="disable_file_created">Module wordt uitgeschakeld bij de volgende reboot.</string>
<string name="disable_file_removed">Module wordt ingeschakeld bij de volgende reboot.</string>
<string name="author">Gemaakt door: %1$s</string>
<string name="update_file_created">Module wordt bijgewerkt bij volgende herstart</string>
<string name="remove_file_created">Module wordt verwijderd bij volgende herstart</string>
<string name="remove_file_deleted">Module wordt niet verwijderd bij volgende herstart</string>
<string name="disable_file_created">Module wordt uitgeschakeld bij volgende herstart</string>
<string name="disable_file_removed">Module wordt ingeschakeld bij volgende herstart</string>
<string name="author">Gemaakt door %1$s</string>
<string name="fab_flash_zip">Module zip flashen</string>
<!--Repo Fragment-->
<string name="update_available">Update Beschikbaar</string>
<string name="update_available">Update beschikbaar</string>
<string name="installed">Geïnstalleerd</string>
<string name="not_installed">Niet geïnstalleerd</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Opslaan op SD-kaart</string>
<string name="menuReload">Herladen</string>
<string name="menuClearLog">Maak log leeg</string>
<string name="logs_cleared">Log succesvol geleegd</string>
<string name="menuClearLog">Log nu wissen</string>
<string name="logs_cleared">Log succesvol gewist</string>
<string name="log_is_empty">Log is leeg</string>
<string name="logs_save_failed">Kon niet naar SD-kaart schrijven:</string>
<string name="logs_save_failed">Kon log niet naar SD-kaart schrijven:</string>
<!--About Activity-->
<string name="about">Over</string>
<string name="app_developers">Hoofddevelopers</string>
<string name="app_developers_"><![CDATA[App gemaakt door <a href="https://github.com/topjohnwu">topjohnwu</a> in samenwerking met <a href="https://github.com/d8ahazard">Digitalhigh</a> en <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
<string name="app_developers">Hoofdontwikkelaars</string>
<string name="app_developers_"><![CDATA[App gemaakt door <a href="https://github.com/topjohnwu">Topjohnwu</a> in samenwerking met <a href="https://github.com/d8ahazard">Digitalhigh</a> en <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
<string name="app_changelog">App\'s changelog</string>
<string name="translators">NaamloosDT, Klaessen</string>
<string name="translators" />
<string name="app_version">App\'s versie</string>
<string name="app_source_code">Source code</string>
<string name="app_source_code">Broncode</string>
<string name="donation">Donatie</string>
<string name="app_translators">App\'s vertalers</string>
<string name="support_thread">Support thread</string>
<string name="support_thread">Hulp thread</string>
<!--Toasts, Dialogs-->
<string name="permissionNotGranted">Deze feature zal niet werken zonder permissie om op de externe opslag te schrijven.</string>
<string name="permissionNotGranted">Deze functie werkt niet zonder schrijfpermissie voor externe opslag.</string>
<string name="no_thanks">Nee bedankt</string>
<string name="repo_install_title">Installeer %1$s</string>
<string name="repo_install_msg">Wilt u %1$s installeren?</string>
<string name="download_install">Downloaden en installeren</string>
<string name="download_file_error">Er is een fout opgetreden bij het downloaden van het bestand</string>
<string name="install_error">Er is een fout opgetreden in de installatie</string>
<string name="invalid_zip">Zip bestand is geen Magisk Module!</string>
<string name="reboot_title">Installatie succesvol!</string>
<string name="reboot_msg">Wilt u nu rebooten?</string>
<string name="reboot">Reboot</string>
<string name="yes">Ja</string>
<string name="ok">Oké</string>
<string name="close">Sluiten</string>
<string name="repo_install_title">%1$s installeren</string>
<string name="repo_install_msg">Zeker weten %1$s installeren?</string>
<string name="download_install">Downloaden &amp; installeren</string>
<string name="download">Downloaden</string>
<string name="goto_install">Ga naar \"Installeren\" sectie</string>
<string name="download_file_error">Fout tijdens downloaden</string>
<string name="install_error">Installatiefout!</string>
<string name="invalid_zip">De zip is geen Magisk module!</string>
<string name="reboot_title">Installatie geslaagd!</string>
<string name="reboot_msg">Wil je nu herstarten?</string>
<string name="reboot">Herstarten</string>
<string name="copying_msg">Zip naar tijdelijke map kopiëren</string>
<string name="zip_install_progress_title">Installeren</string>
<string name="zip_install_progress_msg">Instalatievoortgang: %1$s </string>
<string name="zip_unzip_msg">Zip-bestand uitpakken</string>
<string name="zip_process_msg">Zip-bestand verwerken…</string>
<string name="zip_install_progress_msg">%1$s installeren…</string>
<string name="no_magisk_title">Geen Magisk geïnstalleerd!</string>
<string name="no_magisk_msg">Wilt u Magisk downloaden en installeren?</string>
<string name="no_magisk_msg">Wil je Magisk downloaden en installeren?</string>
<string name="downloading_toast">%1$s downloaden</string>
<string name="magisk_update_title">Nieuwe Magisk update beschikbaar!</string>
<string name="settings_reboot_toast">Herstarten om instellingen toe te passen</string>
<string name="release_notes">Publicatie notities</string>
<string name="repo_cache_cleared">Opslagcache gewist</string>
<string name="safetyNet_hide_notice">Deze app gebruikt SafetyNet\nReeds afgehandeld door standaard MagiskHide</string>
<string name="start_magiskhide">MagiskHide starten…</string>
<string name="no_magisksu_title">Geen gebruik van MagiskSU!</string>
<string name="no_magisksu_msg">Je bent niet geroot met MagiskSU, waardoor alleen MagiskHide mogelijk onvoldoende is!\nHet wordt niet officieel ondersteund, waardoor aanvullende acties (bijv. suhide) benodigd zijn om te slagen voor SafetyNet.</string>
<string name="understand">Ik begrijp het</string>
<string name="process_error">Verwerkingsfout</string>
<string name="internal_storage">De zip is opgeslagen in:\n[Interne opslag]%1$s</string>
<string name="zip_process_title">Verwerken</string>
<string name="manual_boot_image">Gelieve handmatig een boot image te selecteren!</string>
<!--URL Templates-->
<!--Settings Fragment -->
<!--Settings Activity -->
<string name="settings_general_category">Algemeen</string>
<string name="settings_dark_theme_title">Thema</string>
<string name="settings_dark_theme_summary">Selecteer een thema</string>
<string name="settings_dark_theme_title">Donker thema</string>
<string name="settings_dark_theme_summary">Donker thema inschakelen</string>
<string name="settings_notification_title">Update melding</string>
<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="settings_busybox_title">Schakel BusyBox in</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, 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>
<string name="settings_hosts_title">Systeemloze hosts</string>
<string name="settings_hosts_summary">Systemloze hosts ondersteuning voor Adblock apps</string>
<string name="settings_development_category">Development</string>
<string name="settings_developer_logging_title">Geavanceerde debug logging</string>
<string name="settings_developer_logging_summary">Schakel dit in voor uitgebreidere logging.</string>
<string name="settings_shell_logging_title">Shell command debug loggin</string>
<string name="settings_shell_logging_summary">Schakel dit in om alle shell commands en output te loggen</string>
<string name="settings_magiskhide_summary">Reboot om de instellingen toe te passen</string>
<string name="settings_su_app_adb">Apps en ADB</string>
<string name="settings_su_app">Alleen apps</string>
<string name="settings_su_adb">Alleen ADB</string>
<string name="settings_su_disable">Uitgeschakeld</string>
<string name="settings_su_request_10">10 seconden</string>
<string name="settings_su_request_20">20 seconden</string>
<string name="settings_su_request_30">30 seconden</string>
<string name="settings_su_request_60">60 seconden</string>
<string name="superuser_access">Superuser toegang</string>
<string name="auto_response">Automatisch antwoord</string>
<string name="request_timeout">Verzoek time-out</string>
<string name="superuser_notification">Superuser melding</string>
<string name="request_timeout_summary">%1$s seconden</string>
<string name="settings_su_reauth_title">Opnieuw verzoeken na bijwerken</string>
<string name="settings_su_reauth_summary">Superuser rechten opnieuw opvragen na bijwerken applicatie</string>
<!-- Strings related to Settings -->
<string name="multiuser_mode">Multi-gebruiker modus</string>
<string name="settings_owner_only">Alleen apparaateigenaar</string>
<string name="settings_owner_manage">Beheerd door apparaateigenaar</string>
<string name="settings_user_independent">Gebruiker onafhankelijk</string>
<string name="owner_only_summary">Alleen eigenaar heeft roottoegang</string>
<string name="owner_manage_summary">Alleen eigenaar kan roottoegang beheren en prompt verzoeken ontvangen</string>
<string name="user_indepenent_summary">Iedere gebruiker heeft eigen afzonderlijke rootregels</string>
<string name="multiuser_hint_owner_request">Een verzoek is naar de apparaateigenaar verstuurd. Wissel van gebruiker en sta de rechten toe</string>
<!-- Example General settings -->
<string name="mount_namespace_mode">Naamruimte-mount modus</string>
<string name="settings_ns_global">Globale naamruimte</string>
<string name="settings_ns_requester">Verkrijg naamruimte</string>
<string name="settings_ns_isolate">Geïsoleerde naamruimte</string>
<string name="global_summary">Alle rootsessies gebruiken de globale naamruimte</string>
<string name="requester_summary">Rootsessies verkrijgen de verzoeker\'s naamruimte</string>
<string name="isolate_summary">Iedere rootsessie heeft een eigen geïsoleerde naamruimte</string>
<!-- Example settings for Data & Sync -->
<string name="settings_development_category">App-ontwikkeling</string>
<string name="settings_developer_logging_title">Geavanceerde debug logs inschakelen</string>
<string name="settings_developer_logging_summary">Aanvinken om uitgebreide logs in te schakelen</string>
<string name="settings_shell_logging_title">Shell-opdracht debug logs inschakelen</string>
<string name="settings_shell_logging_summary">Aanvinken om alle shell-opdracht en uitvoer logs in te schakelen</string>
<!-- Example settings for Notifications -->
<!--Superuser-->
<string name="su_request_title">Superuser verzoek</string>
<string name="deny_with_str">Weigeren %1$s</string>
<string name="deny">Weigeren</string>
<string name="prompt">Prompt</string>
<string name="grant">Toestaan</string>
<string name="su_warning">Verleent volledige toegang aan je apparaat.\nWeigeren als je het niet zeker weet!</string>
<string name="forever">Altijd</string>
<string name="once">Eénmalig</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">Superuser rechten voor %1$s toegestaan</string>
<string name="su_deny_toast">Superuser rechten voor %1$s geweigerd</string>
<string name="no_apps_found">Geen apps gevonden</string>
<string name="su_snack_grant">Superuser rechten van %1$s toegestaan</string>
<string name="su_snack_deny">Superuser rechten van %1$s geweigerd</string>
<string name="su_snack_notif_on">Meldingen van %1$s ingeschakeld</string>
<string name="su_snack_notif_off">Meldingen van %1$s uitgeschakeld</string>
<string name="su_snack_log_on">Loggen van %1$s ingeschakeld</string>
<string name="su_snack_log_off">Loggen of %1$s uitgeschakeld</string>
<string name="su_snack_revoke">%1$s rechten zijn ingetrokken</string>
<string name="su_revoke_title">Intrekken?</string>
<string name="su_revoke_msg">De rechten van %1$s intrekken?</string>
<string name="toast">Toast</string>
<string name="none">Geen</string>
<!--Superuser logs-->
<string name="pid">PID:\u0020</string>
<string name="target_uid">Doel UID:\u0020</string>
<string name="command">Opdracht:\u0020</string>
</resources>

View File

@@ -17,10 +17,11 @@
<!--Status Fragment-->
<string name="magisk_version">Zainstalowany Magisk v%1$s</string>
<string name="magisk_version_core_only">Zainstalowany Magisk v%1$s (Tylko Tryb Rdzeni)</string>
<string name="magisk_version_error">Magisk nie jest zainstalowany</string>
<string name="checking_for_updates">Sprawdzanie aktualizacji…</string>
<string name="magisk_update_available">Magisk v%1$.1f dostępny!</string>
<string name="magisk_update_available">Magisk v%1$s dostępny!</string>
<string name="cannot_check_updates">Nie można sprawdzić dostępności aktualizacji, brak internetu</string>
<string name="up_to_date">Zainstalowana najnowsza wersja %1$s</string>
<string name="root_error">Root dostępny, ale dostęp nie przyznany</string>
@@ -28,11 +29,15 @@
<string name="proper_root">Root Dostępny</string>
<string name="safetyNet_check_text">Dotknij aby sprawdzić SafetyNet</string>
<string name="checking_safetyNet_status">Sprawdzanie statusu SafetyNet…</string>
<string name="safetyNet_check_success">Sprawdzanie SafetyNet z Powodzeniem</string>
<string name="safetyNet_connection_failed">Nie można połączyć się z Google API</string>
<string name="safetyNet_connection_suspended">Połączenie z Google API zostało zawieszone</string>
<string name="safetyNet_error">Nie można sprawdzić SafetyNet bez internetu</string>
<string name="safetyNet_no_response">Nie można sprawdzić SafetyNet bez internetu</string>
<string name="safetyNet_fail">Błąd SafetyNet: Niezgodność profilu CTS</string>
<string name="safetyNet_pass">SafetyNet Poprawny</string>
<string name="safetyNet_network_loss">Brak połączenia z internetem</string>
<string name="safetyNet_service_disconnected">Usługa została zamknięta</string>
<string name="safetyNet_res_invalid">Usługa nie odpowiada</string>
<string name="root_info_warning">Funkcjonalność znacznie ograniczona</string>
<!--Install Fragment-->
@@ -125,6 +130,8 @@
<string name="internal_storage">Zip jest przechowywany w:\n[Pamięć Wewnętrzna]%1$s</string>
<string name="zip_process_title">Przetwarzanie</string>
<string name="manual_boot_image">Proszę ręcznie wybrać boot image!</string>
<string name="manager_update_title">Nowa Wersja Magisk Manager Jest Dostępna!</string>
<string name="manager_download_install">Naciśnij aby pobrać i zainstalować</string>
<!--Settings Activity -->
<string name="settings_general_category">Ogólne</string>
@@ -135,6 +142,8 @@
<string name="settings_clear_cache_title">Wyczyść Pamięć Repozytorium</string>
<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 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>
@@ -154,6 +163,25 @@
<string name="request_timeout">Czas na decyzję</string>
<string name="superuser_notification">Powiadomienia Superusera</string>
<string name="request_timeout_summary">%1$s sekund</string>
<string name="settings_su_reauth_title">Ponowienie uwierzytelnienia po aktualizacji</string>
<string name="settings_su_reauth_summary">Ponowne uwierzytelnianie uprawnienia superużytkownika po aktualizacji aplikacji</string>
<string name="multiuser_mode">Tryb Multiusera</string>
<string name="settings_owner_only">Tylko Właściciel Urządzenia</string>
<string name="settings_owner_manage">Zarządzanie Właścicielami Urządzenia</string>
<string name="settings_user_independent">Niezależny Użytkownik</string>
<string name="owner_only_summary">Tylko właściciel ma dostęp do roota</string>
<string name="owner_manage_summary">Tylko właściciel może zarządzać prawami dostępu użytkownika do roota iwyświetlać żądania dostępu</string>
<string name="user_indepenent_summary">Każdy użytkownik ma swoje własne odrębne ustawienia dostępu</string>
<string name="multiuser_hint_owner_request">Żądanie zostało wysłane do właściciela urządzenia. Proszę przejść do właściciela i udzielić pozwolenia</string>
<string name="mount_namespace_mode">Montuj Tryb Nazw</string>
<string name="settings_ns_global">Globalna Nazwa</string>
<string name="settings_ns_requester">Dziedziczenie Nazw</string>
<string name="settings_ns_isolate">Izolacja Nazw</string>
<string name="global_summary">Wszystkie sesje root za pomocą globalnej przestrzeni montowań nazw</string>
<string name="requester_summary">Sesje Root będzie dziedziczyć prośby i nazwy</string>
<string name="isolate_summary">W każdej sesji root będzie miał własną odosobnioną nazwę</string>
<string name="settings_development_category">Dla Developerów</string>
<string name="settings_developer_logging_title">Włącz zaawansowane logowanie debugowania</string>

View File

@@ -6,6 +6,7 @@
<!--Welcome Activity-->
<string name="navigation_drawer_open">Abrir gaveta de notificação</string>
<string name="navigation_drawer_close">Fechar gaveta de notificação</string>
<string name="modules">Módulos</string>
<string name="downloads">Baixar</string>
<string name="superuser">Superusuário</string>
@@ -16,26 +17,32 @@
<!--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">Checando por atualizações…</string>
<string name="magisk_update_available">Magisk v%1$.1f disponível!</string>
<string name="magisk_update_available">Magisk v%1$s disponível!</string>
<string name="cannot_check_updates">Não é possível verificar se há atualizações</string>
<string name="up_to_date">Última versão do %1$s instalado</string>
<string name="root_error">Rooteado mas sem permissão de root, o acesso foi permitido?</string>
<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_error">Não é possível verificar o SafetyNet, sem Internet?</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-->
<string name="auto_detect">(Auto) %1$s</string>
<string name="cannot_auto_detect">(Não foi auto detectado)</string>
<string name="boot_image_title">Local da Boot Image</string>
<string name="detect_button">Detectar</string>
<string name="advanced_settings_title">Configurações avançadas</string>
@@ -43,7 +50,11 @@
<string name="keep_dm_verity">Keep 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">Reiniciando em %1$d</string>
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
<string name="uninstall_magisk_msg">Isso removerá todos os módulos, MagiskSU, e Potencialmente criptografar seus dados se não criptografados\nVocê deseja continuar?</string>
<string name="version_none">(Nenhum)</string>
<!--Module Fragment-->
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
@@ -85,9 +96,12 @@
<string name="permissionNotGranted">Este recurso 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">Você deseja instalar%1$s ?</string>
<string name="download_install">Baixar &amp; instalar</string>
<string name="download">Baixar</string>
<string name="goto_install">Ir na seção \"Instalar\"</string>
<string name="download_file_error">Erro ao baixar o arquivo</string>
<string name="install_error">Erro na instalação!</string>
@@ -109,19 +123,28 @@
<string name="repo_cache_cleared">Cache do Repo. limpado</string>
<string name="safetyNet_hide_notice">Este aplicativo usa SafetyNet\nJá manipulado pelo MagiskHide por padrão</string>
<string name="start_magiskhide">Iniciando MagiskHide …</string>
<string name="no_magisksu_title">Não está usando MagiskSU!</string>
<string name="no_magisksu_msg">Você não está rooteado com MagiskSU, Usar MagiskHide em si pode não ser suficiente!\Ele não é oficialmente suportado, E você precisaria de ferramentas adicionais (ex: suhide) para passar pelo Safety Net.</string>
<string name="understand">Eu entendo</string>
<string name="process_error">Erro no processo</string>
<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>
<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">Limpar Repo Cache</string>
<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, 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>
@@ -141,6 +164,25 @@
<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>
@@ -152,7 +194,7 @@
<string name="su_request_title">Solicitação de superusuário</string>
<string name="deny_with_str">Negar%1$s</string>
<string name="deny">Negar</string>
<string name="prompt">Painel</string>
<string name="prompt">Perguntar</string>
<string name="grant">Permitir</string>
<string name="su_warning">Concede acesso total ao seu dispositivo.\nNegue se você não tiver certeza!</string>
<string name="forever">Sempre</string>
@@ -173,7 +215,7 @@
<string name="su_snack_revoke">%1$s Direitos foi 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 simples</string>
<string name="toast">Notificação(Toast)</string>
<string name="none">Nenhum</string>
<!--Superuser logs-->

View File

@@ -0,0 +1,224 @@
<resources>
<!--Welcome Activity-->
<string name="navigation_drawer_open">Abrir gaveta de notificação</string>
<string name="navigation_drawer_close">Fechar gaveta de notificação</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_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="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>
<!--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="translators">Bruno Guerreiro</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 ?</string>
<string name="download_install">Transferir &amp; 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">O 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>
<!--Settings Fragment -->
<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="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_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-->
<string name="pid">PID:\u0020</string>
<string name="target_uid">Alvo UID:\u0020</string>
<string name="command">Comando:\u0020</string>
<string name="safetyNet_check_success">SafetyNet verificado com sucesso</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="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="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>
</resources>

View File

@@ -0,0 +1,216 @@
<resources>
<!--Welcome Activity-->
<string name="navigation_drawer_open">Deschide sertarul de navigare</string>
<string name="navigation_drawer_close">Închide sertarul de navigare</string>
<string name="modules">Module</string>
<string name="downloads">Descărcări</string>
<string name="superuser">Superuser</string>
<string name="log">Jurnal</string>
<string name="settings">Setări</string>
<string name="status">Stare</string>
<string name="install">Instalare</string>
<!--Status Fragment-->
<string name="magisk_version">Magisk instalat v%1$s</string>
<string name="magisk_version_core_only">Magisk instalat v%1$s (Mod de bază)</string>
<string name="magisk_version_error">Magisk nu este instalat</string>
<string name="checking_for_updates">Verificare actualizări…</string>
<string name="magisk_update_available">Magisk v%1$s disponibil!</string>
<string name="cannot_check_updates">Nu se pot verifica actualizările, nu este internet?</string>
<string name="up_to_date">Ultima versiune a %1$s este instalată</string>
<string name="root_error">Root obţinut, dar fără permisiune root, nu este permis?</string>
<string name="not_rooted">Nu este obţinut root</string>
<string name="proper_root">Root obţinut corect</string>
<string name="safetyNet_check_text">Apăsați pentru a începe verificarea SafetyNet</string>
<string name="checking_safetyNet_status">Verificarea stării SafetyNet…</string>
<string name="safetyNet_connection_failed">Nu se poate conecta la Google API</string>
<string name="safetyNet_connection_suspended">Conexiunea la API-ul Google a fost suspendată</string>
<string name="safetyNet_no_response">Nu se poate verifica SafetyNet, nu este internet?</string>
<string name="safetyNet_fail">SafetyNet eșuat: nepotrivire profil CTS</string>
<string name="safetyNet_pass">SafetyNet a trecut</string>
<string name="root_info_warning">Funcționalitatea este foarte limitată</string>
<!--Install Fragment-->
<string name="auto_detect">(Auto) %1$s</string>
<string name="cannot_auto_detect">(Nu se poate detecta automat)</string>
<string name="boot_image_title">Locaţie imagine Boot</string>
<string name="detect_button">Detectare</string>
<string name="advanced_settings_title">Setări avansate</string>
<string name="keep_force_encryption">Păstrare criptare forţată</string>
<string name="keep_dm_verity">Păstrare dm-verity</string>
<string name="current_magisk_title">Versiune Magisk instalată: %1$s</string>
<string name="install_magisk_title">Ultima versiune Magisk: %1$s</string>
<string name="uninstall">Dezinstalare</string>
<string name="reboot_countdown">Repornire în %1$d</string>
<string name="uninstall_magisk_title">Dezinstalare Magisk</string>
<string name="uninstall_magisk_msg">Aceasta va elimina toate modulele, MagiskSU, şi potențial să cripteze datele, dacă nu sunt criptate\nContinuaţi?</string>
<string name="version_none">(Niciuna)</string>
<!--Module Fragment-->
<string name="no_info_provided">(Nu sunt furnizate informații)</string>
<string name="no_modules_found">Niciun modul</string>
<string name="update_file_created">Modulul va fi actualizat la următoarea repornire</string>
<string name="remove_file_created">Modulul va fi eliminat la următoarea repornire</string>
<string name="remove_file_deleted">Modulul nu va fi eliminat la următoarea repornire</string>
<string name="disable_file_created">Modulul va fi dezactivat la următoarea repornire</string>
<string name="disable_file_removed">Modulul va fi activat la următoarea repornire</string>
<string name="author">Creat de %1$s</string>
<string name="fab_flash_zip">Modul Zip</string>
<!--Repo Fragment-->
<string name="update_available">Actualizare disponibilă</string>
<string name="installed">Instalat</string>
<string name="not_installed">Nu este instalat</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Salvare pe cardul SD</string>
<string name="menuReload">Reîncărcare</string>
<string name="menuClearLog">Șterge jurnal acum</string>
<string name="logs_cleared">Jurnal şters</string>
<string name="log_is_empty">Jurnal gol</string>
<string name="logs_save_failed">Nu s-a putut scrie jurnalul pe cardul SD:</string>
<!--About Activity-->
<string name="about">Despre</string>
<string name="app_developers">Dezvoltatori principali</string>
<string name="app_developers_"><![CDATA[Aplicație creată de <a href="https://github.com/topjohnwu">topjohnwu</a> în colaborare cu <a href="https://github.com/d8ahazard">Digitalhigh</a> şi <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
<string name="app_changelog">Lista modificărilor</string>
<string name="translators" />
<string name="app_version">Versiune aplicaţie</string>
<string name="app_source_code">Cod sursă</string>
<string name="donation">Donaţie</string>
<string name="app_translators">Traducători</string>
<string name="support_thread">Pagina de suport</string>
<!--Toasts, Dialogs-->
<string name="permissionNotGranted">Această caracteristică nu va funcționa fără permisiunea de a scrie pe memoria externă.</string>
<string name="no_thanks">Nu, mulţumesc</string>
<string name="yes">Da</string>
<string name="ok">OK</string>
<string name="close">Închide</string>
<string name="repo_install_title">Instalare %1$s</string>
<string name="repo_install_msg">Instalaţi %1$s?</string>
<string name="download_install">Descărcare şi instalare</string>
<string name="download">Descărcare</string>
<string name="goto_install">Accesaţi secţiunea \"Instalare\"</string>
<string name="download_file_error">Eroare la descărcarea fișierului</string>
<string name="install_error">Eroare de instalare!</string>
<string name="invalid_zip">Zip-ul nu este un modul Magisk!!</string>
<string name="reboot_title">Instalarea a reușit!</string>
<string name="reboot_msg">Reporniţi acum?</string>
<string name="reboot">Repornire</string>
<string name="copying_msg">Copierea zip-ului în dosarul temp</string>
<string name="zip_install_progress_title">Instalare</string>
<string name="zip_unzip_msg">Dezarhivarea fișierului zip…</string>
<string name="zip_process_msg">Procesare fişierului zip…</string>
<string name="zip_install_progress_msg">Instalare %1$s…</string>
<string name="no_magisk_title">Magisk nu este instalat!</string>
<string name="no_magisk_msg">Doriți să descărcați și să instalați Magisk?</string>
<string name="downloading_toast">Descărcare %1$s</string>
<string name="magisk_update_title">O nouă actualizare Magisk este disponibilă!</string>
<string name="settings_reboot_toast">Reporniți pentru a aplica setările</string>
<string name="release_notes">Note de lansare</string>
<string name="repo_cache_cleared">Arhive cache eliminate</string>
<string name="safetyNet_hide_notice">Această aplicație utilizează SafetyNet\nDeja gestionat de MagiskHide în mod implicit</string>
<string name="start_magiskhide">Pornire MagiskHide…</string>
<string name="no_magisksu_title">Nu se utilizează MagiskSU!</string>
<string name="no_magisksu_msg">Nu aţi obţinut acces la root cu MagiskSU, utilizarea MagiskHide s-ar putea să nu fie suficientă!\nNu este susținută oficial și veți avea nevoie de instrumente suplimentare (de ex. suhide) pentru a trece Safety Net.</string>
<string name="understand">Înţeleg</string>
<string name="process_error">Eroare de proces</string>
<string name="internal_storage">Zip stocat în:\n[Stocare internă]%1$s</string>
<string name="zip_process_title">Procesare</string>
<string name="manual_boot_image">Selectați manual o imagine de boot!</string>
<string name="manager_update_title">O nouă actualizare pentru Magisk Manager este disponibilă!</string>
<string name="manager_download_install">Apăsați pentru a descărca și instala</string>
<!--Settings Activity -->
<string name="settings_general_category">General</string>
<string name="settings_dark_theme_title">Temă întunecată</string>
<string name="settings_dark_theme_summary">Activare temă întunecată</string>
<string name="settings_notification_title">Notificare actualizare</string>
<string name="settings_notification_summary">Se afișează notificări de actualizare atunci când este disponibilă o nouă versiune</string>
<string name="settings_clear_cache_title">Eliminare cache</string>
<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 ş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>
<string name="settings_hosts_title">Systemless hosts</string>
<string name="settings_hosts_summary">Systemless hosts suport pentru aplicațiile Adblock</string>
<string name="settings_su_app_adb">Aplicaţii şi ADB</string>
<string name="settings_su_app">Doar aplicaţii</string>
<string name="settings_su_adb">Doar ADB</string>
<string name="settings_su_disable">Dezactivat</string>
<string name="settings_su_request_10">10 secunde</string>
<string name="settings_su_request_20">20 de secunde</string>
<string name="settings_su_request_30">30 de secunde</string>
<string name="settings_su_request_60">60 de secunde</string>
<string name="superuser_access">Acces Superuser</string>
<string name="auto_response">Răspuns automat</string>
<string name="request_timeout">Expirare</string>
<string name="superuser_notification">Notificare Superuser</string>
<string name="request_timeout_summary">%1$s secunde</string>
<string name="settings_su_reauth_title">Reautentificare după actualizare</string>
<string name="settings_su_reauth_summary">Reautentificare permisiuni pentru superuser după o actualizare a aplicației</string>
<string name="multiuser_mode">Mod Multiutilizator</string>
<string name="settings_owner_only">Numai proprietarul dispozitivului</string>
<string name="settings_owner_manage">Gestionat de proprietarul dispozitivului</string>
<string name="settings_user_independent">Utilizator independent</string>
<string name="owner_only_summary">Numai proprietarul are acces la root</string>
<string name="owner_manage_summary">Numai proprietarul poate gestiona accesul la root și să primească solicitări</string>
<string name="user_indepenent_summary">Fiecare utilizator are propriile reguli de acces la root</string>
<string name="multiuser_hint_owner_request">A fost trimisă o solicitare proprietarului dispozitivului. Comutaţi la proprietar și acordați permisiunea</string>
<string name="mount_namespace_mode">Mod montare spaţiu de nume</string>
<string name="settings_ns_global">Spaţiu de nume global</string>
<string name="settings_ns_requester">Spaţiu de nume moştenit</string>
<string name="settings_ns_isolate">Spațiu de nume izolat</string>
<string name="global_summary">Toate sesiunile de root utilizează spațiul de nume global</string>
<string name="requester_summary">Sesiunile de root vor moșteni spațiul de nume al solicitantului</string>
<string name="isolate_summary">Fiecare sesiune de root va avea propriul spațiu de nume izolat</string>
<string name="settings_development_category">Dezvoltare aplicaţie</string>
<string name="settings_developer_logging_title">Activați logarea avansată de depanare</string>
<string name="settings_developer_logging_summary">Bifați această opțiune pentru a activa înregistrarea detaliată</string>
<string name="settings_shell_logging_title">Activați logarea comenzilor shell</string>
<string name="settings_shell_logging_summary">Bifați această opțiune pentru a permite logarea tuturor comenzilor shell și ieșirea acestora</string>
<!--Superuser-->
<string name="su_request_title">Solicitare Superuser</string>
<string name="deny_with_str">Refuzaţi %1$s</string>
<string name="deny">Refuzaţi</string>
<string name="prompt">Solicitare</string>
<string name="grant">Permiteţi</string>
<string name="su_warning">Acordă acces complet la dispozitivul dvs..\nRefuzaţi dacă nu sunteţi sigur!</string>
<string name="forever">Pentru totdeauna</string>
<string name="once">O singura dată</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 i-au fost acordate drepturi Superuser</string>
<string name="su_deny_toast">%1$s i-au fost refuzate drepturi Superuser</string>
<string name="no_apps_found">Nicio aplicaţie</string>
<string name="su_snack_grant">Drepturile Superuser pentru %1$s au fost acordate</string>
<string name="su_snack_deny">Drepturile Superuser pentru %1$s au fost refuzate</string>
<string name="su_snack_notif_on">Notificările pentru %1$s au fost acordate</string>
<string name="su_snack_notif_off">Notificările pentru %1$s au fost refuzate</string>
<string name="su_snack_log_on">Logarea pentru %1$s a fost activată</string>
<string name="su_snack_log_off">Logarea pentru %1$s a fost dezactivată</string>
<string name="su_snack_revoke">Drepturile pentru %1$s sunt revocate</string>
<string name="su_revoke_title">Revocaţi?</string>
<string name="su_revoke_msg">Confirmați revocarea drepturilor pentru %1$s?</string>
<string name="toast">Mesaj</string>
<string name="none">Nimic</string>
<!--Superuser logs-->
<string name="pid">PID:\u0020</string>
<string name="target_uid">UID:\u0020</string>
<string name="command">Comandă:\u0020</string>
</resources>

View File

@@ -1,57 +1,68 @@
<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">Установлен 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$.1f!</string>
<string name="cannot_check_updates">Невозможно проверить обновления, нет соединения?</string>
<string name="magisk_update_available">Доступен Magisk v%1$s!</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_connection_failed">Невозможно соединиться с API Google</string>
<string name="safetyNet_connection_suspended">Соединение с API Google было приостановлено</string>
<string name="safetyNet_error">Невозможно выполнить проверку SafetyNet, нет соединения?</string>
<string name="safetyNet_fail">SafetyNet не пройден: несовпадение профиля CTS</string>
<string name="safetyNet_pass">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</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="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>
<!--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>
@@ -59,122 +70,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="goto_install">Перейти в раздел «Установка»</string>
<string name="download_file_error">Ошибка при скачивании файла</string>
<string name="install_error">Ошибка при установке!</string>
а
<string name="invalid_zip">Этот архив не содержит модуль Magisk!!</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="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="zip_process_title">Обработка</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_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">Режим 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="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>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme.Transparent" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
</style>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="fab_padding">24dp</dimen>
</resources>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme.Transparent" parent="AppTheme">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
</style>
<style name="AppTheme.Transparent.Dark" parent="AppTheme.Dark">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
</style>
</resources>

View File

@@ -15,7 +15,7 @@
<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$.1f mevcut!</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="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>
@@ -25,7 +25,7 @@
<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_connection_suspended">Google API bağlantısı askıya alındı</string>
<string name="safetyNet_error">SafetyNet kontrol edilemiyor, İnternet yok mu?</string>
<string name="safetyNet_no_response">SafetyNet kontrol edilemiyor, İnternet 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="root_info_warning">İşlevsellik çok sınırlıdır</string>

View File

@@ -17,7 +17,7 @@
<string name="magisk_version_error">Magisk chưa được cài đặt</string>
<string name="checking_for_updates">Đang kiểm tra cập nhật…</string>
<string name="magisk_update_available">Magisk v%1$.1f available!</string>
<string name="magisk_update_available">Magisk v%1$s available!</string>
<string name="cannot_check_updates">Không thể kiểm tra cập nhật, không có Internet?</string>
<string name="up_to_date">Đã cài đặt phiên bản mới nhất của %1$s</string>
<string name="root_error">Đã root nhưng không có quyền root, chưa được cho phép?</string>
@@ -27,7 +27,7 @@
<string name="checking_safetyNet_status">Đang kiểm tra trạng thái SafetyNet…</string>
<string name="safetyNet_connection_failed">Không thể kết nối với API của Google</string>
<string name="safetyNet_connection_suspended">Kết nối với API của Google đã dừng</string>
<string name="safetyNet_error">Không thể kiểm tra SafetyNet, không có Internet?</string>
<string name="safetyNet_no_response">Không thể kiểm tra SafetyNet, không có Internet?</string>
<string name="safetyNet_fail">SafetyNet thất bại: cấu hình CTS không phù hợp</string>
<string name="safetyNet_pass">SafetyNet thành công</string>
<string name="root_info_warning">Tính năng bị hạn chế rất nhiều</string>

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