Compare commits

...

91 Commits

Author SHA1 Message Date
topjohnwu
7da97489cc Add v7.4.0 release notes 2019-11-02 01:24:56 -04:00
topjohnwu
a9f11b28c8 Fix busybox scripts again 2019-11-02 01:16:54 -04:00
topjohnwu
b31d986c8d Update scripts 2019-11-02 00:41:51 -04:00
Oliver Cervera
2dad751889 Update Italian translation
- updated existing strings based on english updates
- added new strings
2019-11-02 00:28:07 -04:00
osm0sis
c85b1c56af signing: fixes for bootimg hdr_v1 and hdr_v2
- increase SignBoot bootimg header version maximum from 4 to 8 (upstream AOSP is already at 3) and make a variable for future ease
- hdr read size of 1024 bytes was too small as hdr_v1 and hdr_v2 have increased the used header page areas to 1632 and 1648 bytes, respectively, so raise this to the minimum page size of 2048 and also make a variable for future ease
- do not return "not signed" for all caught exceptions, show StackTrace for future debugging then still return false for script purposes
- correct "test keys" boot image signing strings (scripts and app) to "verity keys"
2019-11-02 00:27:56 -04:00
osm0sis
6dd34aec47 scripts: refactor and major addon.d fixes
- remove redundant addon.d.sh script bits that were covered elsewhere ($TMPDIR in util_functions.sh, find_dtbo_image in patch_dtbo_image)
- refactor addon.d.sh and flash_script.sh for simplicity and readability, and put common flashing script in util_functions.sh (as patch_boot_image), which should greatly help avoid them getting out of sync going forward and fixes compressing ramdisk support and post-patch cleanup for addon.d
- add check_data to addon.d.sh since moving stock_boot* and stock_dtbo* backups depend on it and so weren't occuring with addon.d
- fix find_manager_apk with working fallback for recovery addon.d execution (where `magisk --sqlite` will not work for hidden Manager), Manager DynAPK hiding, and print a useful log warning if an APK can't be found
2019-11-02 00:27:56 -04:00
topjohnwu
4cd154675f Random dname 2019-11-01 18:52:37 -04:00
Viktor De Pasquale
d8d72f92b3 Fixed policy toggle being impossible to cancel 2019-11-01 14:47:59 +01:00
topjohnwu
a30f5b175f Fix busybox makefiles 2019-11-01 09:38:01 -04:00
topjohnwu
8277896ca1 Make sure uninstall.sh is executed on remove 2019-11-01 03:07:12 -04:00
topjohnwu
493068c073 Attempt to rescan zygote multiple times
Close #1654
2019-11-01 02:12:28 -04:00
topjohnwu
f4299fbea8 Update BusyBox to 1.31.1 2019-10-31 18:11:10 -04:00
topjohnwu
10ce11d671 Fix config/locale issues
Close #1977
2019-10-31 17:13:06 -04:00
topjohnwu
0f34457a10 Directly store strings in viewmodel 2019-10-31 15:33:13 -04:00
topjohnwu
34c65e13bc Fix strings
Close #2012
2019-10-31 12:39:54 -04:00
John Wu
17a77e2577 Shortcut booleans 2019-10-31 02:44:25 -04:00
John Wu
0f219e5ae6 Better argument parsing logic 2019-10-31 02:44:25 -04:00
osm0sis
353c3c7d81 magiskboot: add unpack -n to help with repack validity tests
- support unpack without decompression to allow easy testing of magiskboot's header, structure and hashing handling by comparing repack checksum versus origbootimg
- make -n first to match repack
2019-10-31 02:44:25 -04:00
Rom
0a89edf3b0 Update French translation 2019-10-31 02:04:00 -04:00
topjohnwu
e7155837d7 Make sure magisk daemon won't get killed by init
According to this comment in #1880:
https://github.com/topjohnwu/Magisk/issues/1880#issuecomment-546657588

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

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

Close #1880
2019-10-31 01:57:47 -04:00
topjohnwu
31e003bda5 Fix bug in version detection 2019-10-30 05:24:22 -04:00
topjohnwu
490e4d3180 Target the proper channel in stub 2019-10-30 05:00:52 -04:00
topjohnwu
dc9f69bab0 Minor changes 2019-10-30 04:15:53 -04:00
topjohnwu
fdf04f77f2 Send bitmap to notifications and shortcuts
On API 23+, the platform unifies the way to handle drawable
resources across processes: all drawables can be passed via Icon.
This allows us to send raw bitmap to the system without the need to
specify a resource ID. This means that we are allowed to NOT include
these drawable resources within our stub APK, since our full APK can
draw the images programmatically and send raw bitmaps to the system.
2019-10-30 01:02:53 -04:00
topjohnwu
5e87483f34 Move addAssetPath to shared 2019-10-29 07:37:19 -04:00
topjohnwu
f7aa451591 Update strings 2019-10-29 07:36:50 -04:00
topjohnwu
321d11c2c6 Move Mapping class 2019-10-29 07:21:14 -04:00
topjohnwu
ee447bc4ce Improve Keygen yet again 2019-10-26 21:11:32 -04:00
Nathan Muccino
31153e4366 Minor grammatical changes
The plural form of the words 'documentation' and 'following' are used very rarely if ever and I don't believe that they should be used in this particular context.
2019-10-26 19:26:27 -04:00
topjohnwu
7693024c29 Replace general resources with platform 2019-10-26 19:23:57 -04:00
Mevlüt TOPÇU
9628700a2f Update Turkish language
Hi,

Merge please

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

Close #1920
2019-10-26 17:12:35 -04:00
topjohnwu
626507093a Don't need to wrap another layer of context 2019-10-26 15:37:12 -04:00
topjohnwu
588b3d14a3 Fix typo 2019-10-24 15:37:32 -04:00
vvb2060
815efa7791 Update zh-rCN translation 2019-10-24 13:04:36 -04:00
topjohnwu
97a691ce2f Improve keygen for signing repackaged manager 2019-10-24 13:04:15 -04:00
topjohnwu
9d948f2c2b Temporary disable verification when hiding app
For some reason, Google Play Protect randomly blocks our self-signed
repackaged Magisk Manager APKs. Since we are root, the sky is our
limit, so yeah, disable package verification temporarily when installing
patched APKs, LOLz

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

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

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

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

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

Method 3 will always work on any device, but the downside is anytime
a communication happens, Magisk Manager will steal foreground focus
regardless of whether UI is drawn. Method 1 is the only way to support
obfuscated stub APKs. The communication test will test method 1 and 2,
and if Magisk Manager is able to receive the messages, it will then
update the daemon configuration to use whichever is preferable. If none
of the broadcasts can be delivered, then the fallback method 3 will be
used.
2019-10-21 13:59:04 -04:00
topjohnwu
953c40b083 Allow upgrade Magisk daemon in emulator 2019-10-21 13:58:57 -04:00
topjohnwu
271b0287d8 Pass in stub version just in case 2019-10-20 17:47:55 -04:00
topjohnwu
96a8a2a8b8 Make SuRequest default to Translucent.NoTitleBar
Close #1959
2019-10-20 17:35:38 -04:00
topjohnwu
75306f658f Revert "Drop API 17 (Android 4.2) support"
Turns out that we cannot use AndroidKeystore anyways, so we don't
actually need to drop API 17. Revert this change.
2019-10-20 07:13:03 -04:00
topjohnwu
325d9a0b86 Generate keys for signing hidden Magisk Manager 2019-10-20 06:56:33 -04:00
topjohnwu
a02493fbaa Workaround R8 bug 2019-10-19 05:44:56 -04:00
topjohnwu
9c27d691dd Drop API 17 (Android 4.2) support 2019-10-19 03:11:54 -04:00
topjohnwu
935bd01f59 Post process release APKs 2019-10-17 18:02:31 -04:00
topjohnwu
eeb5d669f6 Assign signing keystore location in config 2019-10-17 16:20:01 -04:00
topjohnwu
78daa2eb62 Do not use string resources for app label
This not only simplifies hiding stub APKs (no resource IDs involved),
but also opens the opportunity to allow users to customize whatever
app name they want after it is hidden.
2019-10-17 04:47:46 -04:00
topjohnwu
40eda05a30 Make main app fully independent from the stub
- Skip 0x7f01XXXX - 0x7f05XXXX resource IDs in the main app; they are
reserved for stub resources
- Support sending additional data from host to guest
- Use resource mapping passed from host when they are being sent
to the system framework (notifications and shortcuts)
2019-10-17 02:55:42 -04:00
topjohnwu
9f9de8c43b Obfuscate WorkManager components
Remove unused components and hack the context sent into WorkManager
2019-10-16 17:03:55 -04:00
topjohnwu
a910c8ccd8 Support stub APK upgrades 2019-10-16 05:07:29 -04:00
topjohnwu
43bda2d4a4 Allow component classname obfuscation 2019-10-16 04:38:31 -04:00
topjohnwu
c7033dd757 Allow injecting custom channel URL for debug 2019-10-16 01:54:59 -04:00
topjohnwu
5673a9bace Move system accessible resources to shared 2019-10-15 05:49:23 -04:00
topjohnwu
34ff764515 Stabilize resource IDs 2019-10-15 04:37:12 -04:00
topjohnwu
1b3a009da7 Remove unused WorkManager components 2019-10-15 04:36:09 -04:00
topjohnwu
a49002bb2c Reorganize string resources 2019-10-15 03:33:22 -04:00
Omar Kharrab
7342fc2307 Update Arabic translation 2019-10-15 02:57:43 -04:00
topjohnwu
9867a3bd60 Pedantic boot_img_hdr multi-version support 2019-10-15 01:46:29 -04:00
topjohnwu
5ffb9eaa5b Support loading Magisk Manager from stub on 9.0+
In the effort of preventing apps from crawling APK contents across the
whole installed app list to detect Magisk Manager, the solution here
is to NOT install the actual APK into the system, but instead
dynamically load the full app at runtime by a stub app. The full APK
will be stored in the application's private internal data where
non-root processes cannot read or scan.

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

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

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

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

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

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

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

After this commit, the stub app is able to properly download and launch
the full app, with most basic functionalities working just fine.
Do not expect Magisk Manager upgrades and hiding (repackaging) to
work properly, and some other minor issues might pop up.
This feature is still in the early WIP stages.
2019-10-14 03:49:17 -04:00
topjohnwu
b05b688267 Fix issues in stub APK 2019-10-12 03:58:45 -04:00
Simon Shi
f3d7f85063 Fix incorrect link path for /sbin/.core 2019-10-12 01:00:15 -04:00
topjohnwu
de969a9dab Downgrade recyclerview 2019-10-12 00:53:04 -04:00
236 changed files with 3650 additions and 2208 deletions

4
.gitignore vendored
View File

@@ -2,8 +2,8 @@ out
*.zip
*.jks
*.apk
config.prop
update.sh
/config.prop
/update.sh
# Built binaries
native/out

View File

@@ -30,13 +30,12 @@ Furthermore, Magisk provides a **Systemless Interface** to alter the system (or
## Translations
Default string resources for Magisk Manager are scattered throughout
Default string resources for Magisk Manager and its stub APK are located here:
- `app/src/main/res/values/strings.xml`
- `stub/src/main/res/values/strings.xml`
- `shared/src/main/res/values/strings.xml`
Translate each and place them in the respective locations (`<module>/src/main/res/values-<lang>/strings.xml`).
Translate each and place them in the respective locations (`[module]/src/main/res/values-[lang]/strings.xml`).
## Signature Verification

View File

@@ -75,7 +75,7 @@ dependencies {
implementation "${bindingAdapter}:${vBAdapt}"
implementation "${bindingAdapter}-recyclerview:${vBAdapt}"
def vMarkwon = '4.1.1'
def vMarkwon = '4.1.2'
implementation "io.noties.markwon:core:${vMarkwon}"
implementation "io.noties.markwon:html:${vMarkwon}"
implementation "io.noties.markwon:image:${vMarkwon}"
@@ -112,7 +112,7 @@ dependencies {
replacedBy('com.github.topjohnwu:room-runtime')
}
}
def vRoom = "2.2.0"
def vRoom = "2.2.1"
implementation "com.github.topjohnwu:room-runtime:${vRoom}"
kapt "androidx.room:room-compiler:${vRoom}"
@@ -123,11 +123,12 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03'
implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0-beta05'
implementation 'androidx.recyclerview:recyclerview:1.1.0-rc01'
implementation 'androidx.fragment:fragment-ktx:1.2.0-rc01'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.work:work-runtime:2.2.0'
implementation 'androidx.transition:transition:1.2.0'
implementation 'androidx.transition:transition:1.3.0-rc01'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'com.google.android.material:material:1.1.0-beta01'
implementation 'com.google.android.material:material:1.2.0-alpha01'
}

View File

@@ -32,7 +32,11 @@
-keep,allowobfuscation class * extends com.topjohnwu.magisk.base.DelegateWorker
# BootSigner
-keepclassmembers class com.topjohnwu.signing.BootSigner { *; }
-keep class a.a { *; }
# Workaround R8 bug
-keep,allowobfuscation class com.topjohnwu.magisk.model.receiver.GeneralReceiver
-keepclassmembers class a.e { *; }
# Strip logging
-assumenosideeffects class timber.log.Timber.Tree { *; }

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

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

View File

@@ -1,4 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
** Special Requirements **
This AndroidManifest.xml will be copied into the stub
APK to allow APK delegation. This is why these special
requirements exist.
* Class names *
Class names a.a, a.c, a.e should not be changed as they are used
externally. All other class names can be changed.
* Resource IDs *
All resource IDs referred in AndroidManifest.xml is required to be
included into the "shared" module to make the ID match with stub.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.topjohnwu.magisk">
@@ -11,41 +29,46 @@
<application
android:name="a.e"
android:appComponentFactory="a.a"
android:allowBackup="true"
android:theme="@style/MagiskTheme"
android:usesCleartextTraffic="true"
tools:ignore="UnusedAttribute,GoogleAppIndexingWarning">
tools:ignore="UnusedAttribute,GoogleAppIndexingWarning"
tools:replace="android:appComponentFactory">
<!-- Activities -->
<!-- Splash -->
<activity
android:name="a.b"
android:configChanges="orientation|screenSize"
android:exported="true" />
<activity
android:name="a.c"
android:configChanges="orientation|screenSize"
android:exported="true"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Main -->
<activity
android:name="a.b"
android:configChanges="orientation|screenSize"
android:exported="true" />
<!-- Flashing -->
<activity
android:name="a.f"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="nosensor"
android:theme="@style/MagiskTheme.Flashing" />
android:screenOrientation="nosensor" />
<!-- Superuser -->
<activity
android:name="a.m"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:directBootAware="true"
android:excludeFromRecents="true"
android:exported="false"
android:theme="@style/MagiskTheme.SU" />
android:exported="false" />
<!-- Receiver -->
@@ -53,6 +76,7 @@
android:name="a.h"
android:directBootAware="true">
<intent-filter>
<action android:name="android.intent.action.REBOOT" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter>
@@ -64,9 +88,10 @@
</intent-filter>
</receiver>
<!-- Service -->
<!-- DownloadService -->
<service android:name="a.j"
<service
android:name="a.j"
android:exported="false" />
<!-- Hardcode GMS version -->
@@ -74,6 +99,12 @@
android:name="com.google.android.gms.version"
android:value="12451000" />
<!-- Initialize WorkManager on-demand -->
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
</application>
</manifest>

View File

@@ -1,13 +1,22 @@
package a;
import androidx.core.app.AppComponentFactory;
import com.topjohnwu.magisk.utils.PatchAPK;
import com.topjohnwu.signing.BootSigner;
import androidx.annotation.Keep;
public class a extends AppComponentFactory {
@Keep
public class a extends BootSigner {
@Deprecated
public static boolean patchAPK(String in, String out, String pkg) {
return PatchAPK.patch(in, out, pkg);
}
public static boolean patchAPK(String in, String out, String pkg, String label) {
return PatchAPK.patch(in, out, pkg, label);
}
public static void main(String[] args) throws Exception {
BootSigner.main(args);
}
}

View File

@@ -3,5 +3,11 @@ package a;
import com.topjohnwu.magisk.App;
public class e extends App {
/* stub */
public e() {
super();
}
public e(Object o) {
super(o);
}
}

View File

@@ -6,6 +6,7 @@ import android.content.res.Configuration
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDex
import androidx.room.Room
import androidx.work.WorkManager
import androidx.work.impl.WorkDatabase
import androidx.work.impl.WorkDatabase_Impl
import com.topjohnwu.magisk.data.database.RepoDatabase
@@ -13,20 +14,25 @@ import com.topjohnwu.magisk.data.database.RepoDatabase_Impl
import com.topjohnwu.magisk.di.ActivityTracker
import com.topjohnwu.magisk.di.koinModules
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.utils.LocaleManager
import com.topjohnwu.magisk.utils.RootUtils
import com.topjohnwu.magisk.extensions.unwrap
import com.topjohnwu.magisk.utils.RootInit
import com.topjohnwu.magisk.utils.updateConfig
import com.topjohnwu.superuser.Shell
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
import timber.log.Timber
open class App : Application() {
open class App() : Application() {
constructor(o: Any) : this() {
Info.stub = DynAPK.load(o)
}
init {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER or Shell.FLAG_USE_MAGISK_BUSYBOX)
Shell.Config.verboseLogging(BuildConfig.DEBUG)
Shell.Config.addInitializers(RootUtils::class.java)
Shell.Config.addInitializers(RootInit::class.java)
Shell.Config.setTimeout(2)
Room.setFactory {
when (it) {
@@ -38,22 +44,42 @@ open class App : Application() {
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
// Basic setup
if (BuildConfig.DEBUG)
MultiDex.install(base)
Timber.plant(Timber.DebugTree())
// Some context magic
val app: Application
val impl: Context
if (base is Application) {
app = base
impl = base.baseContext
} else {
app = this
impl = base
}
val wrapped = impl.wrap()
super.attachBaseContext(wrapped)
// Normal startup
startKoin {
androidContext(this@App)
androidContext(wrapped)
modules(koinModules)
}
ResourceMgr.init(impl)
app.registerActivityLifecycleCallbacks(get<ActivityTracker>())
WorkManager.initialize(impl.wrapJob(), androidx.work.Configuration.Builder().build())
}
registerActivityLifecycleCallbacks(get<ActivityTracker>())
LocaleManager.setLocale(this)
// This is required as some platforms expect ContextImpl
override fun getBaseContext(): Context {
return super.getBaseContext().unwrap()
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
LocaleManager.setLocale(this)
resources.updateConfig(newConfig)
if (!isRunningAsStub)
super.onConfigurationChanged(newConfig)
}
}

View File

@@ -1,26 +0,0 @@
package com.topjohnwu.magisk
import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
import com.topjohnwu.magisk.model.update.UpdateCheckService
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.ui.flash.FlashActivity
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
object ClassMap {
private val map = mapOf(
App::class.java to a.e::class.java,
MainActivity::class.java to a.b::class.java,
SplashActivity::class.java to a.c::class.java,
FlashActivity::class.java to a.f::class.java,
UpdateCheckService::class.java to a.g::class.java,
GeneralReceiver::class.java to a.h::class.java,
DownloadService::class.java to a.j::class.java,
SuRequestActivity::class.java to a.m::class.java
)
operator fun <T : Class<*>>get(c: Class<*>): T {
return map.getOrElse(c) { throw IllegalArgumentException() } as T
}
}

View File

@@ -32,8 +32,9 @@ object Config : PreferenceModel, DBConfig {
const val ROOT_ACCESS = "root_access"
const val SU_MULTIUSER_MODE = "multiuser_mode"
const val SU_MNT_NS = "mnt_ns"
const val SU_MANAGER = "requester"
const val SU_FINGERPRINT = "su_fingerprint"
const val SU_MANAGER = "requester"
const val KEYSTORE = "keystore"
// prefs
const val SU_REQUEST_TIMEOUT = "su_request_timeout"
@@ -97,7 +98,12 @@ object Config : PreferenceModel, DBConfig {
}
private val defaultChannel =
if (Utils.isCanary) Value.CANARY_DEBUG_CHANNEL
if (Utils.isCanary) {
if (BuildConfig.DEBUG)
Value.CANARY_DEBUG_CHANNEL
else
Value.CANARY_CHANNEL
}
else Value.DEFAULT_CHANNEL
var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS)
@@ -123,6 +129,7 @@ object Config : PreferenceModel, DBConfig {
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY)
var suFingerprint by dbSettings(Key.SU_FINGERPRINT, false)
var suManager by dbStrings(Key.SU_MANAGER, "", true)
var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true)
// Always return a path in external storage where we can write
val downloadDirectory get() =
@@ -131,9 +138,6 @@ object Config : PreferenceModel, DBConfig {
fun initialize() = prefs.edit {
parsePrefs(this)
if (!prefs.contains(Key.UPDATE_CHANNEL))
putString(Key.UPDATE_CHANNEL, defaultChannel.toString())
// Get actual state
putBoolean(Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists())
@@ -142,6 +146,9 @@ object Config : PreferenceModel, DBConfig {
putString(Key.SU_MNT_NS, suMntNamespaceMode.toString())
putString(Key.SU_MULTIUSER_MODE, suMultiuserMode.toString())
putBoolean(Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint())
}.also {
if (!prefs.contains(Key.UPDATE_CHANNEL))
prefs.edit().putString(Key.UPDATE_CHANNEL, defaultChannel.toString()).apply()
}
private fun parsePrefs(editor: SharedPreferences.Editor) = editor.apply {
@@ -205,4 +212,4 @@ object Config : PreferenceModel, DBConfig {
Shell.su("cat $xml > /data/adb/${Const.MANAGER_CONFIGS}").exec()
}
}
}

View File

@@ -22,8 +22,9 @@ object Const {
const val MANAGER_CONFIGS = ".tmp.magisk.config"
val USER_ID = Process.myUid() / 100000
object MagiskVersion {
object Version {
const val MIN_SUPPORT = 18000
const val CONNECT_MODE = 20002
}
object ID {

View File

@@ -0,0 +1,199 @@
@file:Suppress("DEPRECATION")
package com.topjohnwu.magisk
import android.annotation.SuppressLint
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.app.job.JobWorkItem
import android.content.ComponentName
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.res.AssetManager
import android.content.res.Configuration
import android.content.res.Resources
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import com.topjohnwu.magisk.extensions.langTagToLocale
import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
import com.topjohnwu.magisk.model.update.UpdateCheckService
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.ui.flash.FlashActivity
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.magisk.utils.defaultLocale
import com.topjohnwu.magisk.utils.refreshLocale
import com.topjohnwu.magisk.utils.updateConfig
import java.util.*
fun AssetManager.addAssetPath(path: String) {
DynAPK.addAssetPath(this, path)
}
fun Context.wrap(global: Boolean = true): Context
= if (global) GlobalResContext(this) else ResContext(this)
fun Context.wrapJob(): Context = object : GlobalResContext(this) {
override fun getApplicationContext(): Context {
return this
}
@SuppressLint("NewApi")
override fun getSystemService(name: String): Any? {
return if (!isRunningAsStub) super.getSystemService(name) else
when (name) {
Context.JOB_SCHEDULER_SERVICE ->
JobSchedulerWrapper(super.getSystemService(name) as JobScheduler)
else -> super.getSystemService(name)
}
}
}
fun Class<*>.cmp(pkg: String = BuildConfig.APPLICATION_ID): ComponentName {
val name = ClassMap[this].name
return ComponentName(pkg, Info.stub?.componentMap?.get(name) ?: name)
}
fun Context.intent(c: Class<*>): Intent {
val cls = ClassMap[c]
return Info.stub?.let {
val className = it.componentMap.getOrElse(cls.name) { cls.name }
Intent().setComponent(ComponentName(this, className))
} ?: Intent(this, cls)
}
private open class GlobalResContext(base: Context) : ContextWrapper(base) {
open val mRes: Resources get() = ResourceMgr.resource
private val loader by lazy { javaClass.classLoader!! }
override fun getResources(): Resources {
return mRes
}
override fun getClassLoader(): ClassLoader {
return loader
}
override fun createConfigurationContext(config: Configuration): Context {
return ResContext(super.createConfigurationContext(config))
}
}
private class ResContext(base: Context) : GlobalResContext(base) {
override val mRes by lazy { base.resources.patch() }
private fun Resources.patch(): Resources {
updateConfig()
if (isRunningAsStub)
assets.addAssetPath(ResourceMgr.resApk)
return this
}
}
object ResourceMgr {
lateinit var resource: Resources
lateinit var resApk: String
fun init(context: Context) {
resource = context.resources
refreshLocale()
if (isRunningAsStub) {
resApk = DynAPK.current(context).path
resource.assets.addAssetPath(resApk)
}
}
}
@RequiresApi(api = 28)
private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler() {
override fun schedule(job: JobInfo): Int {
return base.schedule(job.patch())
}
override fun enqueue(job: JobInfo, work: JobWorkItem): Int {
return base.enqueue(job.patch(), work)
}
override fun cancel(jobId: Int) {
base.cancel(jobId)
}
override fun cancelAll() {
base.cancelAll()
}
override fun getAllPendingJobs(): List<JobInfo> {
return base.allPendingJobs
}
override fun getPendingJob(jobId: Int): JobInfo? {
return base.getPendingJob(jobId)
}
private fun JobInfo.patch(): JobInfo {
// We need to patch the component of JobInfo to access WorkManager SystemJobService
val name = service.className
val component = ComponentName(
service.packageName,
Info.stub!!.componentMap[name] ?: name)
// Clone the JobInfo except component
val builder = JobInfo.Builder(id, component)
.setExtras(extras)
.setTransientExtras(transientExtras)
.setClipData(clipData, clipGrantFlags)
.setRequiredNetwork(requiredNetwork)
.setEstimatedNetworkBytes(estimatedNetworkDownloadBytes, estimatedNetworkUploadBytes)
.setRequiresCharging(isRequireCharging)
.setRequiresDeviceIdle(isRequireDeviceIdle)
.setRequiresBatteryNotLow(isRequireBatteryNotLow)
.setRequiresStorageNotLow(isRequireStorageNotLow)
.also {
triggerContentUris?.let { uris ->
for (uri in uris)
it.addTriggerContentUri(uri)
}
}
.setTriggerContentUpdateDelay(triggerContentUpdateDelay)
.setTriggerContentMaxDelay(triggerContentMaxDelay)
.setImportantWhileForeground(isImportantWhileForeground)
.setPrefetch(isPrefetch)
.setPersisted(isPersisted)
if (isPeriodic) {
builder.setPeriodic(intervalMillis, flexMillis)
} else {
if (minLatencyMillis > 0)
builder.setMinimumLatency(minLatencyMillis)
if (maxExecutionDelayMillis > 0)
builder.setOverrideDeadline(maxExecutionDelayMillis)
}
if (!isRequireDeviceIdle)
builder.setBackoffCriteria(initialBackoffMillis, backoffPolicy)
return builder.build()
}
}
object ClassMap {
private val map = mapOf(
App::class.java to a.e::class.java,
MainActivity::class.java to a.b::class.java,
SplashActivity::class.java to a.c::class.java,
FlashActivity::class.java to a.f::class.java,
UpdateCheckService::class.java to a.g::class.java,
GeneralReceiver::class.java to a.h::class.java,
DownloadService::class.java to a.j::class.java,
SuRequestActivity::class.java to a.m::class.java
)
operator fun get(c: Class<*>) = map.getOrElse(c) { throw IllegalArgumentException() }
}

View File

@@ -1,26 +1,62 @@
package com.topjohnwu.magisk
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.entity.UpdateInfo
import com.topjohnwu.magisk.utils.CachedValue
import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
val isRunningAsStub get() = Info.stub != null
object Info {
var magiskVersionCode = -1
val envRef = CachedValue { loadState() }
var magiskVersionString = ""
var remote = UpdateInfo()
val env by envRef // Local
var remote = UpdateInfo() // Remote
var stub: DynAPK.Data? = null // Stub
var keepVerity = false
var keepEnc = false
var recovery = false
fun loadMagiskInfo() {
runCatching {
magiskVersionString = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0]
magiskVersionCode = ShellUtils.fastCmd("magisk -V").toInt()
Config.magiskHide = Shell.su("magiskhide --status").exec().isSuccess
val isConnected by lazy {
KObservableField(false).also { field ->
ReactiveNetwork.observeNetworkConnectivity(get())
.subscribeK {
field.value = it.available()
}
}
}
private fun loadState() = runCatching {
val str = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0]
val code = ShellUtils.fastCmd("magisk -V").toInt()
val hide = Shell.su("magiskhide --status").exec().isSuccess
var mode = -1
if (code >= Const.Version.CONNECT_MODE) {
mode = Shell.su("magisk --connect-mode").exec().code
if (mode == 0) {
// Manually trigger broadcast test
Shell.su("magisk --broadcast-test").exec()
}
}
Env(code, str, hide, mode)
}.getOrElse { Env() }
class Env(
val magiskVersionCode: Int = -1,
val magiskVersionString: String = "",
hide: Boolean = false,
var connectionMode: Int = -1
) {
val magiskHide get() = Config.magiskHide
init {
Config.magiskHide = hide
}
}
}

View File

@@ -15,12 +15,13 @@ import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.viewmodel.BaseViewModel
import com.topjohnwu.magisk.extensions.set
import com.topjohnwu.magisk.model.events.EventHandler
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
import com.topjohnwu.magisk.utils.LocaleManager
import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.magisk.wrap
import kotlin.random.Random
typealias RequestCallback = BaseActivity<*, *>.(Int, Intent?) -> Unit
@@ -31,9 +32,8 @@ abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding
protected lateinit var binding: Binding
protected abstract val layoutRes: Int
protected abstract val viewModel: ViewModel
protected open val themeRes: Int = R.style.MagiskTheme
protected open val snackbarView get() = binding.root
protected open val navHostId: Int = 0
protected open val defaultPosition: Int = 0
private val resultCallbacks by lazy { SparseArrayCompat<RequestCallback>() }
@@ -53,10 +53,11 @@ abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(LocaleManager.getLocaleContext(base))
super.attachBaseContext(base.wrap(false))
}
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(themeRes)
super.onCreate(savedInstanceState)
viewModel.viewEvents.observe(this, viewEventObserver)

View File

@@ -0,0 +1,17 @@
package com.topjohnwu.magisk.base
import android.content.BroadcastReceiver
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import com.topjohnwu.magisk.wrap
import org.koin.core.KoinComponent
abstract class BaseReceiver : BroadcastReceiver(), KoinComponent {
final override fun onReceive(context: Context, intent: Intent?) {
onReceive(context.wrap() as ContextWrapper, intent)
}
abstract fun onReceive(context: ContextWrapper, intent: Intent?)
}

View File

@@ -0,0 +1,12 @@
package com.topjohnwu.magisk.base
import android.app.Service
import android.content.Context
import com.topjohnwu.magisk.wrap
import org.koin.core.KoinComponent
abstract class BaseService : Service(), KoinComponent {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base.wrap())
}
}

View File

@@ -1,28 +1,24 @@
package com.topjohnwu.magisk.base.viewmodel
import android.app.Activity
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.topjohnwu.magisk.extensions.doOnSubscribeUi
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.events.BackPressEvent
import com.topjohnwu.magisk.model.events.PermissionEvent
import com.topjohnwu.magisk.model.events.ViewActionEvent
import com.topjohnwu.magisk.utils.KObservableField
import io.reactivex.Observable
import io.reactivex.subjects.PublishSubject
import com.topjohnwu.magisk.Info.isConnected as gIsConnected
abstract class BaseViewModel(
initialState: State = State.LOADING
) : LoadingViewModel(initialState) {
val isConnected = KObservableField(false)
init {
ReactiveNetwork.observeNetworkConnectivity(get())
.subscribeK { isConnected.value = it.available() }
.add()
val isConnected = object : KObservableField<Boolean>(gIsConnected.value, gIsConnected) {
override fun get(): Boolean {
return gIsConnected.value
}
}
fun withView(action: Activity.() -> Unit) {

View File

@@ -29,7 +29,7 @@ class MagiskRepository(
else -> throw IllegalArgumentException()
}.flatMap {
// If remote version is lower than current installed, try switching to beta
if (it.magisk.versionCode < Info.magiskVersionCode
if (it.magisk.versionCode < Info.env.magiskVersionCode
&& Config.updateChannel == Config.Value.DEFAULT_CHANNEL) {
Config.updateChannel = Config.Value.BETA_CHANNEL
apiRaw.fetchBetaUpdate()
@@ -74,4 +74,4 @@ class MagiskRepository(
) }
}
}
}

View File

@@ -1,6 +1,8 @@
package com.topjohnwu.magisk.extensions
import android.content.ComponentName
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.ComponentInfo
@@ -10,19 +12,30 @@ import android.content.pm.PackageManager.*
import android.content.res.Configuration
import android.content.res.Resources
import android.database.Cursor
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.AdaptiveIconDrawable
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.LayerDrawable
import android.net.Uri
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.provider.OpenableColumns
import android.view.View
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import com.topjohnwu.magisk.utils.FileProvider
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.FileProvider
import com.topjohnwu.magisk.utils.DynamicClassLoader
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.superuser.Shell
import java.io.File
import java.io.FileNotFoundException
import java.lang.reflect.Array as JArray
val packageName: String get() = get<Context>().packageName
@@ -91,8 +104,129 @@ fun Context.rawResource(id: Int) = resources.openRawResource(id)
fun Context.readUri(uri: Uri) =
contentResolver.openInputStream(uri) ?: throw FileNotFoundException()
fun Context.getBitmap(id: Int): Bitmap {
var drawable = AppCompatResources.getDrawable(this, id)!!
if (drawable is BitmapDrawable)
return drawable.bitmap
if (SDK_INT >= 26 && drawable is AdaptiveIconDrawable) {
drawable = LayerDrawable(arrayOf(drawable.background, drawable.foreground))
}
val bitmap = Bitmap.createBitmap(
drawable.intrinsicWidth, drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
fun Intent.startActivity(context: Context) = context.startActivity(this)
fun Intent.startActivityWithRoot() {
val args = mutableListOf("am", "start", "--user", Const.USER_ID.toString())
val cmd = toCommand(args).joinToString(" ")
Shell.su(cmd).submit()
}
fun Intent.toCommand(args: MutableList<String> = mutableListOf()): MutableList<String> {
action?.also {
args.add("-a")
args.add(it)
}
component?.also {
args.add("-n")
args.add(it.flattenToString())
}
data?.also {
args.add("-d")
args.add(it.toString())
}
categories?.also {
for (cat in it) {
args.add("-c")
args.add(cat)
}
}
type?.also {
args.add("-t")
args.add(it)
}
extras?.also {
loop@ for (key in it.keySet()) {
val v = it[key] ?: continue
var value: Any = v
val arg: String
when {
v is String -> arg = "--es"
v is Boolean -> arg = "--ez"
v is Int -> arg = "--ei"
v is Long -> arg = "--el"
v is Float -> arg = "--ef"
v is Uri -> arg = "--eu"
v is ComponentName -> {
arg = "--ecn"
value = v.flattenToString()
}
v is List<*> -> {
if (v.isEmpty())
continue@loop
arg = if (v[0] is Int)
"--eial"
else if (v[0] is Long)
"--elal"
else if (v[0] is Float)
"--efal"
else if (v[0] is String)
"--esal"
else
continue@loop /* Unsupported */
val sb = StringBuilder()
for (o in v) {
sb.append(o.toString().replace(",", "\\,"))
sb.append(',')
}
// Remove trailing comma
sb.deleteCharAt(sb.length - 1)
value = sb
}
v.javaClass.isArray -> {
arg = if (v is IntArray)
"--eia"
else if (v is LongArray)
"--ela"
else if (v is FloatArray)
"--efa"
else if (v is Array<*> && v.isArrayOf<String>())
"--esa"
else
continue@loop /* Unsupported */
val sb = StringBuilder()
val len = JArray.getLength(v)
for (i in 0 until len) {
sb.append(JArray.get(v, i)!!.toString().replace(",", "\\,"))
sb.append(',')
}
// Remove trailing comma
sb.deleteCharAt(sb.length - 1)
value = sb
}
else -> continue@loop
} /* Unsupported */
args.add(arg)
args.add(key)
args.add(value.toString())
}
}
args.add("-f")
args.add(flags.toString())
return args
}
fun File.provide(context: Context = get()): Uri {
return FileProvider.getUriForFile(context, context.packageName + ".provider", this)
}
@@ -157,3 +291,18 @@ fun Context.startEndToLeftRight(start: Int, end: Int): Pair<Int, Int> {
}
fun Context.openUrl(url: String) = Utils.openLink(this, url.toUri())
@Suppress("FunctionName")
inline fun <reified T> T.DynamicClassLoader(apk: File)
= DynamicClassLoader(apk, T::class.java.classLoader)
fun Context.unwrap() : Context {
var context = this
while (true) {
if (context is ContextWrapper)
context = context.baseContext
else
break
}
return context
}

View File

@@ -25,3 +25,5 @@ fun String.trimEmptyToNull(): String? = if (isBlank()) null else this
fun String.legalFilename() = replace(" ", "_").replace("'", "").replace("\"", "")
.replace("$", "").replace("`", "").replace("*", "").replace("/", "_")
.replace("#", "").replace("@", "").replace("\\", "_")
fun String.isEmptyInternal() = isNullOrBlank()

View File

@@ -1,17 +1,17 @@
package com.topjohnwu.magisk.model.download
import android.annotation.SuppressLint
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import android.webkit.MimeTypeMap
import androidx.core.app.NotificationCompat
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.chooser
import com.topjohnwu.magisk.extensions.exists
import com.topjohnwu.magisk.extensions.provide
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.entity.internal.Configuration.*
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
@@ -63,20 +63,20 @@ open class DownloadService : RemoteFileService() {
remove(id)
when (subject.configuration) {
is APK.Upgrade -> APKInstall.install(this, subject.file)
else -> Unit
is APK.Restore -> Unit
}
}
// ---
override fun NotificationCompat.Builder.addActions(subject: DownloadSubject)
override fun Notification.Builder.addActions(subject: DownloadSubject)
= when (subject) {
is Magisk -> addActionsInternal(subject)
is Module -> addActionsInternal(subject)
is Manager -> addActionsInternal(subject)
}
private fun NotificationCompat.Builder.addActionsInternal(subject: Magisk)
private fun Notification.Builder.addActionsInternal(subject: Magisk)
= when (val conf = subject.configuration) {
Download -> this.apply {
fileIntent(subject.file.parentFile!!)
@@ -92,7 +92,7 @@ open class DownloadService : RemoteFileService() {
else -> this
}
private fun NotificationCompat.Builder.addActionsInternal(subject: Module)
private fun Notification.Builder.addActionsInternal(subject: Module)
= when (subject.configuration) {
Download -> this.apply {
fileIntent(subject.file.parentFile!!)
@@ -106,19 +106,19 @@ open class DownloadService : RemoteFileService() {
else -> this
}
private fun NotificationCompat.Builder.addActionsInternal(subject: Manager)
private fun Notification.Builder.addActionsInternal(subject: Manager)
= when (subject.configuration) {
APK.Upgrade -> setContentIntent(APKInstall.installIntent(context, subject.file))
else -> this
}
@Suppress("ReplaceSingleLineLet")
private fun NotificationCompat.Builder.setContentIntent(intent: Intent) =
private fun Notification.Builder.setContentIntent(intent: Intent) =
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
.let { setContentIntent(it) }
@Suppress("ReplaceSingleLineLet")
private fun NotificationCompat.Builder.addAction(icon: Int, title: Int, intent: Intent) =
private fun Notification.Builder.addAction(icon: Int, title: Int, intent: Intent) =
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
.let { addAction(icon, getString(title), it) }
@@ -140,8 +140,7 @@ open class DownloadService : RemoteFileService() {
inline operator fun invoke(context: Context, argBuilder: Builder.() -> Unit) {
val app = context.applicationContext
val builder = Builder().apply(argBuilder)
val intent = Intent(app, ClassMap[DownloadService::class.java])
.putExtra(ARG_URL, builder.subject)
val intent = app.intent(DownloadService::class.java).putExtra(ARG_URL, builder.subject)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
app.startForegroundService(intent)
@@ -152,4 +151,4 @@ open class DownloadService : RemoteFileService() {
}
}
}

View File

@@ -1,43 +1,47 @@
package com.topjohnwu.magisk.model.download
import android.content.ComponentName
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.extensions.writeTo
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.utils.DynamicClassLoader
import com.topjohnwu.magisk.utils.PatchAPK
import com.topjohnwu.magisk.utils.RootUtils
import com.topjohnwu.superuser.Shell
import timber.log.Timber
import java.io.File
private fun RemoteFileService.patchPackage(apk: File, id: Int) {
if (packageName != BuildConfig.APPLICATION_ID) {
update(id) { notification ->
notification.setProgress(0, 0, true)
.setProgress(0, 0, true)
.setContentTitle(getString(R.string.hide_manager_title))
.setContentText("")
}
val patched = File(apk.parent, "patched.apk")
try {
// Try using the new APK to patch itself
val loader = DynamicClassLoader(apk)
loader.loadClass("a.a")
.getMethod("patchAPK", String::class.java, String::class.java, String::class.java)
.invoke(null, apk.path, patched.path, packageName)
} catch (e: Exception) {
Timber.e(e)
// Fallback to use the current implementation
PatchAPK.patch(apk.path, patched.path, packageName)
}
private fun RemoteFileService.patch(apk: File, id: Int) {
if (packageName == BuildConfig.APPLICATION_ID)
return
update(id) { notification ->
notification.setProgress(0, 0, true)
.setProgress(0, 0, true)
.setContentTitle(getString(R.string.hide_manager_title))
.setContentText("")
}
val patched = File(apk.parent, "patched.apk")
PatchAPK.patch(apk, patched, packageName, applicationInfo.nonLocalizedLabel.toString())
apk.delete()
patched.renameTo(apk)
}
private fun RemoteFileService.upgrade(apk: File, id: Int) {
if (isRunningAsStub) {
// Move to upgrade location
apk.copyTo(DynAPK.update(this), overwrite = true)
apk.delete()
patched.renameTo(apk)
if (Info.stub!!.version < Info.remote.stub.versionCode) {
// We also want to upgrade stub
service.fetchFile(Info.remote.stub.link).blockingGet().byteStream().use {
it.writeTo(apk)
}
patch(apk, id)
} else {
// Simply relaunch the app
ProcessPhoenix.triggerRebirth(this)
}
} else {
patch(apk, id)
}
}
@@ -51,15 +55,11 @@ private fun RemoteFileService.restore(apk: File, id: Int) {
Config.export()
// Make it world readable
apk.setReadable(true, false)
if (Shell.su("pm install $apk").exec().isSuccess) {
val component = ComponentName(BuildConfig.APPLICATION_ID,
ClassMap.get<Class<*>>(SplashActivity::class.java).name)
RootUtils.rmAndLaunch(packageName, component)
}
Shell.su("pm install $apk && pm uninstall $packageName").exec()
}
fun RemoteFileService.handleAPK(subject: DownloadSubject.Manager)
= when (subject.configuration) {
is Upgrade -> patchPackage(subject.file, subject.hashCode())
is Upgrade -> upgrade(subject.file, subject.hashCode())
is Restore -> restore(subject.file, subject.hashCode())
}

View File

@@ -1,24 +1,22 @@
package com.topjohnwu.magisk.model.download
import android.app.Notification
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.topjohnwu.magisk.base.BaseService
import com.topjohnwu.magisk.view.Notifications
import org.koin.core.KoinComponent
import java.util.*
import kotlin.random.Random.Default.nextInt
abstract class NotificationService : Service(), KoinComponent {
abstract class NotificationService : BaseService(), KoinComponent {
abstract val defaultNotification: NotificationCompat.Builder
abstract val defaultNotification: Notification.Builder
private val manager by lazy { NotificationManagerCompat.from(this) }
private val hasNotifications get() = notifications.isNotEmpty()
private val notifications =
Collections.synchronizedMap(mutableMapOf<Int, NotificationCompat.Builder>())
Collections.synchronizedMap(mutableMapOf<Int, Notification.Builder>())
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
@@ -30,7 +28,7 @@ abstract class NotificationService : Service(), KoinComponent {
fun update(
id: Int,
body: (NotificationCompat.Builder) -> Unit = {}
body: (Notification.Builder) -> Unit = {}
) {
val notification = notifications.getOrPut(id) { defaultNotification }
@@ -43,7 +41,7 @@ abstract class NotificationService : Service(), KoinComponent {
protected fun finishNotify(
id: Int,
editBody: (NotificationCompat.Builder) -> NotificationCompat.Builder? = { null }
editBody: (Notification.Builder) -> Notification.Builder? = { null }
) : Int {
val currentNotification = remove(id)?.run(editBody)
@@ -62,11 +60,11 @@ abstract class NotificationService : Service(), KoinComponent {
// ---
private fun notify(id: Int, notification: Notification) {
manager.notify(id, notification)
Notifications.mgr.notify(id, notification)
}
private fun cancel(id: Int) {
manager.cancel(id)
Notifications.mgr.cancel(id)
}
protected fun remove(id: Int) = notifications.remove(id).also {
@@ -84,4 +82,4 @@ abstract class NotificationService : Service(), KoinComponent {
// --
override fun onBind(p0: Intent?): IBinder? = null
}
}

View File

@@ -1,8 +1,8 @@
package com.topjohnwu.magisk.model.download
import android.app.Activity
import android.app.Notification
import android.content.Intent
import androidx.core.app.NotificationCompat
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.network.GithubRawServices
import com.topjohnwu.magisk.di.NullActivity
@@ -22,9 +22,9 @@ import java.io.InputStream
abstract class RemoteFileService : NotificationService() {
private val service: GithubRawServices by inject()
val service: GithubRawServices by inject()
override val defaultNotification: NotificationCompat.Builder
override val defaultNotification
get() = Notifications.progress(this, "")
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@@ -108,11 +108,11 @@ abstract class RemoteFileService : NotificationService() {
@Throws(Throwable::class)
protected abstract fun onFinished(subject: DownloadSubject, id: Int)
protected abstract fun NotificationCompat.Builder.addActions(subject: DownloadSubject)
: NotificationCompat.Builder
protected abstract fun Notification.Builder.addActions(subject: DownloadSubject)
: Notification.Builder
companion object {
const val ARG_URL = "arg_url"
}
}
}

View File

@@ -8,7 +8,8 @@ import se.ansman.kotshi.JsonSerializable
data class UpdateInfo(
val app: ManagerJson = ManagerJson(),
val uninstaller: UninstallerJson = UninstallerJson(),
val magisk: MagiskJson = MagiskJson()
val magisk: MagiskJson = MagiskJson(),
val stub: StubJson = StubJson()
)
@JsonSerializable
@@ -33,3 +34,9 @@ data class ManagerJson(
val link: String = "",
val note: String = ""
) : Parcelable
@JsonSerializable
data class StubJson(
val versionCode: Int = -1,
val link: String = ""
)

View File

@@ -1,16 +1,15 @@
package com.topjohnwu.magisk.model.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import android.os.Build.VERSION.SDK_INT
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.base.BaseReceiver
import com.topjohnwu.magisk.data.database.PolicyDao
import com.topjohnwu.magisk.data.database.base.su
import com.topjohnwu.magisk.extensions.inject
import com.topjohnwu.magisk.extensions.reboot
import com.topjohnwu.magisk.extensions.startActivity
import com.topjohnwu.magisk.extensions.startActivityWithRoot
import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.entity.ManagerJson
import com.topjohnwu.magisk.model.entity.internal.Configuration
@@ -20,8 +19,10 @@ import com.topjohnwu.magisk.utils.SuLogger
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
import org.koin.core.inject
import timber.log.Timber
open class GeneralReceiver : BroadcastReceiver() {
open class GeneralReceiver : BaseReceiver() {
private val policyDB: PolicyDao by inject()
@@ -36,8 +37,19 @@ open class GeneralReceiver : BroadcastReceiver() {
return intent.data?.encodedSchemeSpecificPart.orEmpty()
}
override fun onReceive(context: Context, intent: Intent?) {
override fun onReceive(context: ContextWrapper, intent: Intent?) {
intent ?: return
// Debug messages
if (BuildConfig.DEBUG) {
Timber.d(intent.action)
intent.extras?.let { bundle ->
bundle.keySet().forEach {
Timber.d("[%s]=[%s]", it, bundle[it])
}
}
}
when (intent.action ?: return) {
Intent.ACTION_REBOOT, Intent.ACTION_BOOT_COMPLETED -> {
val action = intent.getStringExtra("action")
@@ -51,16 +63,26 @@ open class GeneralReceiver : BroadcastReceiver() {
}
when (action) {
REQUEST -> {
val i = Intent(context, ClassMap[SuRequestActivity::class.java])
val i = context.intent(SuRequestActivity::class.java)
.setAction(action)
.putExtra("socket", intent.getStringExtra("socket"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
context.startActivity(i)
if (SDK_INT >= 29) {
// Android Q does not allow starting activity from background
i.startActivityWithRoot()
} else {
i.startActivity(context)
}
}
LOG -> SuLogger.handleLogs(context, intent)
NOTIFY -> SuLogger.handleNotify(context, intent)
TEST -> {
val mode = intent.getIntExtra("mode", 1 shl 1)
if (mode > Info.env.connectionMode)
Info.env.connectionMode = mode
Shell.su("magisk --connect-mode $mode").submit()
}
LOG -> SuLogger.handleLogs(intent)
NOTIFY -> SuLogger.handleNotify(intent)
TEST -> Shell.su("magisk --use-broadcast").submit()
}
}
Intent.ACTION_PACKAGE_REPLACED ->

View File

@@ -20,7 +20,7 @@ class UpdateCheckService : DelegateWorker() {
magiskRepo.fetchUpdate().blockingGet()
if (BuildConfig.VERSION_CODE < Info.remote.app.versionCode)
Notifications.managerUpdate(applicationContext)
else if (Info.magiskVersionCode < Info.remote.magisk.versionCode)
else if (Info.env.magiskVersionCode < Info.remote.magisk.versionCode)
Notifications.magiskUpdate(applicationContext)
ListenableWorker.Result.success()
}.getOrElse {

View File

@@ -266,7 +266,7 @@ abstract class MagiskInstaller {
val patched = File(installDir, "new-boot.img")
if (isSigned) {
console.add("- Signing boot image with test keys")
console.add("- Signing boot image with verity keys")
val signed = File(installDir, "signed.img")
try {
withStreams(SuFileInputStream(patched), signed.outputStream().buffered()) {

View File

@@ -7,8 +7,6 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import com.ncapdevi.fragnav.FragNavController
import com.ncapdevi.fragnav.FragNavTransactionOptions
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const.Key.OPEN_SECTION
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R
@@ -17,6 +15,7 @@ import com.topjohnwu.magisk.base.BaseFragment
import com.topjohnwu.magisk.databinding.ActivityMainBinding
import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback
import com.topjohnwu.magisk.extensions.snackbar
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.*
import com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder
import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
@@ -40,8 +39,8 @@ open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Na
override val layoutRes: Int = R.layout.activity_main
override val viewModel: MainViewModel by viewModel()
override val navHostId: Int = R.id.main_nav_host
override val defaultPosition: Int = 0
private val navHostId: Int = R.id.main_nav_host
private val defaultPosition: Int = 0
private val navigationController by lazy {
FragNavController(supportFragmentManager, navHostId)
@@ -61,7 +60,7 @@ open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Na
override fun onCreate(savedInstanceState: Bundle?) {
if (!SplashActivity.DONE) {
startActivity(Intent(this, ClassMap[SplashActivity::class.java]))
startActivity(intent(SplashActivity::class.java))
finish()
}
@@ -155,11 +154,11 @@ open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Na
private fun checkHideSection() {
val menu = binding.navView.menu
menu.findItem(R.id.magiskHideFragment).isVisible =
Shell.rootAccess() && Config.magiskHide
Shell.rootAccess() && Info.env.magiskHide
menu.findItem(R.id.modulesFragment).isVisible =
Shell.rootAccess() && Info.magiskVersionCode >= 0
Shell.rootAccess() && Info.env.magiskVersionCode >= 0
menu.findItem(R.id.reposFragment).isVisible =
(viewModel.isConnected.value && Shell.rootAccess() && Info.magiskVersionCode >= 0)
(viewModel.isConnected.value && Shell.rootAccess() && Info.env.magiskVersionCode >= 0)
menu.findItem(R.id.logFragment).isVisible =
Shell.rootAccess()
menu.findItem(R.id.superuserFragment).isVisible =

View File

@@ -1,27 +1,31 @@
package com.topjohnwu.magisk.ui
import android.content.Intent
import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
open class SplashActivity : AppCompatActivity() {
open class SplashActivity : Activity() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base.wrap())
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Shell.getShell {
if (Info.magiskVersionCode > 0 && Info.magiskVersionCode < Const.MagiskVersion.MIN_SUPPORT) {
if (Info.env.magiskVersionCode > 0 && Info.env.magiskVersionCode < Const.Version.MIN_SUPPORT) {
AlertDialog.Builder(this)
.setTitle(R.string.unsupport_magisk_title)
.setMessage(R.string.unsupport_magisk_message)
.setNegativeButton(R.string.ok, null)
.setNegativeButton(android.R.string.ok, null)
.setOnDismissListener { finish() }
.show()
} else {
@@ -56,7 +60,7 @@ open class SplashActivity : AppCompatActivity() {
// Setup shortcuts
Shortcuts.setup(this)
val intent = Intent(this, ClassMap[MainActivity::class.java])
val intent = intent(MainActivity::class.java)
intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION))
DONE = true
startActivity(intent)

View File

@@ -6,12 +6,12 @@ import android.net.Uri
import android.os.Bundle
import androidx.core.app.NotificationManagerCompat
import androidx.core.net.toUri
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseActivity
import com.topjohnwu.magisk.databinding.ActivityFlashBinding
import com.topjohnwu.magisk.extensions.snackbar
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.BackPressEvent
import com.topjohnwu.magisk.model.events.PermissionEvent
import com.topjohnwu.magisk.model.events.SnackbarEvent
@@ -23,6 +23,7 @@ import java.io.File
open class FlashActivity : BaseActivity<FlashViewModel, ActivityFlashBinding>() {
override val layoutRes: Int = R.layout.activity_flash
override val themeRes: Int = R.style.MagiskTheme_Flashing
override val viewModel: FlashViewModel by viewModel {
val uri = intent.data ?: let { finish(); Uri.EMPTY }
val additionalUri = intent.getParcelableExtra(Const.Key.FLASH_DATA) ?: uri
@@ -59,7 +60,7 @@ open class FlashActivity : BaseActivity<FlashViewModel, ActivityFlashBinding>()
companion object {
private fun intent(context: Context) = Intent(context, ClassMap[FlashActivity::class.java])
private fun intent(context: Context) = context.intent(FlashActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
private fun intent(context: Context, file: File) = intent(context).setData(file.toUri())

View File

@@ -9,11 +9,11 @@ import com.topjohnwu.magisk.base.BaseActivity
import com.topjohnwu.magisk.base.BaseFragment
import com.topjohnwu.magisk.data.repository.MagiskRepository
import com.topjohnwu.magisk.databinding.FragmentMagiskBinding
import com.topjohnwu.magisk.extensions.DynamicClassLoader
import com.topjohnwu.magisk.extensions.openUrl
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.extensions.writeTo
import com.topjohnwu.magisk.model.events.*
import com.topjohnwu.magisk.utils.DynamicClassLoader
import com.topjohnwu.magisk.utils.SafetyNetHelper
import com.topjohnwu.magisk.view.MarkDownWindow
import com.topjohnwu.magisk.view.dialogs.*
@@ -87,8 +87,8 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentMagiskBinding>(),
.setTitle(R.string.proprietary_title)
.setMessage(R.string.proprietary_notice)
.setCancelable(false)
.setPositiveButton(R.string.yes) { _, _ -> download() }
.setNegativeButton(R.string.no_thanks) { _, _ -> viewModel.finishSafetyNetCheck(-2) }
.setPositiveButton(android.R.string.yes) { _, _ -> download() }
.setNegativeButton(android.R.string.no) { _, _ -> viewModel.finishSafetyNetCheck(-2) }
.show()
}

View File

@@ -77,7 +77,7 @@ class HomeViewModel(
""
}
val safetyNetTitle = KObservableField(R.string.safetyNet_check_text)
val safetyNetTitle = KObservableField(R.string.safetyNet_check_text.res())
val ctsState = KObservableField(SafetyNetState.IDLE)
val basicIntegrityState = KObservableField(SafetyNetState.IDLE)
val safetyNetState = Observer(ctsState, basicIntegrityState) {
@@ -107,10 +107,10 @@ class HomeViewModel(
Info.recovery = it ?: return@addOnPropertyChangedCallback
}
isConnected.addOnPropertyChangedCallback {
if (it == true) refresh()
if (it == true) refresh(false)
}
refresh()
refresh(false)
}
fun paypalPressed() = OpenLinkEvent(Const.Url.PAYPAL_URL).publish()
@@ -135,7 +135,7 @@ class HomeViewModel(
fun safetyNetPressed() {
ctsState.value = SafetyNetState.LOADING
basicIntegrityState.value = SafetyNetState.LOADING
safetyNetTitle.value = R.string.checking_safetyNet_status
safetyNetTitle.value = R.string.checking_safetyNet_status.res()
UpdateSafetyNetEvent().publish()
}
@@ -144,7 +144,7 @@ class HomeViewModel(
response and 0x0F == 0 -> {
val hasCtsPassed = response and SafetyNetHelper.CTS_PASS != 0
val hasBasicIntegrityPassed = response and SafetyNetHelper.BASIC_PASS != 0
safetyNetTitle.value = R.string.safetyNet_check_success
safetyNetTitle.value = R.string.safetyNet_check_success.res()
ctsState.value = if (hasCtsPassed) {
SafetyNetState.PASS
} else {
@@ -164,13 +164,17 @@ class HomeViewModel(
ctsState.value = SafetyNetState.IDLE
basicIntegrityState.value = SafetyNetState.IDLE
safetyNetTitle.value = when (response) {
SafetyNetHelper.RESPONSE_ERR -> R.string.safetyNet_res_invalid
else -> R.string.safetyNet_api_error
SafetyNetHelper.RESPONSE_ERR -> R.string.safetyNet_res_invalid.res()
else -> R.string.safetyNet_api_error.res()
}
}
}
fun refresh() {
@JvmOverloads
fun refresh(invalidate: Boolean = true) {
if (invalidate)
Info.envRef.invalidate()
hasRoot.value = Shell.rootAccess()
val fetchUpdate = if (isConnected.value)
@@ -179,7 +183,8 @@ class HomeViewModel(
Completable.complete()
Completable.fromAction {
Info.loadMagiskInfo()
// Ensure value is ready
Info.env
}.andThen(fetchUpdate)
.applyViewModel(this)
.doOnSubscribeUi {
@@ -187,7 +192,7 @@ class HomeViewModel(
_managerState.value = MagiskState.LOADING
ctsState.value = SafetyNetState.IDLE
basicIntegrityState.value = SafetyNetState.IDLE
safetyNetTitle.value = R.string.safetyNet_check_text
safetyNetTitle.value = R.string.safetyNet_check_text.res()
}.subscribeK {
updateSelf()
ensureEnv()
@@ -197,33 +202,40 @@ class HomeViewModel(
private fun refreshVersions() {
magiskCurrentVersion.value = if (magiskState.value != MagiskState.NOT_INSTALLED) {
version.format(Info.magiskVersionString, Info.magiskVersionCode)
VERSION_FMT.format(Info.env.magiskVersionString, Info.env.magiskVersionCode)
} else {
""
}
managerCurrentVersion.value = version
.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
managerCurrentVersion.value = if (isRunningAsStub) MGR_VER_FMT
.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, Info.stub!!.version)
else
VERSION_FMT.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
}
private fun updateSelf() {
magiskState.value = when (Info.magiskVersionCode) {
in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED
!in Info.remote.magisk.versionCode..Int.MAX_VALUE -> MagiskState.OBSOLETE
magiskState.value = when (Info.env.magiskVersionCode) {
in Int.MIN_VALUE .. 0 -> MagiskState.NOT_INSTALLED
in 1 until Info.remote.magisk.versionCode -> MagiskState.OBSOLETE
else -> MagiskState.UP_TO_DATE
}
magiskLatestVersion.value = version
.format(Info.remote.magisk.version, Info.remote.magisk.versionCode)
magiskLatestVersion.value =
VERSION_FMT.format(Info.remote.magisk.version, Info.remote.magisk.versionCode)
_managerState.value = when (Info.remote.app.versionCode) {
in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED //wrong update channel
in (BuildConfig.VERSION_CODE + 1)..Int.MAX_VALUE -> MagiskState.OBSOLETE
else -> MagiskState.UP_TO_DATE
in Int.MIN_VALUE .. 0 -> MagiskState.NOT_INSTALLED //wrong update channel
in (BuildConfig.VERSION_CODE + 1) .. Int.MAX_VALUE -> MagiskState.OBSOLETE
else -> {
if (Info.stub?.version ?: Int.MAX_VALUE < Info.remote.stub.versionCode)
MagiskState.OBSOLETE
else
MagiskState.UP_TO_DATE
}
}
managerLatestVersion.value = version
.format(Info.remote.app.version, Info.remote.app.versionCode)
managerLatestVersion.value = MGR_VER_FMT
.format(Info.remote.app.version, Info.remote.app.versionCode, Info.remote.stub.versionCode)
}
private fun ensureEnv() {
@@ -240,7 +252,8 @@ class HomeViewModel(
}
companion object {
private const val version = "%s (%d)"
private const val VERSION_FMT = "%s (%d)"
private const val MGR_VER_FMT = "%s (%d) (%d)"
}
}

View File

@@ -8,12 +8,12 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseFragment
import com.topjohnwu.magisk.databinding.FragmentModulesBinding
import com.topjohnwu.magisk.extensions.reboot
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.OpenFilePickerEvent
import com.topjohnwu.magisk.model.events.ViewEvent
import com.topjohnwu.magisk.ui.flash.FlashActivity
@@ -28,7 +28,7 @@ class ModulesFragment : BaseFragment<ModuleViewModel, FragmentModulesBinding>()
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) {
// Get the URI of the selected file
val intent = Intent(activity, ClassMap[FlashActivity::class.java])
val intent = activity.intent(FlashActivity::class.java)
intent.setData(data.data).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP)
startActivity(intent)
}

View File

@@ -13,20 +13,16 @@ import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreferenceCompat
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.base.BasePreferenceFragment
import com.topjohnwu.magisk.data.database.RepoDao
import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding
import com.topjohnwu.magisk.databinding.DialogCustomNameBinding
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.extensions.toLangTag
import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.observer.Observer
import com.topjohnwu.magisk.net.Networking
import com.topjohnwu.magisk.utils.*
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
import com.topjohnwu.superuser.Shell
@@ -56,6 +52,7 @@ class SettingsFragment : BasePreferenceFragment() {
preferenceManager.setStorageDeviceProtected()
setPreferencesFromResource(R.xml.app_settings, rootKey)
// Get preferences
updateChannel = findPreference(Config.Key.UPDATE_CHANNEL)!!
rootConfig = findPreference(Config.Key.ROOT_ACCESS)!!
autoRes = findPreference(Config.Key.SU_AUTO_RESPONSE)!!
@@ -69,17 +66,68 @@ class SettingsFragment : BasePreferenceFragment() {
val magiskCategory = findPreference<PreferenceCategory>("magisk")!!
val suCategory = findPreference<PreferenceCategory>("superuser")!!
val hideManager = findPreference<Preference>("hide")!!
hideManager.setOnPreferenceClickListener {
PatchAPK.hideManager(requireContext())
true
val restoreManager = findPreference<Preference>("restore")!!
// Remove/Disable entries
// Only show canary channels if user is already on canary channel
// or the user have already chosen canary channel
if (!Utils.isCanary && Config.updateChannel < Config.Value.CANARY_CHANNEL) {
// Remove the last 2 entries
val entries = updateChannel.entries
updateChannel.entries = entries.copyOf(entries.size - 2)
}
val restoreManager = findPreference<Preference>("restore")
restoreManager?.setOnPreferenceClickListener {
DownloadService(requireContext()) {
subject = DownloadSubject.Manager(Configuration.APK.Restore)
// Remove dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserConfig)
}
// Remove re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
suCategory.removePreference(reauth)
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.isEnabled = false
fingerprint.isChecked = false
fingerprint.setSummary(R.string.disable_fingerprint)
}
if (Const.USER_ID == 0 && Info.isConnected.value && Shell.rootAccess()) {
if (activity.packageName == BuildConfig.APPLICATION_ID) {
generalCatagory.removePreference(restoreManager)
hideManager.setOnPreferenceClickListener {
showManagerNameDialog {
PatchAPK.hideManager(requireContext(), it)
}
true
}
} else {
generalCatagory.removePreference(hideManager)
restoreManager.setOnPreferenceClickListener {
DownloadService(requireContext()) {
subject = DownloadSubject.Manager(Configuration.APK.Restore)
}
true
}
}
true
} else {
// Remove if not primary user, no connection, or no root
generalCatagory.removePreference(restoreManager)
generalCatagory.removePreference(hideManager)
}
if (!Utils.showSuperUser()) {
preferenceScreen.removePreference(suCategory)
}
if (!Shell.rootAccess()) {
preferenceScreen.removePreference(magiskCategory)
generalCatagory.removePreference(hideManager)
}
findPreference<Preference>("clear")?.setOnPreferenceClickListener {
Completable.fromAction { repoDB.clear() }.subscribeK {
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT)
@@ -123,58 +171,7 @@ class SettingsFragment : BasePreferenceFragment() {
setLocalePreference(findPreference(Config.Key.LOCALE)!!)
/* We only show canary channels if user is already on canary channel
* or the user have already chosen canary channel */
if (!Utils.isCanary && Config.updateChannel < Config.Value.CANARY_CHANNEL) {
// Remove the last 2 entries
val entries = updateChannel.entries
updateChannel.entries = entries.copyOf(entries.size - 2)
}
setSummary()
// Disable dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserConfig)
}
// Disable re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
reauth.isEnabled = false
reauth.isChecked = false
reauth.setSummary(R.string.android_o_not_support)
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.isEnabled = false
fingerprint.isChecked = false
fingerprint.setSummary(R.string.disable_fingerprint)
}
if (Shell.rootAccess() && Const.USER_ID == 0) {
if (activity.packageName == BuildConfig.APPLICATION_ID) {
generalCatagory.removePreference(restoreManager)
} else {
if (!Networking.checkNetworkStatus(requireContext())) {
generalCatagory.removePreference(restoreManager)
}
generalCatagory.removePreference(hideManager)
}
} else {
generalCatagory.removePreference(restoreManager)
generalCatagory.removePreference(hideManager)
}
if (!Utils.showSuperUser()) {
preferenceScreen.removePreference(suCategory)
}
if (!Shell.rootAccess()) {
preferenceScreen.removePreference(magiskCategory)
generalCatagory.removePreference(hideManager)
}
}
override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) {
@@ -201,7 +198,7 @@ class SettingsFragment : BasePreferenceFragment() {
Shell.su("magiskhide --disable").submit()
}
Config.Key.LOCALE -> {
LocaleManager.setLocale(activity.application)
refreshLocale()
activity.recreate()
}
Config.Key.CHECK_UPDATES -> Utils.scheduleUpdateCheck(activity)
@@ -225,27 +222,12 @@ class SettingsFragment : BasePreferenceFragment() {
private fun setLocalePreference(lp: ListPreference) {
lp.isEnabled = false
availableLocales.map {
val names = mutableListOf<String>()
val values = mutableListOf<String>()
names.add(
LocaleManager.getString(defaultLocale, R.string.system_default)
)
values.add("")
it.forEach { locale ->
names.add(locale.getDisplayName(locale))
values.add(locale.toLangTag())
}
Pair(names.toTypedArray(), values.toTypedArray())
}.subscribeK { (names, values) ->
lp.isEnabled = true
lp.entries = names
lp.entryValues = values
lp.summary = currentLocale.getDisplayName(currentLocale)
}
availableLocales.subscribeK { (names, values) ->
lp.isEnabled = true
lp.entries = names
lp.entryValues = values
lp.summary = currentLocale.getDisplayName(currentLocale)
}
}
private fun setSummary(key: String) {
@@ -297,8 +279,8 @@ class SettingsFragment : BasePreferenceFragment() {
AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_update_custom)
.setView(v)
.setPositiveButton(R.string.ok) { _, _ -> onSuccess(url.text.toString()) }
.setNegativeButton(R.string.close) { _, _ -> onCancel() }
.setPositiveButton(android.R.string.ok) { _, _ -> onSuccess(url.text.toString()) }
.setNegativeButton(android.R.string.cancel) { _, _ -> onCancel() }
.setOnCancelListener { onCancel() }
.show()
}
@@ -322,11 +304,35 @@ class SettingsFragment : BasePreferenceFragment() {
AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_download_path_title)
.setView(binding.root)
.setPositiveButton(R.string.ok) { _, _ ->
.setPositiveButton(android.R.string.ok) { _, _ ->
Utils.ensureDownloadPath(data.text.value)?.let { onSuccess(data.text.value) }
?: Utils.toast(R.string.settings_download_path_error, Toast.LENGTH_SHORT)
}
.setNegativeButton(R.string.close, null)
.setNegativeButton(android.R.string.cancel, null)
.show()
}
}
private inline fun showManagerNameDialog(
crossinline onSuccess: (String) -> Unit
) {
val data = ManagerNameData()
val view = DialogCustomNameBinding
.inflate(LayoutInflater.from(requireContext()))
.also { it.data = data }
AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_app_name)
.setView(view.root)
.setPositiveButton(android.R.string.ok) { _, _ ->
if (view.dialogNameInput.error.isNullOrBlank()) {
onSuccess(data.name.value)
}
}
.setNegativeButton(android.R.string.cancel, null)
.show()
}
inner class ManagerNameData {
val name = KObservableField(resources.getString(R.string.re_app_name))
}
}

View File

@@ -42,6 +42,11 @@ class SuperuserViewModel(
init {
rxBus.register<PolicyEnableEvent>()
.filter {
val isIgnored = it.item == ignoreNext
if (isIgnored) ignoreNext = null
!isIgnored
}
.subscribeK { togglePolicy(it.item, it.enable) }
.add()
rxBus.register<PolicyUpdateEvent>()
@@ -84,8 +89,8 @@ class SuperuserViewModel(
CustomAlertDialog(this)
.setTitle(R.string.su_revoke_title)
.setMessage(getString(R.string.su_revoke_msg, item.item.appName))
.setPositiveButton(R.string.yes) { _, _ -> updateState() }
.setNegativeButton(R.string.no_thanks, null)
.setPositiveButton(android.R.string.yes) { _, _ -> updateState() }
.setNegativeButton(android.R.string.no, null)
.setCancelable(true)
.show()
}
@@ -144,4 +149,4 @@ class SuperuserViewModel(
private fun deletePolicy(policy: MagiskPolicy) =
policyDB.delete(policy.uid).andThen(Single.just(policy))
}
}

View File

@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.ui.surequest
import android.content.pm.ActivityInfo
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.view.Window
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseActivity
@@ -18,6 +17,7 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestBinding>() {
override val layoutRes: Int = R.layout.activity_request
override val themeRes: Int = R.style.MagiskTheme_SU
override val viewModel: SuRequestViewModel by viewModel()
override fun onBackPressed() {
@@ -30,19 +30,17 @@ open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestB
super.onCreate(savedInstanceState)
val intent = intent
val action = intent.action
if (TextUtils.equals(action, GeneralReceiver.REQUEST)) {
if (!viewModel.handleRequest(intent))
finish()
return
when (intent?.action) {
GeneralReceiver.REQUEST -> {
if (!viewModel.handleRequest(intent))
finish()
return
}
GeneralReceiver.LOG -> SuLogger.handleLogs(this, intent)
GeneralReceiver.NOTIFY -> SuLogger.handleNotify(this, intent)
}
if (TextUtils.equals(action, GeneralReceiver.LOG))
SuLogger.handleLogs(intent)
else if (TextUtils.equals(action, GeneralReceiver.NOTIFY))
SuLogger.handleNotify(intent)
finish()
}

View File

@@ -0,0 +1,22 @@
package com.topjohnwu.magisk.utils
class CachedValue<T>(private val factory: () -> T) : Lazy<T> {
private var _val : T? = null
override val value: T
get() {
val local = _val
return local ?: synchronized(this) {
_val ?: factory().also { _val = it }
}
}
override fun isInitialized() = _val != null
fun invalidate() {
synchronized(this) {
_val = null
}
}
}

View File

@@ -16,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.navigation.NavigationView
import com.google.android.material.textfield.TextInputLayout
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial
import com.topjohnwu.magisk.extensions.subscribeK
@@ -220,4 +221,11 @@ fun getScrollPosition(view: RecyclerView) = (view.layoutManager as? LinearLayout
@BindingAdapter("isEnabled")
fun setEnabled(view: View, isEnabled: Boolean) {
view.isEnabled = isEnabled
}
@BindingAdapter("error")
fun TextInputLayout.setErrorString(error: String) {
val newError = error.let { if (it.isEmpty()) null else it }
if (this.error == null && newError == null) return
this.error = newError
}

View File

@@ -1,61 +0,0 @@
package com.topjohnwu.magisk.utils
import dalvik.system.DexClassLoader
import java.io.File
import java.io.IOException
import java.net.URL
import java.util.*
@Suppress("FunctionName")
inline fun <reified T> T.DynamicClassLoader(apk: File) = DynamicClassLoader(apk, T::class.java.classLoader)
class DynamicClassLoader(apk: File, parent: ClassLoader?)
: DexClassLoader(apk.path, apk.parent, null, parent) {
private val base by lazy { Any::class.java.classLoader!! }
@Throws(ClassNotFoundException::class)
override fun loadClass(name: String, resolve: Boolean) : Class<*>
= findLoadedClass(name) ?: runCatching {
base.loadClass(name)
}.getOrElse {
runCatching {
findClass(name)
}.getOrElse { err ->
runCatching {
parent.loadClass(name)
}.getOrElse { throw err }
}
}
override fun getResource(name: String) = base.getResource(name)
?: findResource(name)
?: parent?.getResource(name)
@Throws(IOException::class)
override fun getResources(name: String): Enumeration<URL> {
val resources = mutableListOf(
base.getResources(name),
findResources(name), parent.getResources(name))
return object : Enumeration<URL> {
override fun hasMoreElements(): Boolean {
while (true) {
if (resources.isEmpty())
return false
if (!resources[0].hasMoreElements()) {
resources.removeAt(0)
} else {
return true
}
}
}
override fun nextElement(): URL {
if (!hasMoreElements())
throw NoSuchElementException()
return resources[0].nextElement()
}
}
}
}

View File

@@ -9,15 +9,11 @@ import java.io.Serializable
* You can define if wrapped type is Nullable or not.
* You can use kotlin get/set syntax for value
*/
class KObservableField<T> : ObservableField<T>, Serializable {
open class KObservableField<T> : ObservableField<T>, Serializable {
var value: T
set(value) {
if (field != value) {
field = value
notifyChange()
}
}
get() = get()
set(value) { set(value) }
constructor(init: T) {
value = init
@@ -27,23 +23,8 @@ class KObservableField<T> : ObservableField<T>, Serializable {
value = init
}
@Deprecated(
message = "Needed for data binding, use KObservableField.value syntax from code",
replaceWith = ReplaceWith("value")
)
@Suppress("UNCHECKED_CAST")
override fun get(): T {
return value
return super.get() as T
}
@Deprecated(
message = "Needed for data binding, use KObservableField.value = ... syntax from code",
replaceWith = ReplaceWith("value = newValue")
)
override fun set(newValue: T) {
value = newValue
}
override fun toString(): String {
return "KObservableField(value=$value)"
}
}
}

View File

@@ -0,0 +1,143 @@
package com.topjohnwu.magisk.utils
import android.content.pm.PackageManager
import android.util.Base64
import android.util.Base64OutputStream
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.di.koinModules
import com.topjohnwu.signing.CryptoUtils.readCertificate
import com.topjohnwu.signing.CryptoUtils.readPrivateKey
import com.topjohnwu.superuser.internal.InternalUtils
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
import org.koin.core.context.GlobalContext
import org.koin.core.context.startKoin
import timber.log.Timber
import java.io.ByteArrayOutputStream
import java.math.BigInteger
import java.security.KeyPairGenerator
import java.security.KeyStore
import java.security.MessageDigest
import java.security.PrivateKey
import java.security.cert.X509Certificate
import java.util.*
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
private interface CertKeyProvider {
val cert: X509Certificate
val key: PrivateKey
}
@Suppress("DEPRECATION")
class Keygen: CertKeyProvider {
companion object {
private const val ALIAS = "magisk"
private val PASSWORD get() = "magisk".toCharArray()
private const val TESTKEY_CERT = "61ed377e85d386a8dfee6b864bd85b0bfaa5af81"
private const val ALPHANUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
private const val BASE64_FLAG = Base64.NO_PADDING or Base64.NO_WRAP
}
private val start = Calendar.getInstance()
private val end = Calendar.getInstance().apply { add(Calendar.YEAR, 30) }
override val cert get() = provider.cert
override val key get() = provider.key
private val provider: CertKeyProvider
inner class KeyStoreProvider : CertKeyProvider {
private val ks by lazy { init() }
override val cert by lazy { ks.getCertificate(ALIAS) as X509Certificate }
override val key by lazy { ks.getKey(ALIAS, PASSWORD) as PrivateKey }
}
class TestProvider : CertKeyProvider {
override val cert by lazy {
readCertificate(javaClass.getResourceAsStream("/keys/testkey.x509.pem"))
}
override val key by lazy {
readPrivateKey(javaClass.getResourceAsStream("/keys/testkey.pk8"))
}
}
init {
// This object could possibly be accessed from an external app
// Get context from reflection into Android's framework
val context = InternalUtils.getContext()
val pm = context.packageManager
val info = pm.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES)
val sig = info.signatures[0]
val digest = MessageDigest.getInstance("SHA1")
val chksum = digest.digest(sig.toByteArray())
val sb = StringBuilder()
for (b in chksum) {
sb.append("%02x".format(0xFF and b.toInt()))
}
provider = if (sb.toString() == TESTKEY_CERT) {
// The app was signed by the test key, continue to use it (legacy mode)
TestProvider()
} else {
KeyStoreProvider()
}
}
private fun randomString(): String {
val rand = kotlin.random.Random.Default
val len = rand.nextInt(5, 10)
val sb = StringBuilder(len)
for (i in 0..len) {
val idx = rand.nextInt(ALPHANUM.length)
sb.append(ALPHANUM[idx])
}
return sb.toString()
}
private fun init(): KeyStore {
GlobalContext.getOrNull() ?: {
// Invoked externally, do some basic initialization
startKoin {
modules(koinModules)
}
Timber.plant(Timber.DebugTree())
}()
val raw = Config.keyStoreRaw
val ks = KeyStore.getInstance("PKCS12")
if (raw.isEmpty()) {
ks.load(null)
} else {
GZIPInputStream(Base64.decode(raw, BASE64_FLAG).inputStream()).use {
ks.load(it, PASSWORD)
}
}
// Keys already exist
if (ks.containsAlias(ALIAS))
return ks
// Generate new private key and certificate
val kp = KeyPairGenerator.getInstance("RSA").apply { initialize(4096) }.genKeyPair()
val dname = X500Name("CN=${randomString()}")
val builder = JcaX509v3CertificateBuilder(dname, BigInteger(160, Random()),
start.time, end.time, dname, kp.public)
val signer = JcaContentSignerBuilder("SHA256WithRSA").build(kp.private)
val cert = JcaX509CertificateConverter().getCertificate(builder.build(signer))
// Store them into keystore
ks.setKeyEntry(ALIAS, kp.private, PASSWORD, arrayOf(cert))
val bytes = ByteArrayOutputStream()
GZIPOutputStream(Base64OutputStream(bytes, BASE64_FLAG)).use {
ks.store(it, PASSWORD)
}
Config.keyStoreRaw = bytes.toString("UTF-8")
return ks
}
}

View File

@@ -1,68 +0,0 @@
package com.topjohnwu.magisk.utils
import android.content.Context
import android.content.ContextWrapper
import android.content.res.Configuration
import android.content.res.Resources
import androidx.annotation.StringRes
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.inject
import com.topjohnwu.magisk.extensions.langTagToLocale
import com.topjohnwu.superuser.internal.InternalUtils
import io.reactivex.Single
import java.util.*
var currentLocale = Locale.getDefault()!!
private set
val defaultLocale = Locale.getDefault()!!
val availableLocales = Single.fromCallable {
val compareId = R.string.app_changelog
val res: Resources by inject()
mutableListOf<Locale>().apply {
// Add default locale
add(Locale.ENGLISH)
// Add some special locales
add(Locale.TAIWAN)
add(Locale("pt", "BR"))
// Other locales
val otherLocales = res.assets.locales
.map { it.langTagToLocale() }
.distinctBy { LocaleManager.getString(it, compareId) }
listOf("", "").toTypedArray()
addAll(otherLocales)
}.sortedWith(Comparator { a, b ->
a.getDisplayName(a).toLowerCase(a)
.compareTo(b.getDisplayName(b).toLowerCase(b))
})
}.cache()!!
object LocaleManager {
fun setLocale(wrapper: ContextWrapper) {
val localeConfig = Config.locale
currentLocale = when {
localeConfig.isEmpty() -> defaultLocale
else -> localeConfig.langTagToLocale()
}
Locale.setDefault(currentLocale)
InternalUtils.replaceBaseContext(wrapper, getLocaleContext(wrapper, currentLocale))
}
fun getLocaleContext(context: Context, locale: Locale = currentLocale): Context {
val config = Configuration(context.resources.configuration)
config.setLocale(locale)
return context.createConfigurationContext(config)
}
fun getString(locale: Locale, @StringRes id: Int): String {
return getLocaleContext(get(), locale).getString(id)
}
}

View File

@@ -0,0 +1,89 @@
@file:Suppress("DEPRECATION")
package com.topjohnwu.magisk.utils
import android.annotation.SuppressLint
import android.content.res.Configuration
import android.content.res.Resources
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.ResourceMgr
import com.topjohnwu.magisk.extensions.langTagToLocale
import com.topjohnwu.magisk.extensions.toLangTag
import io.reactivex.Single
import java.util.*
import kotlin.Comparator
import kotlin.collections.ArrayList
var currentLocale: Locale = Locale.getDefault()
@SuppressLint("ConstantLocale")
val defaultLocale: Locale = Locale.getDefault()
val availableLocales = Single.fromCallable {
val compareId = R.string.app_changelog
val config = ResourceMgr.resource.configuration
val metrics = ResourceMgr.resource.displayMetrics
val res = Resources(ResourceMgr.resource.assets, metrics, config)
val locales = mutableListOf<Locale>().apply {
// Add default locale
add(Locale.ENGLISH)
// Add some special locales
add(Locale.TAIWAN)
add(Locale("pt", "BR"))
// Other locales
val otherLocales = ResourceMgr.resource.assets.locales
.map { it.langTagToLocale() }
.distinctBy {
config.setLocale(it)
res.updateConfiguration(config, metrics)
res.getString(compareId)
}
addAll(otherLocales)
}.sortedWith(Comparator { a, b ->
a.getDisplayName(a).toLowerCase(a)
.compareTo(b.getDisplayName(b).toLowerCase(b))
})
config.setLocale(defaultLocale)
res.updateConfiguration(config, metrics)
val defName = res.getString(R.string.system_default)
// Restore back to current locale
config.setLocale(currentLocale)
res.updateConfiguration(config, metrics)
Pair(locales, defName)
}.map { (locales, defName) ->
val names = ArrayList<String>(locales.size + 1)
val values = ArrayList<String>(locales.size + 1)
names.add(defName)
values.add("")
locales.forEach { locale ->
names.add(locale.getDisplayName(locale))
values.add(locale.toLangTag())
}
Pair(names.toTypedArray(), values.toTypedArray())
}.cache()!!
fun Resources.updateConfig(config: Configuration = configuration) {
config.setLocale(currentLocale)
updateConfiguration(config, displayMetrics)
}
fun refreshLocale() {
val localeConfig = Config.locale
currentLocale = when {
localeConfig.isEmpty() -> defaultLocale
else -> localeConfig.langTagToLocale()
}
Locale.setDefault(currentLocale)
ResourceMgr.resource.updateConfig()
}

View File

@@ -1,11 +1,14 @@
package com.topjohnwu.magisk.utils
import android.content.ComponentName
import android.content.Context
import android.os.Build.VERSION.SDK_INT
import android.widget.Toast
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.data.network.GithubRawServices
import com.topjohnwu.magisk.extensions.DynamicClassLoader
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.extensions.writeTo
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.signing.JarMap
import com.topjohnwu.signing.SignAPK
@@ -47,81 +50,86 @@ object PatchAPK {
}
private fun findAndPatch(xml: ByteArray, from: String, to: String): Boolean {
if (from.length != to.length)
if (to.length > from.length)
return false
val buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer()
val offList = mutableListOf<Int>()
var i = 0
while (i < buf.length - from.length) {
var match = true
for (j in 0 until from.length) {
loop@ while (i < buf.length - from.length) {
for (j in from.indices) {
if (buf.get(i + j) != from[j]) {
match = false
break
++i
continue@loop
}
}
if (match) {
offList.add(i)
i += from.length
}
++i
offList.add(i)
i += from.length
}
if (offList.isEmpty())
return false
val toBuf = to.toCharArray().copyOf(from.length)
for (off in offList) {
buf.position(off)
buf.put(to)
buf.put(toBuf)
}
return true
}
private fun findAndPatch(xml: ByteArray, a: Int, b: Int): Boolean {
val buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer()
val len = xml.size / 4
for (i in 0 until len) {
if (buf.get(i) == a) {
buf.put(i, b)
return true
private fun patchAndHide(context: Context, label: String): Boolean {
// If not running as stub, and we are compatible with stub, use stub
val src = if (!isRunningAsStub && SDK_INT >= 28 && Info.env.connectionMode == 3) {
val stub = File(context.cacheDir, "stub.apk")
val svc = get<GithubRawServices>()
runCatching {
svc.fetchFile(Info.remote.stub.link).blockingGet().byteStream().use {
it.writeTo(stub)
}
}.onFailure {
Timber.e(it)
return false
}
stub.path
} else {
context.packageCodePath
}
return false
}
private fun patchAndHide(context: Context): Boolean {
// Generate a new app with random package name
val repack = File(context.filesDir, "patched.apk")
// Generate a new random package name and signature
val repack = File(context.cacheDir, "patched.apk")
val pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length)
Config.keyStoreRaw = ""
if (!patch(context.packageCodePath, repack.path, pkg))
if (!patch(src, repack.path, pkg, label))
return false
// Install the application
repack.setReadable(true, false)
if (!Shell.su("pm install $repack").exec().isSuccess)
if (!Shell.su("force_pm_install $repack").exec().isSuccess)
return false
Config.suManager = pkg
Config.export()
RootUtils.rmAndLaunch(BuildConfig.APPLICATION_ID,
ComponentName(pkg, ClassMap.get<Class<*>>(SplashActivity::class.java).name))
Shell.su("pm uninstall ${BuildConfig.APPLICATION_ID}").submit()
return true
}
@JvmStatic
fun patch(apk: String, out: String, pkg: String): Boolean {
@JvmOverloads
fun patch(apk: String, out: String, pkg: String, label: String = "Manager"): Boolean {
try {
val jar = JarMap(apk)
val je = jar.getJarEntry(Const.ANDROID_MANIFEST)
val xml = jar.getRawData(je)
if (!findAndPatch(xml, BuildConfig.APPLICATION_ID, pkg) ||
!findAndPatch(xml, R.string.app_name, R.string.re_app_name))
!findAndPatch(xml, "Magisk Manager", label))
return false
// Write apk changes
jar.getOutputStream(je).write(xml)
SignAPK.sign(jar, FileOutputStream(out).buffered())
val keys = Keygen()
SignAPK.sign(keys.cert, keys.key, jar, FileOutputStream(out).buffered())
} catch (e: Exception) {
Timber.e(e)
return false
@@ -130,11 +138,36 @@ object PatchAPK {
return true
}
fun hideManager(context: Context) {
fun patch(apk: File, out: File, pkg: String, label: String): Boolean {
try {
if (apk.length() < 1 shl 18) {
// APK is smaller than 256K, must be stub
return patch(apk.path, out.path, pkg, label)
}
// Try using the new APK to patch itself
val loader = DynamicClassLoader(apk)
val cls = loader.loadClass("a.a")
for (m in cls.declaredMethods) {
val pars = m.parameterTypes
if (pars.size == 4 && pars[0] == String::class.java) {
return m.invoke(null, apk.path, out.path, pkg, label) as Boolean
}
}
throw Exception("No matching method found")
} catch (e: Exception) {
Timber.e(e)
// Fallback to use the current implementation
return patch(apk.path, out.path, pkg, label)
}
}
fun hideManager(context: Context, label: String) {
Completable.fromAction {
val progress = Notifications.progress(context, context.getString(R.string.hide_manager_title))
Notifications.mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build())
if (!patchAndHide(context))
if (!patchAndHide(context, label))
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG)
Notifications.mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID)
}.subscribeK()

View File

@@ -0,0 +1,44 @@
package com.topjohnwu.magisk.utils
import android.content.Context
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.rawResource
import com.topjohnwu.magisk.wrap
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.io.SuFile
class RootInit : Shell.Initializer() {
override fun onInit(context: Context, shell: Shell): Boolean {
return init(context.wrap(), shell)
}
fun init(context: Context, shell: Shell): Boolean {
// Invalidate env state if shell is recreated
Info.envRef.invalidate()
val job = shell.newJob()
if (shell.isRoot) {
job.add(context.rawResource(R.raw.util_functions))
.add(context.rawResource(R.raw.utils))
Const.MAGISK_DISABLE_FILE = SuFile("/cache/.disable_magisk")
} else {
job.add(context.rawResource(R.raw.nonroot_utils))
}
job.add("mount_partitions",
"get_flags",
"run_migrations",
"export BOOTMODE=true")
.exec()
Info.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean()
Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean()
Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean()
return true
}
}

View File

@@ -1,158 +0,0 @@
package com.topjohnwu.magisk.utils
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.Uri
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.rawResource
import com.topjohnwu.magisk.extensions.toShellCmd
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.io.SuFile
import java.util.*
import java.lang.reflect.Array as RArray
fun Intent.toCommand(args: MutableList<String>) {
if (action != null) {
args.add("-a")
args.add(action!!)
}
if (component != null) {
args.add("-n")
args.add(component!!.flattenToString())
}
if (data != null) {
args.add("-d")
args.add(dataString!!)
}
if (categories != null) {
for (cat in categories) {
args.add("-c")
args.add(cat)
}
}
if (type != null) {
args.add("-t")
args.add(type!!)
}
val extras = extras
if (extras != null) {
loop@ for (key in extras.keySet()) {
val v = extras.get(key) ?: continue
var value: Any = v
val arg: String
when {
v is String -> arg = "--es"
v is Boolean -> arg = "--ez"
v is Int -> arg = "--ei"
v is Long -> arg = "--el"
v is Float -> arg = "--ef"
v is Uri -> arg = "--eu"
v is ComponentName -> {
arg = "--ecn"
value = v.flattenToString()
}
v is ArrayList<*> -> {
if (v.size <= 0)
/* Impossible to know the type due to type erasure */
continue@loop
arg = if (v[0] is Int)
"--eial"
else if (v[0] is Long)
"--elal"
else if (v[0] is Float)
"--efal"
else if (v[0] is String)
"--esal"
else
continue@loop /* Unsupported */
val sb = StringBuilder()
for (o in v) {
sb.append(o.toString().replace(",", "\\,"))
sb.append(',')
}
// Remove trailing comma
sb.deleteCharAt(sb.length - 1)
value = sb
}
v.javaClass.isArray -> {
arg = if (v is IntArray)
"--eia"
else if (v is LongArray)
"--ela"
else if (v is FloatArray)
"--efa"
else if (v is Array<*> && v.isArrayOf<String>())
"--esa"
else
continue@loop /* Unsupported */
val sb = StringBuilder()
val len = RArray.getLength(v)
for (i in 0 until len) {
sb.append(RArray.get(v, i)!!.toString().replace(",", "\\,"))
sb.append(',')
}
// Remove trailing comma
sb.deleteCharAt(sb.length - 1)
value = sb
}
else -> continue@loop
} /* Unsupported */
args.add(arg)
args.add(key)
args.add(value.toString())
}
}
args.add("-f")
args.add(flags.toString())
}
fun startActivity(intent: Intent) {
if (intent.component == null)
return
val args = ArrayList<String>()
args.add("am")
args.add("start")
intent.toCommand(args)
Shell.su(args.toShellCmd()).exec()
}
class RootUtils : Shell.Initializer() {
override fun onInit(context: Context, shell: Shell): Boolean {
val job = shell.newJob()
if (shell.isRoot) {
job.add(context.rawResource(R.raw.util_functions))
.add(context.rawResource(R.raw.utils))
Const.MAGISK_DISABLE_FILE = SuFile("/cache/.disable_magisk")
Info.loadMagiskInfo()
} else {
job.add(context.rawResource(R.raw.nonroot_utils))
}
job.add("mount_partitions",
"get_flags",
"run_migrations",
"export BOOTMODE=true")
.exec()
Info.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean()
Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean()
Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean()
return true
}
companion object {
fun rmAndLaunch(rm: String, component: ComponentName) {
Shell.su("(rm_launch $rm ${component.flattenToString()})").exec()
}
}
}

View File

@@ -2,14 +2,13 @@ package com.topjohnwu.magisk.utils
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.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.database.PolicyDao
import com.topjohnwu.magisk.data.repository.LogRepository
import com.topjohnwu.magisk.extensions.inject
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.model.entity.MagiskPolicy
import com.topjohnwu.magisk.model.entity.toLog
import com.topjohnwu.magisk.model.entity.toPolicy
@@ -17,15 +16,13 @@ import java.util.*
object SuLogger {
private val context: Context by inject()
fun handleLogs(intent: Intent) {
fun handleLogs(context: Context, intent: Intent) {
val fromUid = intent.getIntExtra("from.uid", -1)
if (fromUid < 0) return
if (fromUid == Process.myUid()) return
val pm: PackageManager by inject()
val pm = context.packageManager
val notify: Boolean
val data = intent.extras
@@ -36,7 +33,7 @@ object SuLogger {
}.getOrElse { return }
} else {
// Doesn't report whether notify or not, check database ourselves
val policyDB: PolicyDao by inject()
val policyDB = get<PolicyDao>()
val policy = policyDB.fetch(fromUid).blockingGet() ?: return
notify = policy.notification
policy
@@ -46,7 +43,7 @@ object SuLogger {
return
if (notify)
handleNotify(policy)
handleNotify(context, policy)
val toUid = intent.getIntExtra("to.uid", -1)
if (toUid < 0) return
@@ -62,11 +59,11 @@ object SuLogger {
date = Date()
)
val logRepo: LogRepository by inject()
val logRepo = get<LogRepository>()
logRepo.put(log).blockingGet()?.printStackTrace()
}
private fun handleNotify(policy: MagiskPolicy) {
private fun handleNotify(context: Context, policy: MagiskPolicy) {
if (policy.notification && Config.suNotification == Config.Value.NOTIFICATION_TOAST) {
Utils.toast(
context.getString(
@@ -80,16 +77,16 @@ object SuLogger {
}
}
fun handleNotify(intent: Intent) {
fun handleNotify(context: Context, intent: Intent) {
val fromUid = intent.getIntExtra("from.uid", -1)
if (fromUid < 0) return
if (fromUid == Process.myUid()) return
runCatching {
val packageManager: PackageManager by inject()
val policy = fromUid.toPolicy(packageManager)
val pm = context.packageManager
val policy = fromUid.toPolicy(pm)
.copy(policy = intent.getIntExtra("policy", -1))
if (policy.policy >= 0)
handleNotify(policy)
handleNotify(context, policy)
}
}
}

View File

@@ -45,7 +45,7 @@ object Utils {
.setRequiresDeviceIdle(true)
.build()
val request = PeriodicWorkRequest
.Builder(ClassMap[UpdateCheckService::class.java], 12, TimeUnit.HOURS)
.Builder(ClassMap[UpdateCheckService::class.java] as Class<Worker>, 12, TimeUnit.HOURS)
.setConstraints(constraints)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(

View File

@@ -48,7 +48,7 @@ object MarkDownWindow : KoinComponent {
AlertDialog.Builder(activity)
.setTitle(title)
.setView(mv)
.setNegativeButton(R.string.close) { dialog, _ -> dialog.dismiss() }
.setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.dismiss() }
.show()
}
}

View File

@@ -1,100 +1,120 @@
package com.topjohnwu.magisk.view
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import android.os.Build.VERSION.SDK_INT
import androidx.core.app.TaskStackBuilder
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R
import androidx.core.content.getSystemService
import androidx.core.graphics.drawable.toIcon
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.Const.ID.PROGRESS_NOTIFICATION_CHANNEL
import com.topjohnwu.magisk.Const.ID.UPDATE_NOTIFICATION_CHANNEL
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.getBitmap
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
import com.topjohnwu.magisk.ui.SplashActivity
object Notifications {
val mgr by lazy { NotificationManagerCompat.from(get()) }
val mgr by lazy { get<Context>().getSystemService<NotificationManager>()!! }
fun setup(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mgr.deleteNotificationChannel("magisk_notification")
var channel = NotificationChannel(Const.ID.UPDATE_NOTIFICATION_CHANNEL,
if (SDK_INT >= 26) {
var channel = NotificationChannel(UPDATE_NOTIFICATION_CHANNEL,
context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT)
mgr.createNotificationChannel(channel)
channel = NotificationChannel(Const.ID.PROGRESS_NOTIFICATION_CHANNEL,
channel = NotificationChannel(PROGRESS_NOTIFICATION_CHANNEL,
context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW)
mgr.createNotificationChannel(channel)
}
}
private fun updateBuilder(context: Context): Notification.Builder {
return Notification.Builder(context).apply {
val bitmap = context.getBitmap(R.drawable.ic_magisk_outline)
setLargeIcon(bitmap)
if (SDK_INT >= 26) {
setSmallIcon(bitmap.toIcon())
setChannelId(UPDATE_NOTIFICATION_CHANNEL)
} else {
setSmallIcon(R.drawable.ic_magisk_outline)
setVibrate(longArrayOf(0, 100, 100, 100))
}
}
}
fun magiskUpdate(context: Context) {
val intent = Intent(context, ClassMap[SplashActivity::class.java])
intent.putExtra(Const.Key.OPEN_SECTION, "magisk")
val intent = context.intent(SplashActivity::class.java)
.putExtra(Const.Key.OPEN_SECTION, "magisk")
val stackBuilder = TaskStackBuilder.create(context)
stackBuilder.addParentStack(ClassMap.get<Class<*>>(SplashActivity::class.java))
stackBuilder.addParentStack(SplashActivity::class.java.cmp(context.packageName))
stackBuilder.addNextIntent(intent)
val pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
builder.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle(context.getString(R.string.magisk_update_title))
.setContentText(context.getString(R.string.manager_download_install))
.setVibrate(longArrayOf(0, 100, 100, 100))
.setAutoCancel(true)
.setContentIntent(pendingIntent)
val builder = updateBuilder(context)
.setContentTitle(context.getString(R.string.magisk_update_title))
.setContentText(context.getString(R.string.manager_download_install))
.setAutoCancel(true)
.setContentIntent(pendingIntent)
mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build())
}
fun managerUpdate(context: Context) {
val intent = Intent(context, ClassMap[GeneralReceiver::class.java])
intent.action = Const.Key.BROADCAST_MANAGER_UPDATE
intent.putExtra(Const.Key.INTENT_SET_APP, Info.remote.app)
val intent = context.intent(GeneralReceiver::class.java)
.setAction(Const.Key.BROADCAST_MANAGER_UPDATE)
.putExtra(Const.Key.INTENT_SET_APP, Info.remote.app)
val pendingIntent = PendingIntent.getBroadcast(context,
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
builder.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle(context.getString(R.string.manager_update_title))
.setContentText(context.getString(R.string.manager_download_install))
.setVibrate(longArrayOf(0, 100, 100, 100))
.setAutoCancel(true)
.setContentIntent(pendingIntent)
val builder = updateBuilder(context)
.setContentTitle(context.getString(R.string.manager_update_title))
.setContentText(context.getString(R.string.manager_download_install))
.setAutoCancel(true)
.setContentIntent(pendingIntent)
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build())
}
fun dtboPatched(context: Context) {
val intent = Intent(context, ClassMap[GeneralReceiver::class.java])
val intent = context.intent(GeneralReceiver::class.java)
.setAction(Const.Key.BROADCAST_REBOOT)
val pendingIntent = PendingIntent.getBroadcast(context,
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
builder.setSmallIcon(R.drawable.ic_magisk_outline)
.setContentTitle(context.getString(R.string.dtbo_patched_title))
.setContentText(context.getString(R.string.dtbo_patched_reboot))
.setVibrate(longArrayOf(0, 100, 100, 100))
.addAction(R.drawable.ic_refresh, context.getString(R.string.reboot), pendingIntent)
val builder = updateBuilder(context)
.setContentTitle(context.getString(R.string.dtbo_patched_title))
.setContentText(context.getString(R.string.dtbo_patched_reboot))
if (SDK_INT >= 23) {
val action = Notification.Action.Builder(
context.getBitmap(R.drawable.ic_refresh).toIcon(),
context.getString(R.string.reboot), pendingIntent).build()
builder.addAction(action)
} else {
builder.addAction(
R.drawable.ic_refresh,
context.getString(R.string.reboot), pendingIntent)
}
mgr.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build())
}
fun progress(context: Context, title: CharSequence): NotificationCompat.Builder {
val builder = NotificationCompat.Builder(context, Const.ID.PROGRESS_NOTIFICATION_CHANNEL)
builder.setPriority(NotificationCompat.PRIORITY_LOW)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentTitle(title)
.setProgress(0, 0, true)
.setOngoing(true)
fun progress(context: Context, title: CharSequence): Notification.Builder {
val builder = if (SDK_INT >= 26) {
Notification.Builder(context, PROGRESS_NOTIFICATION_CHANNEL)
} else {
Notification.Builder(context).setPriority(Notification.PRIORITY_LOW)
}
builder.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentTitle(title)
.setProgress(0, 0, true)
.setOngoing(true)
return builder
}
}

View File

@@ -7,7 +7,10 @@ import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.graphics.drawable.toAdaptiveIcon
import androidx.core.graphics.drawable.toIcon
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.extensions.getBitmap
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell
@@ -15,57 +18,82 @@ import com.topjohnwu.superuser.Shell
object Shortcuts {
fun setup(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
if (Build.VERSION.SDK_INT >= 25) {
val manager = context.getSystemService(ShortcutManager::class.java)
manager?.dynamicShortcuts = getShortCuts(context)
}
}
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
@RequiresApi(api = 25)
private fun getShortCuts(context: Context): List<ShortcutInfo> {
val shortCuts = mutableListOf<ShortcutInfo>()
val root = Shell.rootAccess()
val intent = context.intent(SplashActivity::class.java)
fun getIcon(id: Int): Icon {
return if (Build.VERSION.SDK_INT >= 26)
context.getBitmap(id).toAdaptiveIcon()
else
context.getBitmap(id).toIcon()
}
if (Utils.showSuperUser()) {
shortCuts.add(ShortcutInfo.Builder(context, "superuser")
shortCuts.add(
ShortcutInfo.Builder(context, "superuser")
.setShortLabel(context.getString(R.string.superuser))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java])
.setIntent(
Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "superuser")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_superuser))
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
)
.setIcon(getIcon(R.drawable.sc_superuser))
.setRank(0)
.build())
.build()
)
}
if (root && Config.magiskHide) {
shortCuts.add(ShortcutInfo.Builder(context, "magiskhide")
if (root && Info.env.magiskHide) {
shortCuts.add(
ShortcutInfo.Builder(context, "magiskhide")
.setShortLabel(context.getString(R.string.magiskhide))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java])
.setIntent(
Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "magiskhide")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_magiskhide))
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
)
.setIcon(getIcon(R.drawable.sc_magiskhide))
.setRank(1)
.build())
.build()
)
}
if (!Config.coreOnly && root && Info.magiskVersionCode >= 0) {
shortCuts.add(ShortcutInfo.Builder(context, "modules")
if (!Config.coreOnly && root && Info.env.magiskVersionCode >= 0) {
shortCuts.add(
ShortcutInfo.Builder(context, "modules")
.setShortLabel(context.getString(R.string.modules))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java])
.setIntent(
Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "modules")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_extension))
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
)
.setIcon(getIcon(R.drawable.sc_extension))
.setRank(3)
.build())
shortCuts.add(ShortcutInfo.Builder(context, "downloads")
.build()
)
shortCuts.add(
ShortcutInfo.Builder(context, "downloads")
.setShortLabel(context.getString(R.string.downloads))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java])
.setIntent(
Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "downloads")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_cloud_download))
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
)
.setIcon(getIcon(R.drawable.sc_cloud_download))
.setRank(2)
.build())
.build()
)
}
return shortCuts
}

View File

@@ -23,7 +23,7 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) {
setTitle(R.string.env_fix_title)
setMessage(R.string.env_fix_msg)
setCancelable(true)
setPositiveButton(R.string.yes) { _, _ ->
setPositiveButton(android.R.string.yes) { _, _ ->
val pd = ProgressDialog.show(activity,
activity.getString(R.string.setup_title),
activity.getString(R.string.setup_msg))
@@ -46,6 +46,6 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) {
}
}.exec()
}
setNegativeButton(R.string.no_thanks, null)
setNegativeButton(android.R.string.no, null)
}
}

View File

@@ -31,7 +31,7 @@ class FingerprintAuthDialog(activity: Activity, private val callback: () -> Unit
binding.message.compoundDrawablePadding = Utils.dpInPx(20)
binding.message.gravity = Gravity.CENTER
setMessage(R.string.auth_fingerprint)
setNegativeButton(R.string.close) { _, _ ->
setNegativeButton(android.R.string.cancel) { _, _ ->
helper?.cancel()
failureCallback?.invoke()
}

View File

@@ -62,12 +62,12 @@ internal class InstallMethodDialog(activity: BaseActivity<*, *>, options: List<S
.setTitle(R.string.warning)
.setMessage(R.string.install_inactive_slot_msg)
.setCancelable(true)
.setPositiveButton(R.string.yes) { _, _ ->
.setPositiveButton(android.R.string.yes) { _, _ ->
DownloadService(activity) {
subject = DownloadSubject.Magisk(Configuration.Flash.Secondary)
}
}
.setNegativeButton(R.string.no_thanks, null)
.setNegativeButton(android.R.string.no, null)
.show()
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@color/primary_dark"
android:fillColor="@color/dark"
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM17,13l-5,5 -5,-5h3V9h4v4h3z"/>
</vector>

View File

@@ -4,6 +4,6 @@
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="@color/primary_dark"
android:fillColor="@color/dark"
android:pathData="M20.5,11H19V7c0,-1.1 -0.9,-2 -2,-2h-4V3.5C13,2.12 11.88,1 10.5,1S8,2.12 8,3.5V5H4c-1.1,0 -1.99,0.9 -1.99,2v3.8H3.5c1.49,0 2.7,1.21 2.7,2.7s-1.21,2.7 -2.7,2.7H2V20c0,1.1 0.9,2 2,2h3.8v-1.5c0,-1.49 1.21,-2.7 2.7,-2.7 1.49,0 2.7,1.21 2.7,2.7V22H17c1.1,0 2,-0.9 2,-2v-4h1.5c1.38,0 2.5,-1.12 2.5,-2.5S21.88,11 20.5,11z"/>
</vector>

View File

@@ -5,6 +5,6 @@
android:width="24dp">
<path
android:fillAlpha="1.00"
android:fillColor="@color/primary_dark"
android:fillColor="@color/dark"
android:pathData="M200.6,24.2C231.8,24.2 263,33 289.6,49.5C304.7,58.8 318.2,70.7 329.8,84.1C351.5,109.6 365.2,141.7 368.8,175C373.6,217.4 361.5,261.5 335.5,295.5C334.2,297.1 332.8,298.7 331.9,300.7C341.7,310.1 351,320 360.9,329.3C322.7,339.3 284.5,349.6 246.3,359.9C256.4,323.5 266,287 275.7,250.5C262.4,250.5 249.1,250.5 235.8,250.5C228.5,269.8 221.2,289.1 214.1,308.4C205.9,308.6 197.8,308.5 189.6,308.5C188.4,306.7 187.1,304.9 185.9,303C192.4,285.5 199.1,268 205.6,250.5C189.5,250.6 173.4,250.3 157.4,250.6C150.4,270 142.9,289.2 135.8,308.5C129.8,308.5 123.9,308.4 117.9,308.6C130.4,317.8 144,325.6 158.9,330.3C171.9,334.6 185.6,336.6 199.4,336.7C199.4,349.4 199.3,362.1 199.4,374.8C165.8,374.9 132.2,364.5 104.4,345.6C91.7,337 80.3,326.5 70.2,314.9C48.5,289.4 34.8,257.3 31.2,224C26.3,180.4 39.2,134.9 66.8,100.7C67.2,99.9 67.7,99.2 68.1,98.4C58.3,88.9 49,79 39.1,69.7C77.3,59.7 115.6,49.4 153.7,39.1C143.6,75.7 133.8,112.5 124.1,149.3C137.9,149.3 151.7,149.2 165.5,149.3C172.9,130 180.2,110.6 187.3,91.2C195.5,90.8 203.7,91 211.8,91C213,92.8 214.3,94.6 215.5,96.3C209.1,114 202.3,131.6 195.8,149.2C211.8,149.3 227.8,149.2 243.9,149.3C251.2,129.9 258.3,110.3 265.8,90.9C271.5,90.8 277.3,91.6 282.9,90.4C280.2,89.5 278.1,87.7 275.9,86.1C254,70.7 227.4,62.2 200.6,62.3C200.6,49.6 200.7,36.9 200.6,24.2M292.5,100C286.4,116.4 280.2,132.8 274,149.3C280.9,149.2 287.8,149.3 294.7,149.2C296,150.8 297.3,152.4 298.6,153.9C297.1,162.1 295.7,170.3 294.3,178.5C283.9,178.5 273.4,178.5 262.9,178.5C257.5,192.7 252.1,206.9 246.9,221.2C258.7,221.3 270.5,221.1 282.3,221.3C283.5,222.9 284.8,224.4 286.1,225.9C284.9,233.7 283.4,241.4 282.1,249.1C281.6,251 283.6,252.1 284.6,253.3C291.5,259.8 297.7,266.9 304.8,273.1C312.9,262.1 319.6,250.1 324.2,237.3C334.3,208.7 334.2,176.7 323.7,148.3C317,130.1 306.4,113.4 292.5,100M95.2,125.9C86.2,138 79,151.4 74.5,165.8C65.3,194.4 66.4,226.3 77.6,254.2C84.6,271.5 95.1,287.4 108.7,300.1C114.9,283.6 121.3,267.1 127.2,250.5C121.5,250.5 115.8,250.5 110,250.5C108.6,250.4 106.7,251 105.8,249.5C104.5,247.9 102.3,246.3 102.9,244.1C104.2,236.5 105.5,228.9 106.8,221.2C117.4,221.2 128.1,221.4 138.7,221.1C143.9,206.9 149.3,192.7 154.6,178.5C142.9,178.4 131.1,178.6 119.3,178.4C117.6,177.3 116.4,175.3 115,173.8C116.3,165.8 117.9,157.9 119,150C118.3,148.2 116.6,147.1 115.3,145.7C108.6,139.2 102.3,132.1 95.2,125.9M168.8,221.2C184.8,221.2 200.8,221.3 216.8,221.2C222.2,207 227.5,192.8 232.8,178.5C216.8,178.5 200.7,178.5 184.6,178.5C179.4,192.8 174,207 168.8,221.2Z"/>
</vector>

View File

@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/primary_dark"
android:fillColor="@color/dark"
android:pathData="M5.41,21L6.12,17H2.12L2.47,15H6.47L7.53,9H3.53L3.88,7H7.88L8.59,3H10.59L9.88,7H15.88L16.59,3H18.59L17.88,7H21.88L21.53,9H17.53L16.47,15H20.47L20.12,17H16.12L15.41,21H13.41L14.12,17H8.12L7.41,21H5.41M9.53,9L8.47,15H14.47L15.53,9H9.53Z" />
</vector>

View File

@@ -32,7 +32,7 @@
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
<androidx.fragment.app.FragmentContainerView
android:id="@+id/main_nav_host"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.topjohnwu.magisk.extensions.XStringKt" />
<variable
name="data"
type="com.topjohnwu.magisk.ui.settings.SettingsFragment.ManagerNameData" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingStart="@dimen/margin_generic"
android:paddingTop="@dimen/margin_generic"
android:paddingEnd="@dimen/margin_generic">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/dialog_name_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/settings_app_name_hint"
app:counterEnabled="true"
app:counterMaxLength="14"
app:counterOverflowTextColor="@color/colorError"
app:error="@{data.name.length() > 14 || data.name.empty || XStringKt.isEmptyInternal(data.name) ? @string/settings_app_name_error : @string/empty}"
app:errorEnabled="true"
app:helperText="@string/settings_app_name_helper">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={data.name}"
tools:text="@string/re_app_name" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</layout>

View File

@@ -15,8 +15,6 @@
<import type="com.topjohnwu.magisk.R" />
<import type="com.topjohnwu.magisk.extensions.XStringKt" />
<variable
name="viewModel"
type="com.topjohnwu.magisk.ui.home.HomeViewModel" />
@@ -239,7 +237,7 @@
android:layout_marginRight="@dimen/margin_generic"
android:gravity="center"
android:maxLines="1"
android:text="@{XStringKt.res(viewModel.safetyNetTitle)}"
android:text="@{viewModel.safetyNetTitle}"
android:textStyle="bold"
app:autoSizeMaxTextSize="14sp"
app:autoSizeTextType="uniform"

View File

@@ -1,4 +1,5 @@
# v7.3.5
- Sort installed modules by name
- Better pre-5.0 support
- Fix potential issues when patching tar files
# v7.4.0
- Hide Magisk Manager with stub APKs on Android 9.0+. Not all devices will be supported, please refer to Magisk v20.1 release notes.
- Allow customizing app name when hiding Magisk Manager
- Generate random keys to sign the hidden Magisk Manager to prevent signature detections
- Fix fingerprint UI infinite loop

View File

@@ -110,8 +110,12 @@ EOF
cd /
}
rm_launch() {
pm uninstall $1
am start -n $2
exit
force_pm_install() {
local APK=$1
local VERIFY=`settings get global package_verifier_enable`
[ "$VERIFY" -eq 1 ] && settings put global package_verifier_enable 0
pm install -r $APK
local res=$?
[ "$VERIFY" -eq 1 ] && settings put global package_verifier_enable 1
return $res
}

View File

@@ -1,174 +1,224 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<resources>
<string name="advanced_settings_title">إعدادات متقدمة</string>
<string name="app_changelog">تغييرات التطبيق</string>
<string name="author">انشئ بواسطة %1$s</string>
<string name="auto_response">استجابة تلقائية</string>
<string name="checking_for_updates">البحث عن تحديثات…</string>
<string name="checking_safetyNet_status">التحقق من حالة SafetyNet…</string>
<string name="close">إغلاق</string>
<string name="command">الأمر: %1$s</string>
<string name="deny">رفض</string>
<string name="disable_file_created">سيتم تعطيل الإضافة في إعادة التشغيل التالي</string>
<string name="disable_file_removed">سيتم تمكين الإضافة في إعادة التشغيل التالي</string>
<string name="download">التنزيل</string>
<string name="downloads">التنزيلات</string>
<string name="forever">للابد</string>
<string name="grant">سماح</string>
<string name="install">التثبيت</string>
<string name="installed">مثبت</string>
<string name="keep_dm_verity">إبقاء AVB 2.0/dm-verity</string>
<string name="keep_force_encryption">الحفاظ علي قوه التشفير</string>
<string name="log">السجل</string>
<string name="logs_cleared">تم حذف السجل بنجاح</string>
<string name="magisk_update_title">تحديث Magisk جديد متوفر!</string>
<string name="magisk_version_error">Magisk غير مثبت</string>
<string name="menuClearLog">حذف السجل الآن</string>
<string name="menuReload">إعادة تحميل</string>
<string name="modules">الإضافات</string>
<string name="multiuser_mode">وضع تعدد المستخدمين</string>
<string name="no_apps_found">لا توجد تطبيقات</string>
<string name="no_info_provided">(لم يتم توفير أي معلومات)</string>
<string name="no_modules_found">لم يعثر على الإضافات</string>
<string name="none">بدون</string>
<string name="not_installed">غير مثبت</string>
<string name="once">مرة</string>
<string name="owner_manage_summary">يمكن للمالك فقط إدارة صلاحيات الروت وتلقي مطالبات الطلب</string>
<string name="owner_only_summary">المالك فقط لديه صلاحيات الروت</string>
<string name="prompt">طلب</string>
<string name="reboot">إعادة التشغيل</string>
<string name="release_notes">ملاحظات الإصدار</string>
<string name="remove_file_created">سيتم حذف الإضافة في إعادة التشغيل التالي</string>
<string name="remove_file_deleted">لن يتم حذف الإضافة في إعادة التشغيل التالي</string>
<string name="repo_cache_cleared">تم مسح الذاكرة المؤقته للمستودع</string>
<string name="repo_install_msg">هل تريد تثبيت %1$s ?</string>
<string name="repo_install_title">تثبيت %1$s</string>
<string name="request_timeout">مهلة الطلب</string>
<string name="request_timeout_summary">%1$d ثانية</string>
<string name="safetyNet_check_success">نجح فحص SafetyNet</string>
<string name="safetyNet_check_text">انقر لبدء فحص SafetyNet</string>
<string name="safetyNet_res_invalid">الاستجابة غير صالحه</string>
<string name="settings">الإعدادات</string>
<string name="settings_clear_cache_summary">حذف المعلومات المخزنة مؤقتا للمستودع على الانترنت، يجبر التطبيق لتحديث عبر الانترنت</string>
<string name="settings_clear_cache_title">حذف الذاكرة المؤقتة للمستودع</string>
<string name="settings_core_only_summary">تمكين الميزات الأساسية فقط، لن يتم تحميل جميع الإضافات. MagiskSU، MagiskHide، systemless hosts، و لا يزال ممكنا</string>
<string name="settings_core_only_title">Magisk الوضع الأساسي فقط</string>
<string name="settings_dark_theme_summary">تفعيل السمة الغامقة</string>
<string name="settings_dark_theme_title">السمة الغامقة</string>
<string name="settings_general_category">عام</string>
<string name="settings_hosts_summary">Systemless يدعم تطبيقات حجب الإعلانات</string>
<string name="settings_hosts_title">تمكين المضيفين(الهوست) لـ systemless</string>
<string name="settings_magiskhide_summary">إخفاء Magisk من مختلف الاكتشافات</string>
<string name="settings_owner_manage">إدارة مالك الجهاز</string>
<string name="settings_owner_only">مالك الجهاز فقط</string>
<string name="settings_reboot_toast">إعادة التشغيل لتطبيق الإعدادات</string>
<string name="settings_su_adb">ADB فقط</string>
<string name="settings_su_app">التطبيقات فقط</string>
<string name="settings_su_app_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="settings_user_independent">مستخدم مستقل</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="su_request_title">Superuser طلبات</string>
<string name="su_revoke_msg">تأكيد لسحب صلاحيات %1$s ?</string>
<string name="su_revoke_title">سحب؟</string>
<string name="su_snack_deny">Superuser الصلاحيات لـ %1$s تم رفضها</string>
<string name="su_snack_grant">Superuser الصلاحيات لـ %1$s تم منحها</string>
<string name="su_snack_log_off">السجلات لـ %1$s تم تعطيلها</string>
<string name="su_snack_log_on">السجلات لـ %1$s تم تفعيلها</string>
<string name="su_snack_notif_off">الإشعارات لـ %1$s تم تعطيلها</string>
<string name="su_snack_notif_on">الإشعارات لـ %1$s تم تفعيلها</string>
<string name="su_warning">"منح حق الوصول الكامل إلى جهازك.
رفض إذا كنت غير متأكد!"</string>
<string name="superuser">Superuser</string>
<string name="superuser_access">Superuser صلاحيات</string>
<string name="superuser_notification">Superuser إشعارات</string>
<string name="target_uid">الهدف UID: %1$d</string>
<string name="tenmin">10 دقائق</string>
<string name="thirtymin">30 دقائق</string>
<string name="toast">ملاحظة منبثقة</string>
<string name="twentymin">20 دقائق</string>
<string name="uninstall">إلغاء التثبيت</string>
<string name="uninstall_magisk_title">إلغاء تثبيت Magisk</string>
<string name="update_available">يتوفر تحديث</string>
<string name="update_file_created">سيتم تحديث الإضافة في إعادة التشغيل التالي</string>
<string name="user_indepenent_summary">كل مستخدم لديه قواعد روت منفصلة خاصة به</string>
<string name="android_o_not_support">لا يدعم إصدار الأندرويد +8.0</string>
<string name="auth_fail">فشل المصادقة</string>
<string name="auth_fingerprint">مصادقة البصمة</string>
<string name="complete_uninstall">إلغاء التثبيت بالكامل</string>
<string name="direct_install">تثبيت مباشر (موصى به)</string>
<string name="disable_fingerprint">لم يتم تعيين بصمات الأصابع أو لا يوجد جهاز مدعوم</string>
<string name="download_zip_only">تحميل ملف zip فقط</string>
<string name="dtbo_patched_reboot">قام مدير Magisk بتصحيح dtbo.img ، يرجى إعادة التشغيل</string>
<string name="dtbo_patched_title">تم تصحيح DTBO!</string>
<string name="env_fix_msg">يحتاج جهازك إلى إعداد إضافي لـ Magisk للعمل بشكل صحيح. سيتم تنزيل ملف zip لتثبيت Magisk ، هل تريد المتابعة الآن؟</string>
<string name="env_fix_title">يتطلب إعداد إضافي</string>
<string name="flashing">التثبيت</string>
<string name="global_summary">تستخدم كافة جلسات الجذر مساحة الأسم ذات التركيب العالمي</string>
<string name="hide_manager_fail_toast">فشل إخفاء مدير Magisk …</string>
<string name="hide_manager_title">إخفاء مدير Magisk…</string>
<string name="install_inactive_slot">التثبيت على فتحة غير نشطة (بعد OTA)</string>
<string name="install_inactive_slot_msg">"سيتم إجبار جهازك للتمهيد على الفتحة غير النشطة الحالية بعد إعادة التشغيل!
فقط استخدام هذا الخيار بعد الانتهاء من OTA.
استمرار؟"</string>
<string name="invalid_update_channel">قناة تحديث غير صالحة</string>
<string name="isolate_summary">سيكون لكل جلسة جذر مساحة الاسم الخاصة بها معزولة</string>
<string name="language">اللغة</string>
<string name="update_channel">تحديثات Magisk</string>
<string name="manager_download_install">اضغط للتنزيل والتثبيت</string>
<string name="manager_update_title">تحديث مدير Magisk الجديد متوفر!</string>
<string name="menuSaveLog">حفظ السجل</string>
<string name="mount_namespace_mode">وضع تركيب مساحة الأسم</string>
<string name="open_link_failed_toast">لم يتم العثور على تطبيق لفتح الرابط …</string>
<string name="proprietary_notice">مدير Magisk هو FOSS ، والذي لا يحتوي على شفرة API الخاصة بشركة SafetyNet الخاصة بشركة Google.
هل تسمح لـ Magisk Manager بتنزيل ملحق (يحتوي على GoogleApiClient) لعمليات التحقق من SafetyNet؟ "</string>
<string name="proprietary_title">تحميل رمز الملكية</string>
<string name="reboot_bootloader">إعادة تمهيد إلى وضع Bootloader</string>
<string name="reboot_download">إعادة تمهيد إلى وضع التحميل</string>
<string name="reboot_recovery">إعادة تمهيد إلى وضع الإسترداد</string>
<string name="requester_summary">"سترث جلسات الجذر مساحة الأسماء المطلوبة الخاصة بها"</string>
<string name="restore_done">تمت الأستعادة!</string>
<string name="restore_fail">النسخ الاحتياطي الأصلي غير موجود!</string>
<string name="restore_img">استعادة الصور</string>
<string name="restore_img_msg">الأستعادة …</string>
<string name="safetyNet_api_error">خطأ SafetyNet API</string>
<string name="select_method">حدد الطريقة</string>
<string name="settings_check_update_summary">التحقق من التحديثات في الخلفية بشكل دوري</string>
<string name="settings_check_update_title">تفقد التحديث</string>
<string name="settings_hide_manager_summary">أعد حزم مدير Magisk مع اسم حزمة عشوائية</string>
<string name="settings_hide_manager_title">إخفاء مدير Magisk</string>
<string name="settings_ns_global">مساحة الاسم العالمية</string>
<string name="settings_ns_isolate">مساحة الاسم المعزولة</string>
<string name="settings_ns_requester">وراثة مساحة الاسم</string>
<string name="settings_restore_manager_summary">استعادة مدير Magisk مع الحزمة الأصلية</string>
<string name="settings_restore_manager_title">استعادة مدير Magisk</string>
<string name="settings_su_fingerprint_summary">أستخدام ماسح بصمات الأصابع للسماح بطلبات المستخدم المتميز</string>
<string name="settings_su_fingerprint_title">تمكين مصادقة البصمة</string>
<string name="settings_su_reauth_summary">أعد المصادقة على صلاحيات المستخدم المتميز بعد إجراء ترقيات للتطبيق</string>
<string name="settings_su_reauth_title">إعادة المصادقة بعد الترقية</string>
<string name="settings_update">تحديث الاعدادات</string>
<string name="settings_update_beta">بيتا</string>
<string name="settings_update_channel_title">قناة التحديث</string>
<string name="settings_update_custom">مخصص</string>
<string name="settings_update_custom_msg">أدخل عنوان URL مخصص</string>
<string name="settings_update_stable">مستقر</string>
<string name="setup_fail">فشل الإعداد</string>
<string name="setup_msg">تشغيل إعداد البيئة…</string>
<string name="setup_title">إعداد إضافي</string>
<string name="sort_by_name">الترتيب حسب الاسم</string>
<string name="sort_by_update">فرز حسب آخر تحديث</string>
<string name="sorting_order">ترتيب الفرز</string>
<string name="system_default">(أفتراضي النظام)</string>
<string name="uninstall_magisk_msg">سيتم تعطيل/إزالة جميع الوحدات. ستتم إزالة الجذر ، وربما تشفير بياناتك إذا كانت بياناتك غير مشفرة حالياً</string>
<string name="update">تحديث</string>
<string name="updated_on">تم التحديث في: %1$s</string>
<string name="warning">تحذير</string>
<!--Welcome Activity-->
<string name="modules">الإضافات</string>
<string name="downloads">التنزيلات</string>
<string name="superuser">المستخدم المتميز</string>
<string name="log">السجل</string>
<string name="settings">الإعدادات</string>
<string name="install">التثبيت</string>
<string name="unsupport_magisk_title">إصدار Magisk غير مدعوم</string>
<string name="unsupport_magisk_message">لا يدعم هذا الإصدار من Magisk Manager إصدارا لـ Magisk vأقل من 18\n\n بإمكانك تحديث Magisk يدويا أو تثبيت إصدار أدنى.</string>
<!--Status Fragment-->
<string name="magisk_version_error">Magisk غير مثبت</string>
<string name="checking_for_updates">البحث عن تحديثات…</string>
<string name="invalid_update_channel">قناة تحديث غير صالحة</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_api_error">خطأ SafetyNet API</string>
<string name="safetyNet_res_invalid">رد غير صالح</string>
<string name="magisk_up_to_date">Magisk محدث</string>
<string name="manager_up_to_date">Magisk Manager محدث</string>
<string name="advanced_settings_title">إعدادات متقدمة</string>
<string name="keep_force_encryption">إبقاء التشفير بقوة</string>
<string name="keep_dm_verity">إبقاء AVB 2.0/dm-verity</string>
<string name="recovery_mode">نمط الاستعادة</string>
<string name="current_installed">التحديث المثبت : %1$s</string>
<string name="latest_version">آخر تحديث : %1$s</string>
<string name="uninstall">إلغاء التثبيت</string>
<string name="uninstall_magisk_title">إلغاء تثبيت Magisk</string>
<string name="uninstall_magisk_msg">ستُعطل/ستُحذف جميع الإضافات. سيُحذف الروت ، وربما ستشفر بياناتك إذا لم تكن غير مشفرة حالياً.</string>
<string name="update">تحديث</string>
<string name="core_only_enabled">(النمط الأساسي فقط ممكن)</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="reboot_recovery">إعادة التشغيل إلى نمط الاستعادة</string>
<string name="reboot_bootloader">إعادة التشغيل إلى نمط Bootloader</string>
<string name="reboot_download">إعادة التشغيل إلى نمط التحميل</string>
<string name="reboot_edl">إعادة التشغيل إلى نمط EDL</string>
<!--Repo Fragment-->
<string name="update_available">يتوفر على تحديث</string>
<string name="installed">مثبت</string>
<string name="not_installed">غير مثبت</string>
<string name="updated_on">حُدث في: %1$s</string>
<string name="sorting_order">ترتيب الفرز</string>
<string name="sort_by_name">افرز حسب الاسم</string>
<string name="sort_by_update">افرز حسب آخر تحديث</string>
<!--Log Fragment-->
<string name="menuSaveLog">حفظ السجل</string>
<string name="menuReload">إعادة التحميل</string>
<string name="menuClearLog">حذف السجل الآن</string>
<string name="logs_cleared">حُذف السجل بنجاح</string>
<!--About Activity-->
<string name="app_changelog">تغييرات التطبيق</string>
<!-- System Components, Notifications -->
<string name="update_channel">تحديثات Magisk</string>
<string name="progress_channel">إشعارات التقدم</string>
<string name="download_complete">التنزيل انتهى</string>
<string name="download_file_error">خطأ تنزيل الملف</string>
<string name="download_open_parent">أظهر والد المجلد</string>
<string name="download_open_self">أظهر الملف</string>
<string name="magisk_update_title">تحديث Magisk جديد متوفر!</string>
<string name="manager_update_title">تحديث Magisk Manager جديد متوفر!</string>
<!-- Installation -->
<string name="manager_download_install">اضغط للتنزيل و التثبيت</string>
<string name="download_zip_only">تحميل ملف Zip فقط</string>
<string name="direct_install">تثبيت مباشر (موصى بها)</string>
<string name="install_inactive_slot">التثبيت على فتحة غير نشطة (بعد OTA)</string>
<string name="install_inactive_slot_msg">"سيُجبر جهازك للتشغيل على الفتحة غير النشطة الحالية بعد إعادة التشغيل! استخدم فقط هذا الخيار بعد الانتهاء من OTA. استمرار؟"</string>
<string name="select_method">اختر الطريقة</string>
<string name="setup_title">إعداد إضافي</string>
<string name="select_patch_file">اختر و رقع ملفا</string>
<string name="patch_file_msg">اختر ملفا خاما (*.img) أو ملف ODIN tarfile (*.tar)</string>
<string name="reboot_delay_toast">إعادة التشغيل خلال خمس ثواني…</string>
<!--Toasts, Dialogs-->
<string name="repo_install_title">تثبيت %1$s</string>
<string name="repo_install_msg">هل تريد تثبيت %1$s ?</string>
<string name="download">التنزيل</string>
<string name="reboot">إعادة التشغيل</string>
<string name="settings_reboot_toast">إعادة التشغيل لتطبيق الإعدادات</string>
<string name="release_notes">ملاحظات الإصدار</string>
<string name="repo_cache_cleared">مُسحت الذاكرة المؤقتة للإضافة</string>
<string name="dtbo_patched_title">رُقع DTBO!</string>
<string name="dtbo_patched_reboot">رقع Magisk Manager الملف dtbo.img. يرجى إعادة التشغيل</string>
<string name="flashing">…تثبيت</string>
<string name="done">تم!</string>
<string name="failure">فشل</string>
<string name="hide_manager_title">إخفاء Magisk Manager…</string>
<string name="hide_manager_fail_toast">فشل إخفاء Magisk Manager…</string>
<string name="open_link_failed_toast">لم يُعثر على تطبيق لفتح الرابط …</string>
<string name="warning">تحذير</string>
<string name="complete_uninstall">إلغاء التثبيت بالكامل</string>
<string name="restore_img">استعادة الصور</string>
<string name="restore_img_msg">استعادة…</string>
<string name="restore_done">استُعيدت!</string>
<string name="restore_fail">النسخة الاحتياطية الأصلية غير موجودة!</string>
<string name="proprietary_title">تحميل شفرة المسجلة الملكية</string>
<string name="proprietary_notice">لا Magisk Manager برنامج FOSS ،و لا يحتوي على شفرة SafetyNet API الخاصة بشركة Google.\n\nهل تسمح لـ Magisk Manager بتحميل ملحق (يحتوي على GoogleApiClient) للفحص SafetyNet؟</string>
<string name="setup_fail">فشل الإعداد</string>
<string name="env_fix_title">يتطلب إعدادا إضافيا</string>
<string name="env_fix_msg">يحتاج جهازك إلى إعداد إضافي ليتسنى لـ Magisk بشكل صحيح. سينزل ملف Zip لتثبيت Magisk ، هل تريد المتابعة الآن؟</string>
<string name="setup_msg">تشغيل إعداد البيئة…</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_download_path_title">مسار التحميل</string>
<string name="settings_download_path_message">ستحمل الملفات إلى %1$s</string>
<string name="settings_clear_cache_title">حذف الذاكرة المؤقتة للإضافات</string>
<string name="settings_clear_cache_summary">حذف المعلومات المخزنة مؤقتا للإضافات المباشرة، هذا سيجبر التطبيق على التحديث عبر الانترنت</string>
<string name="settings_hide_manager_title">إخفاء Magisk Manager</string>
<string name="settings_hide_manager_summary">أعد حزم Magisk Manager مع اسم حزمة عشوائي</string>
<string name="settings_restore_manager_title">استعادة Magisk Manager</string>
<string name="settings_restore_manager_summary">استعادة Magisk Manager مع اسم الحزمة الأصلي</string>
<string name="language">اللغة</string>
<string name="system_default">(النظام المبدئي)</string>
<string name="settings_update">تحديث الإعدادات</string>
<string name="settings_check_update_title">تفقد التحديثات</string>
<string name="settings_check_update_summary">التحقق من التحديثات في الخلفية بشكل دوري</string>
<string name="settings_update_channel_title">قناة التحديث</string>
<string name="settings_update_stable">مستقر</string>
<string name="settings_update_beta">بيتا</string>
<string name="settings_update_custom">مخصص</string>
<string name="settings_update_custom_msg">أدخل عنوانا URL مخصصا</string>
<string name="settings_core_only_title"> النمط Magisk الأساسي فقط</string>
<string name="settings_core_only_summary">تمكين الميزات الأساسية فقط، سيُشغل الإضافات MagiskSU و MagiskHide فقط و لا غيرها.</string>
<string name="settings_magiskhide_summary">إخفاء Magisk من شتى طرق الاكتشاف</string>
<string name="settings_hosts_title">Systemless hosts</string>
<string name="settings_hosts_summary">Systemless hosts يدعم تطبيقات حجب الإعلانات</string>
<string name="settings_hosts_toast">مُكنت إضافة 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_15">15 ثانية</string>
<string name="settings_su_request_20">20 ثانية</string>
<string name="settings_su_request_30">30 ثانية</string>
<string name="settings_su_request_45">45 ثانية</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$d ثانية</string>
<string name="settings_su_reauth_title">إعادة المصادقة بعد الترقية</string>
<string name="settings_su_reauth_summary">أعد المصادقة على صلاحيات المستخدم المتميز بعد إجراء ترقيات للتطبيق</string>
<string name="settings_su_fingerprint_summary">استخدام قارئ بصمات الأصابع للسماح بطلبات المستخدم المتميز</string>
<string name="settings_su_fingerprint_title">تمكين مصادقة البصمة</string>
<string name="auth_fingerprint">مصادقة البصمة</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="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="disable_fingerprint">لم تُعين بصمات الأصابع أو لا يوجد قارئ بصمات</string>
<string name="settings_download_path_error">خطأ عند إنشاء مجلد. عليه أن يكون سهلا الوصول إليه من خلال مجلد التخزين للروت و ألا يكون ملفا.</string>
<!--Superuser-->
<string name="su_request_title">طلبات المستخدم المتميز</string>
<string name="deny">رفض</string>
<string name="prompt">طلب</string>
<string name="grant">سماح</string>
<string name="su_warning">"منح حق الوصول الكامل إلى جهازك. ارفض إذا كنت غير متأكد!"</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_revoke_title">سحب؟</string>
<string name="su_revoke_msg">تأكيد لسحب صلاحيات %1$s ?</string>
<string name="toast">ملاحظة منبثقة</string>
<string name="none">بدون</string>
<string name="auth_fail">فشل المصادقة</string>
<!--Superuser logs-->
<string name="pid">PID: %1$d</string>
<string name="target_uid">Target UID: %1$d</string>
<string name="command">Command: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">اظهار برامج النظام</string>
</resources>

View File

@@ -1,122 +1,70 @@
<resources>
<!--Welcome Activity-->
<string name="modules">Əlavələr</string>
<string name="downloads">Endirmələr</string>
<string name="superuser">Superuser</string>
<string name="log">Log</string>
<string name="settings">Tənzimləmələr</string>
<string name="install">Quraşdır</string>
<string name="unsupport_magisk_title">Dəstəklənməyən Magisk Versiyası</string>
<string name="unsupport_magisk_message">Magisk Manager\'in bu versiyası Magisk\'in v18.0 versiyasndan aşağısını dəstəkləmir.\n\nMagisk\'i əllə yüksəldə, yaxud tətbiqi əvvəlki versiyalarına qaytara bilərsiniz.</string>
<!--Status Fragment-->
<string name="magisk_version_error">Magisk yüklənməyib.</string>
<string name="checking_for_updates">Yeniləmələr yoxlanılır…</string>
<string name="invalid_update_channel">Etibarsız Yeniləmə Kanalı</string>
<string name="safetyNet_check_text">SafetyNet vəziyətinə bax</string>
<string name="checking_safetyNet_status">SafetyNet vəziyəti yoxlanılır…</string>
<string name="safetyNet_check_success">SafetyNet Uğurla Yoxlanıldı</string>
<string name="safetyNet_api_error">SafetyNet API Xətası</string>
<string name="safetyNet_res_invalid">Cavab etibarsızdır.</string>
<string name="magisk_up_to_date">Magisk ən yenidir</string>
<string name="manager_up_to_date">Magisk Manager ən yenidir</string>
<string name="advanced_settings_title">Qabaqcıl Parametrlər</string>
<string name="keep_force_encryption">Şifrələməyə məcbur etməni qoru</string>
<string name="keep_dm_verity">AVB 2.0/dm-verity\'i qoru</string>
<string name="current_installed">Yüklənən: %1$s</string>
<string name="latest_version">Ən son: %1$s</string>
<string name="uninstall">Sil</string>
<string name="uninstall_magisk_title">Magisk\'i Sil</string>
<string name="uninstall_magisk_msg">Bütün əlavələr ləğv olunacaq/silinəcək. Root silinəcək, və əgər hal-hazırda deyilsə, bütün məlumatlarınız potensiyal olaraq şifrələnəcək.</string>
<string name="update">Yenilə</string>
<string name="core_only_enabled">(Yalnız nüvə modu qoşulub)</string>
<!--Module Fragment-->
<string name="no_info_provided">(Məlumat təmin edilməyib)</string>
<string name="no_modules_found">Əlavələr yoxdur.</string>
<string name="update_file_created">Əlavə sonrakı yenidən başlatmada yenilənəcək.</string>
<string name="remove_file_created">Əlavə sonrakı yenidən başlatmada silinəcək.</string>
<string name="remove_file_deleted">Əlavə sonrakı yenidən başlatmada silinməyəcək.</string>
<string name="disable_file_created">Əlavə sonrakı yenidən başlatmada qapadılacaq.</string>
<string name="disable_file_removed">Əlavə sonrakı yenidən başlatmada açılacaq.</string>
<string name="author">%1$s tərəfindən yaradılıb</string>
<string name="reboot_recovery">Bərpa rejimində yenidən başlat</string>
<string name="reboot_bootloader">Bootloader\'ə yenidən başlat</string>
<string name="reboot_download">Yükləmə rejimində yenidən başlat</string>
<string name="reboot_edl">EDL\'ə yenidən başlat</string>
<!--Repo Fragment-->
<string name="update_available">Yeniləmə Var</string>
<string name="installed">Yüklənib</string>
<string name="not_installed">Yüklənməyib</string>
<string name="updated_on">Yeniləmə vaxtı: %1$s</string>
<string name="sorting_order">Nizamlama Qaydası</string>
<string name="sort_by_name">Ada görə nizamla</string>
<string name="sort_by_update">Son yeniləməyə görə nizamla</string>
<!--Log Fragment-->
<string name="menuSaveLog">Log\'u saxla</string>
<string name="menuReload">Təzələ</string>
<string name="menuClearLog">Log\'u indi təmizlə</string>
<string name="logs_cleared">Log uğurla təmizləndi.</string>
<!--About Activity-->
<string name="app_changelog">Yeniliklər</string>
<!-- System Components, Notifications -->
<string name="update_channel">Magisk Yeniləmələri</string>
<string name="progress_channel">Nəticə Bildirişləri</string>
<string name="download_complete">Yükləmə bitdi</string>
@@ -127,262 +75,135 @@
<string name="manager_update_title">Magisk Manager Yeniləməsi Var!</string>
<!--Toasts, Dialogs-->
<string name="close">Qapat</string>
<string name="repo_install_title">%1$s faylını yüklə</string>
<string name="repo_install_msg">%1$s faylını indi yükləmək istəyirsiniz?</string>
<string name="download">Yüklə</string>
<string name="reboot">Yenidən Başlat</string>
<string name="settings_reboot_toast">Tənzimləmələri saxlamaq üçün yenidən başladın.</string>
<string name="release_notes">Yeniliklər</string>
<string name="repo_cache_cleared">Repo keşi silindi</string>
<string name="manager_download_install">Yükləyib quraşdırmaq üçün toxun.</string>
<string name="dtbo_patched_title">DTBO yamaqlanıb!</string>
<string name="dtbo_patched_reboot">Magisk Manager dtbo.img\'ni yamaqladı. Xahiş olunur yenidən başladın.</string>
<string name="flashing">Qurulur</string>
<string name="hide_manager_title">Magisk Manager gizlədilir…</string>
<string name="hide_manager_fail_toast">Magisk Manager\'i gizlətmək alınmadı.</string>
<string name="open_link_failed_toast">Keçid açmağa heçbir tətbiq tapılmadı.</string>
<string name="download_zip_only">Yalnız Zip yüklə</string>
<string name="direct_install">Birdəfəlik Yüklə (Tövsiyə olunur)</string>
<string name="select_patch_file">Fayl Seç və Yamaqla</string>
<string name="install_inactive_slot">Fəal olmayan slota quraşdır (OTA\'dan sonra)</string>
<string name="warning">Xəbərdarlıq</string>
<string name="install_inactive_slot_msg">Cihazınız yenidən başladıldıqdan sonra fəal olmayan slota başlamağa MƏCBUR ediləcək!\nBu seçimi yalnız OTA bitdikdən sonra istifadə edin.\nDavam edirsiniz?</string>
<string name="select_method">Üsul Seçin</string>
<string name="complete_uninstall">Silməni Bitir</string>
<string name="restore_img">Surətləri Qaytar</string>
<string name="restore_img_msg">Geri qaytarılır…</string>
<string name="restore_done">Geri qaytarma bitdi!</string>
<string name="restore_fail">Stock nüsxə mövcud deyil!</string>
<string name="proprietary_title">Özəl kodu yükləyin</string>
<string name="proprietary_notice">Magisk Manager açıq lisenziyalıdır və Google\'ın özəl SafetyNet API kodunu ehtiva etmir.\n\Magisk Managerə SafetyNet yoxlamaları üçün tərkibində GoogleApiClient olan əlavəni yükləməyə icazə verirsiniz?</string>
<string name="setup_fail">Quraşdırma alınmadı.</string>
<string name="env_fix_title">Əlavə Quraşdırma Lazımdır</string>
<string name="env_fix_msg">Cihazınızın Magisk\'in düzgün işləməsi üçün əlavə quraşdırmaya ehtiyacı var . Bu Magisk zip faylını endirəcək, davam etmək istəyirsiniz?</string>
<string name="setup_title">Əlavə quraşdırma</string>
<string name="setup_msg">Quraşdırma yerinə yetirilir…</string>
<!--Settings Activity -->
<string name="settings_general_category">Ümumi</string>
<string name="settings_dark_theme_title">Qaranlıq Mövzu</string>
<string name="settings_dark_theme_summary">Qaranlıq mövzunu aç.</string>
<string name="settings_clear_cache_title">Repo Keşini Təmizlə</string>
<string name="settings_clear_cache_summary">Onlayn repolar üçün keşlənmiş məlumatı silin. Bu tətbiqi onlayn şəkildə yenilənməyə məcbur edir.</string>
<string name="settings_hide_manager_title">Magisk Manager\'i Gizlə</string>
<string name="settings_hide_manager_summary">Magisk Manager\'i təsadüfi adla yenidən sıxışdır.</string>
<string name="settings_restore_manager_title">Magisk Manager\'i Geri Qaytar</string>
<string name="settings_restore_manager_summary">Magisk Manager\'i orjinal sıxışdırma ilə geri qaytar</string>
<string name="language">Dil</string>
<string name="system_default">(Sistem Dili)</string>
<string name="settings_update">Tənzimləmələri Yenilə</string>
<string name="settings_check_update_title">Yeniləmələri Yoxla</string>
<string name="settings_check_update_summary">Axraplanda vaxtaşırı yeniləmələri yoxla.</string>
<string name="settings_update_channel_title">Kanalı Yenilə</string>
<string name="settings_update_stable">Stabil</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Özəl</string>
<string name="settings_update_custom_msg">Özəl URL daxil edin</string>
<string name="settings_core_only_title">Magisk Yalnız Nüvə Modu</string>
<string name="settings_core_only_summary">Yalnız nüvə xüsusiyyətlərini aç. MagiskSU və MagiskHide hələ də açıq qalacaq, amma əlavələr yüklənməyəcək.</string>
<string name="settings_magiskhide_summary">Magisk\'i fərqli növdə aşkarlamalardan gizləyin.</string>
<string name="settings_hosts_title">Sistemsiz host\'lar</string>
<string name="settings_hosts_summary">Adblock tətbiqləri üçün Sistemsiz host dəstəyi.</string>
<string name="settings_hosts_toast">Sistemsiz host əlavəsi quraşdırıldı</string>
<string name="settings_su_app_adb">Tətbiqlər və ADB</string>
<string name="settings_su_app">Yalnız Tətbiqlər</string>
<string name="settings_su_adb">Yalnız ADB</string>
<string name="settings_su_disable">Qapalı</string>
<string name="settings_su_request_10">10 saniyə</string>
<string name="settings_su_request_15">15 saniyə</string>
<string name="settings_su_request_20">20 saniyə</string>
<string name="settings_su_request_30">30 saniyə</string>
<string name="settings_su_request_45">45 saniyə</string>
<string name="settings_su_request_60">60 saniyə</string>
<string name="superuser_access">Superuser İcazəsi</string>
<string name="auto_response">Avtomatik Cavab</string>
<string name="request_timeout">İcazə Vaxtaşımı</string>
<string name="superuser_notification">Superuser Bildirişləri</string>
<string name="request_timeout_summary">%1$d saniyə</string>
<string name="settings_su_reauth_title">Yüksəltmədən sonra Yenidən İdentifikasiya et</string>
<string name="settings_su_reauth_summary">Tətbiq yeniləmələridən sonra superuser icazələrini yenidən identifikasiya et</string>
<string name="settings_su_fingerprint_title">Barmaq İzi İdentifikasiyasını</string>
<string name="settings_su_fingerprint_summary">Barmaq izi oxuyucunu superuser icazələri üçün işlət</string>
<string name="auth_fingerprint">Barmaq izini İdentifikasiya et</string>
<string name="multiuser_mode">Çox-istifadəçi modu</string>
<string name="settings_owner_only">Yalnız cihaz sahibi</string>
<string name="settings_owner_manage">Cihaz sahibinin idarəçiliyində</string>
<string name="settings_user_independent">İstifadəçidən asılı olmayaraq</string>
<string name="owner_only_summary">Yalnız cihaz sahibinin root icazəsi var.</string>
<string name="owner_manage_summary">Yalnız cihaz sahibi root icazələrini redaktə edə və icazə istəkləri qəbul edə bilər.</string>
<string name="user_indepenent_summary">Hər istifadəçinin ayrı root qaydaları var.</string>
<string name="mount_namespace_mode">Namespace Modunu Qoş</string>
<string name="settings_ns_global">Qlobal Namespace</string>
<string name="settings_ns_requester">Keçmə Namespace</string>
<string name="settings_ns_isolate">Ayrılmış Namespace</string>
<string name="global_summary">Bütün root sessyaları qlobal qoşma namespace\'dən istifadə edir.</string>
<string name="requester_summary">Root sessyaları soruşulan namespace\'ləri birindən digərinə keçirəcək.</string>
<string name="isolate_summary">Hər bir root sessyasının ayrılmış namespace\'i olacaq.</string>
<string name="android_o_not_support">Android 8.0+\'da dəstəklənmir.</string>
<string name="disable_fingerprint">Barmaq izi təyin edilməyib ya da dəstəklənmir.</string>
<!--Superuser-->
<string name="su_request_title">Superuser Tələbi</string>
<string name="deny">Ləğv et</string>
<string name="prompt">Yönləndir</string>
<string name="grant">Təmin et</string>
<string name="su_warning">Cihazın tam icazəsi ilə təmin edin.\nƏmin deyilsinizsə ləğv edin!</string>
<string name="forever">Sonsuz</string>
<string name="once">Bir dəfəlik</string>
<string name="tenmin">10 dəq</string>
<string name="twentymin">20 dəq</string>
<string name="thirtymin">30 dəq</string>
<string name="sixtymin">60 dəq</string>
<string name="su_allow_toast">%1$s SuperUser icazəsi ilə təmin edildi</string>
<string name="su_deny_toast">%1$s SuperUser icazəsi ilə təmin edilmədi</string>
<string name="no_apps_found">Tətbiq yoxdur</string>
<string name="su_snack_grant">%1$s üçün Superuser icazəsi verilib</string>
<string name="su_snack_deny">%1$s üçün Superuser icazəsi verilməyib</string>
<string name="su_snack_notif_on">%1$s üçün bildirişlər açıqdır</string>
<string name="su_snack_notif_off">%1$s üçün bildirişlər bağlıdır</string>
<string name="su_snack_log_on">%1$s üçün giriş açıqdır</string>
<string name="su_snack_log_off">%1$s üçün giriş bağlıdır</string>
<string name="su_revoke_title">Ləğv olunsun?</string>
<string name="su_revoke_msg">%1$s üçün haqları ləğv etməyi təsdiq edirsiniz?</string>
<string name="toast">Tost</string>
<string name="none">Heçnə</string>
<string name="auth_fail">İdentifikasiya xətası</string>
<!--Superuser logs-->
<string name="pid">PID: %1$d</string>
<string name="target_uid">Hədəf UID: %1$d</string>
<string name="command">Komanda: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">Sistem tətbiqlərini göstər</string>
</resources>

View File

@@ -61,7 +61,6 @@
<string name="app_changelog">Списък с промени</string>
<!--Toasts, Dialogs-->
<string name="close">Затваряне</string>
<string name="repo_install_title">Инсталиране на %1$s</string>
<string name="repo_install_msg">Желаете ли да инсталирате %1$s сега?</string>
<string name="download">Изтегляне</string>
@@ -162,7 +161,6 @@
<string name="global_summary">Всички сесии с руут достъп използват глобалното именно пространство.</string>
<string name="requester_summary">Всички сесии с руут достъп наследяват именното пространство на запитващото приложение.</string>
<string name="isolate_summary">Всички сесии с руут достъп имат собствени именни пространства.</string>
<string name="android_o_not_support">Не поддържа Android 8.0+.</string>
<string name="disable_fingerprint">Не са добавени пръстови отпечатъци или устройството не поддържа тази функция.</string>
<!--Superuser-->

View File

@@ -24,6 +24,7 @@
<string name="advanced_settings_title">Configuració avançada</string>
<string name="keep_force_encryption">Mantenir el xifrat forçat</string>
<string name="keep_dm_verity">Mantenir AVB 2.0/dm-verity</string>
<string name="recovery_mode">Mode de Recuperació</string>
<string name="current_installed">Instal·lada: %1$s</string>
<string name="latest_version">Última: %1$s</string>
<string name="uninstall">Desinstal·lar</string>
@@ -75,19 +76,18 @@
<string name="manager_update_title">Actualització de Magisk Manager disponible!</string>
<!-- Installation -->
<string name="manager_download_install">Prem per descarregar i instalar.</string>
<string name="download_zip_only">Descarrega només el ZIP</string>
<string name="manager_download_install">Premi per baixar i instalar.</string>
<string name="download_zip_only">Únicament baixa el ZIP</string>
<string name="direct_install">Instal·lació directa (Recomanat)</string>
<string name="install_inactive_slot">Instal·la a la ranura inactiva (Després d\'una OTA)</string>
<string name="install_inactive_slot_msg">El teu dispositiu serà FORÇAT a arrancar en l\'actual ranura inactiva després del reinici!\nUtilitza aquesta opció NOMÉS quan l\'OTA s\'hagi fet.\nContinuar?</string>
<string name="select_method">Sel·lecciona mètode</string>
<string name="select_method">Sel·lecciona un mètode</string>
<string name="setup_title">Instal·lació addicional</string>
<string name="select_patch_file">Sel·lecciona i arranja un arxiu</string>
<string name="patch_file_msg">Sel·lecciona una imatge crua (*.img) o un ODIN tarfile (*.tar)</string>
<string name="reboot_delay_toast">Reinici en 5 segons…</string>
<!--Toasts, Dialogs-->
<string name="close">Tancar</string>
<string name="repo_install_title">Instal·lar %1$s</string>
<string name="repo_install_msg">Vols instal·lar %1$s ara?</string>
<string name="download">Baixar</string>
@@ -110,23 +110,23 @@
<string name="restore_img_msg">Restaurant…</string>
<string name="restore_done">Restauració feta!</string>
<string name="restore_fail">La còpia de seguretat de Stock no existeix!</string>
<string name="proprietary_title">Descarrega codi propietari</string>
<string name="proprietary_notice">Magisk Manager és codi lliure i no conté codi de l\'API de SafetyNet, ja que és codi propietari de Google.\n\nPot permetre que Magisk Manager descarregui una extensió que conté el GoogleApiClient per poder fer la comprobació de SafetyNet?</string>
<string name="proprietary_title">Baixar codi propietari</string>
<string name="proprietary_notice">Magisk Manager és codi lliure i no conté codi de l\'API de SafetyNet, ja que és codi propietari de Google.\n\nPot permetre que Magisk Manager baixi una extensió que conté el GoogleApiClient per poder fer la comprobació de SafetyNet?</string>
<string name="setup_fail">Instal·lació fallida.</string>
<string name="env_fix_title">Es requereix instal·lació addicional</string>
<string name="env_fix_msg">El teu dispositiu necessita instal·lació addicional per Magisk per funcionar correctament. Es descarregarà el ZIP d\'instal·lació de Magisk , vol procedir a l\'instalació ara?</string>
<string name="env_fix_msg">El teu dispositiu necessita instal·lació addicional per Magisk per funcionar correctament. Es baixarà el ZIP d\'instal·lació de Magisk , vol procedir a l\'instalació ara?</string>
<string name="setup_msg">S\'està executant la configuració de l\'entorn…</string>
<!--Settings Activity -->
<string name="settings_general_category">General</string>
<string name="settings_dark_theme_title">Tema obscur</string>
<string name="settings_dark_theme_summary">Habilitar el tema obscur</string>
<string name="settings_download_path_title">Directori de descàrrega</string>
<string name="settings_dark_theme_title">Tema fosc</string>
<string name="settings_dark_theme_summary">Habilitar el tema fosc</string>
<string name="settings_download_path_title">Directori de baixades</string>
<string name="settings_download_path_message">Els arxius es desaràn a %1$s</string>
<string name="settings_clear_cache_title">Netejar memòria cau del repositori</string>
<string name="settings_clear_cache_summary">Neteja l\'informació en memòria cau per als repositoris en línia, força a l\'aplicació a actualitzar-se en línia.</string>
<string name="settings_hide_manager_title">Amagar Magisk Manager</string>
<string name="settings_hide_manager_summary">Re-empaquetar Magisk Manager amb un nom de paquet a l\'atzar</string>
<string name="settings_hide_manager_summary">Reempaquetar Magisk Manager amb un nom de paquet a l\'atzar</string>
<string name="settings_restore_manager_title">Restaurar Magisk Manager</string>
<string name="settings_restore_manager_summary">Restaura Magisk Manager amb el nom de paquet original</string>
<string name="language">Idioma</string>
@@ -146,6 +146,10 @@
<string name="settings_hosts_summary">Suport per aplicacions tipus Adblock fora de la partició del sistema</string>
<string name="settings_hosts_toast">Agregat el mòdul Systemless Hosts</string>
<string name="settings_app_name">Escriu el nom desitjat per l\'App</string>
<string name="settings_app_name_hint">Nou nom</string>
<string name="settings_app_name_helper">Es refarà l\'App amb aquest nom</string>
<string name="settings_app_name_error">Format invàl·lid</string>
<string name="settings_su_app_adb">Aplicacions y ADB</string>
<string name="settings_su_app">Només aplicacions</string>
<string name="settings_su_adb">Només ADB</string>
@@ -161,8 +165,8 @@
<string name="request_timeout">Temps de petició</string>
<string name="superuser_notification">Notificació de superusuari</string>
<string name="request_timeout_summary">%1$d segons</string>
<string name="settings_su_reauth_title">Re-autenticació</string>
<string name="settings_su_reauth_summary">Demanar permisos de superusuari novament si una aplicació es actualitzada o reinstal·lada</string>
<string name="settings_su_reauth_title">Demanar després d\'una actualització</string>
<string name="settings_su_reauth_summary">Demanar permisos de superusuari novament si una aplicació és actualitzada o reinstal·lada</string>
<string name="settings_su_fingerprint_title">Autenticació per Empremta Dactilar</string>
<string name="settings_su_fingerprint_summary">Utilitza el sensor d\'Empremta Dactilar per permetre les sol·licituds de superusuari</string>
<string name="auth_fingerprint">Autenticar Emprempta Digital</string>
@@ -174,7 +178,7 @@
<string name="owner_only_summary">Només l\'administrador té accés d\'arrel</string>
<string name="owner_manage_summary"> Només l\'administrador pot supervisar l\'acces d\'arrel y rebre sol·licituds d\'altres usuaris</string>
<string name="user_indepenent_summary">Tots els usuaris tenen separades les seves pròpies regles d\'arrel </string>
<string name="mount_namespace_mode">Muntar Namespace </string>
<string name="settings_ns_global">Namespace Global</string>
<string name="settings_ns_requester">Heretar Namespace</string>
@@ -182,7 +186,6 @@
<string name="global_summary">Totes les sessions d\'arrel utilitzen el suport Namespace Global</string>
<string name="requester_summary">Les sessions d\'arrel heretaran les peticiones Namespace</string>
<string name="isolate_summary">Totes les sessions d\'arrel tindran la seva pròpia Namespace</string>
<string name="android_o_not_support">No es compatible amb Android 8.0+</string>
<string name="disable_fingerprint">No s\'han establert empremtes dactilars o no existeix el suport del dispositiu</string>
<string name="settings_download_path_error">Error al crear la carpeta. El directori ha de ser accesible desde el directori arrel i no pot ser un arxiu.</string>
@@ -217,7 +220,7 @@
<string name="pid">PID: %1$d</string>
<string name="target_uid">UID de l\'objectiu: %1$d</string>
<string name="command">Ordre: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">Mostra apps del sistema</string>

View File

@@ -84,7 +84,6 @@
<string name="reboot_delay_toast">Restartování za 5 sekund…</string>
<!--Toasts, Dialogs-->
<string name="close">Zavřít</string>
<string name="repo_install_title">Instalovat %1$s</string>
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
<string name="download">Stáhnout</string>
@@ -175,7 +174,6 @@
<string name="global_summary">Všechny relace root používají globální připojení jmenného prostoru.</string>
<string name="requester_summary">Kořenové relace dědí jmenný prostor žadatele.</string>
<string name="isolate_summary">Každá relace root bude mít svůj vlastní izolovaný jmenný prostor.</string>
<string name="android_o_not_support">Nepodporuje Android 8.0+.</string>
<string name="disable_fingerprint">Nebyly nastaveny žádné otisky prstů ani žádná podpora zařízení.</string>
<!--Superuser-->

View File

@@ -84,7 +84,6 @@
<string name="reboot_delay_toast">Neustart in 5 Sekunden…</string>
<!--Toasts, Dialogs-->
<string name="close">Schließen</string>
<string name="repo_install_title">Installiere %1$s</string>
<string name="repo_install_msg">Möchtest du %1$s installieren?</string>
<string name="download">Herunterladen</string>
@@ -177,7 +176,6 @@
<string name="global_summary">Alle Root-Sitzungen benutzen den global angelegten Namespace</string>
<string name="requester_summary">Root-Sitzungen erben den Namespace des Abfragenden</string>
<string name="isolate_summary">Jede Root-Sitzung hat ihren isolierten Namespace</string>
<string name="android_o_not_support">Android 8.0+ wird nicht unterstützt</string>
<string name="disable_fingerprint">Keine Fingerabdrücke gespeichert oder keine Geräteunterstützung</string>
<!--Superuser-->

View File

@@ -62,7 +62,6 @@
<string name="app_changelog">Καταγραφή αλλαγών εφαρμογής</string>
<!--Toasts, Dialogs-->
<string name="close">Κλείσιμο</string>
<string name="repo_install_title">Εγκατάσταση %1$s</string>
<string name="repo_install_msg">Θέλετε να εγκαταστήσετε το %1$s τώρα;</string>
<string name="download">Λήψη</string>
@@ -144,7 +143,6 @@
<string name="global_summary">Όλες οι συνεδρίες root χρησιμοποιούν τον καθολικό χώρο oνομάτων προσάρτησης</string>
<string name="requester_summary">Οι συνεδρίες root θα κληρονομούν το χώρο ονομάτων του αιτούντα τους</string>
<string name="isolate_summary">Κάθε συνεδρία root θα έχει το δικό της απομονωμένο χώρο ονομάτων</string>
<string name="android_o_not_support">Δεν υποστηρίζεται Android 8.0+</string>
<!--Superuser-->
<string name="su_request_title">Αίτημα υπερχρήστη</string>

View File

@@ -24,7 +24,7 @@
<string name="advanced_settings_title">Ajustes avanzados</string>
<string name="keep_force_encryption">Mantener cifrado forzado</string>
<string name="keep_dm_verity">Mantener AVB 2.0/dm-verity</string>
<string name="recovery_mode">Modo Recovery</string>
<string name="recovery_mode">Modo Recovery</string>
<string name="current_installed">Instalada: %1$s</string>
<string name="latest_version">Última: %1$s</string>
<string name="uninstall">Desinstalar</string>
@@ -45,7 +45,7 @@
<string name="reboot_recovery">Reiniciar en Modo Recovery</string>
<string name="reboot_bootloader">Reiniciar en Modo Bootloader</string>
<string name="reboot_download">Reiniciar en Modo Download</string>
<string name="reboot_edl">Reiniciar en Modo EDL</string>
<string name="reboot_edl">Reiniciar en Modo EDL</string>
<!--Repo Fragment-->
<string name="update_available">Actualización Disponible</string>
@@ -72,21 +72,20 @@
<string name="download_file_error">Error descargando archivo</string>
<string name="magisk_update_title">Actualización de Magisk disponible!</string>
<string name="manager_update_title">Actualización de Magisk Manager disponible!</string>
<!-- Installation -->
<string name="manager_download_install">Pulse para descargar e instalar</string>
<string name="download_zip_only">Descargar sólo el archivo ZIP</string>
<string name="direct_install">Instalación Directa (Recomendado)</string>
<string name="install_inactive_slot">Instalar en ranura inactiva (después de OTA)</string>
<string name="install_inactive_slot_msg">¡Se forzará su dispositivo para que arranque en la ranura inactiva actual después de un reinicio!\nUtilice esta opción solo después de que se haya completado la OTA.\nContinuar?</string>
<string name="select_method">Seleccionar Método</string>
<string name="setup_title">Configuración Adicional</string>
<string name="select_patch_file">Seleccionar y parchear un archivo</string>
<string name="patch_file_msg">Seleccione una imagen raw (* .img) o un archivo tar de ODIN (* .tar)</string>
<string name="reboot_delay_toast">Reiniciando en 5 segundos…</string>
<!-- Installation -->
<string name="manager_download_install">Pulse para descargar e instalar</string>
<string name="download_zip_only">Descargar sólo el archivo ZIP</string>
<string name="direct_install">Instalación Directa (Recomendado)</string>
<string name="install_inactive_slot">Instalar en ranura inactiva (después de OTA)</string>
<string name="install_inactive_slot_msg">¡Se forzará su dispositivo para que arranque en la ranura inactiva actual después de un reinicio!\nUtilice esta opción solo después de que se haya completado la OTA.\nContinuar?</string>
<string name="select_method">Seleccionar Método</string>
<string name="setup_title">Configuración Adicional</string>
<string name="select_patch_file">Seleccionar y parchear un archivo</string>
<string name="patch_file_msg">Seleccione una imagen raw (* .img) o un archivo tar de ODIN (* .tar)</string>
<string name="reboot_delay_toast">Reiniciando en 5 segundos…</string>
<!--Toasts, Dialogs-->
<string name="close">Cerrar</string>
<string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">¿Quieres instalar %1$s ahora?</string>
<string name="download">Descargar</string>
@@ -121,7 +120,7 @@
<string name="settings_dark_theme_title">Tema oscuro</string>
<string name="settings_dark_theme_summary">Habilitar el tema oscuro</string>
<string name="settings_download_path_title">Ruta de Descarga</string>
<string name="settings_download_path_message">Los archivos se guardarán en %1$s</string>
<string name="settings_download_path_message">Los archivos se guardarán en %1$s</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_hide_manager_title">Ocultar Magisk Manager</string>
@@ -180,7 +179,6 @@
<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="android_o_not_support">No es compatible con Android 8.0+</string>
<string name="disable_fingerprint">No se establecieron huellas dactilares o no existe soporte del dispositivo</string>
<string name="settings_download_path_error">Error al crear la carpeta. Debe ser accesible desde el directorio raíz de almacenamiento y no debe ser un archivo.</string>
@@ -218,5 +216,5 @@
<!-- MagiskHide -->
<string name="show_system_app">Mostrar sistema</string>
</resources>

View File

@@ -88,7 +88,6 @@
<string name="reboot_delay_toast">Taaskäivitamine 5 sekundi pärast…</string>
<!--Toasts, Dialogs-->
<string name="close">Sulge</string>
<string name="repo_install_title">Installi %1$s</string>
<string name="repo_install_msg">Kas soovid kohe installida %1$s?</string>
<string name="download">Allalaadimine</string>
@@ -183,7 +182,6 @@
<string name="global_summary">Kõik juurkasutaja sessioonid kasutavad globaalset monteerimise nimeruumi.</string>
<string name="requester_summary">Juurkasutaja sessioonid võtavad üle selle taotleja nimeruumi.</string>
<string name="isolate_summary">Iga juurkasutaja sessioon saab oma isoleeritud nimeruumi.</string>
<string name="android_o_not_support">Ei toeta Androidi versiooni 8.0+.</string>
<string name="disable_fingerprint">Sõrmejälgi pole määratud või seade pole toetatud.</string>
<string name="settings_download_path_error">Faili loomisel esines viga. See peab olema ligipääsetav mäluruumi juurkaustast ning ei tohi olla fail.</string>

View File

@@ -88,7 +88,6 @@
<string name="reboot_delay_toast">Redémarrage dans 5 secondes…</string>
<!--Toasts, Dialogs-->
<string name="close">Fermer</string>
<string name="repo_install_title">Installer %1$s</string>
<string name="repo_install_msg">Voulezvous installer %1$s maintenant?</string>
<string name="download">Télécharger</string>
@@ -146,7 +145,10 @@
<string name="settings_hosts_title">Fichier hosts sans système</string>
<string name="settings_hosts_summary">Prise en charge du fichier hosts sans système pour les applications de type AdBlock.</string>
<string name="settings_hosts_toast">Ajout dun module hosts sans système</string>
<string name="settings_app_name">Taper le nom de l\'application désirée</string>
<string name="settings_app_name_hint">Nouveau nom</string>
<string name="settings_app_name_helper">L\'application sera réempacter sous ce nom</string>
<string name="settings_app_name_error">Format invalide</string>
<string name="settings_su_app_adb">Applications et ADB</string>
<string name="settings_su_app">Applications uniquement</string>
<string name="settings_su_adb">ADB uniquement</string>
@@ -183,7 +185,6 @@
<string name="global_summary">Toutes les sessions superutilisateur utilisent lespace de noms global du montage.</string>
<string name="requester_summary">Les sessions superutilisateur hériteront de lespace de noms de leur demandeur.</string>
<string name="isolate_summary">Chaque session superutilisateur aura son propre espace de noms isolé.</string>
<string name="android_o_not_support">Android 8.0 et supérieurs ne sont pas pris en charge.</string>
<string name="disable_fingerprint">Aucune empreinte digitale na été définie ou le lecteur dempreinte nest pas pris en charge.</string>
<string name="settings_download_path_error">Erreur lors de la création du dossier. Il doit être accessible depuis le répertoire racine du stockage et ne doit pas être un fichier.</string>

View File

@@ -0,0 +1,223 @@
<resources>
<!--Welcome Activity-->
<string name="modules">मॉड्यूल</string>
<string name="downloads">डाउनलोड</string>
<string name="superuser">उत्तम उपयोगकर्ता</string>
<string name="log">अभिलेख</string>
<string name="settings">सेटिंग्स</string>
<string name="install">स्थापित करें</string>
<string name="unsupport_magisk_title">असमर्थित Magisk संस्करण</string>
<string name="unsupport_magisk_message">Magisk Manager का यह संस्करण Magisk के v18.0 संस्करण से कम का समर्थन नहीं करता है.\n\nआप या तो खुद से Magisk को अपग्रेड करें, या फिर एप्लीकेशन को पुराने संस्करण पे डाउनग्रेड करें .</string>
<!--Status Fragment-->
<string name="magisk_version_error">Magisk स्थापित नहीं है</string>
<string name="checking_for_updates">अपडेट्स के लिए जांच हो रही है…</string>
<string name="invalid_update_channel">अमान्य अपडेट चैनल</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_api_error">SafetyNet API त्रुटि</string>
<string name="safetyNet_res_invalid">अनुक्रिया अमान्य है.</string>
<string name="magisk_up_to_date">Magisk अप टू डेट है</string>
<string name="manager_up_to_date">Magisk Manager अप टू डेट है</string>
<string name="advanced_settings_title">एडवांस सेटिंग्स</string>
<string name="keep_force_encryption">बल एन्क्रिप्शन को बनाये रखें</string>
<string name="keep_dm_verity">AVB 2.0/dm-verity को बनाये रखें</string>
<string name="recovery_mode">रिकवरी मोड</string>
<string name="current_installed">स्थापित: %1$s</string>
<string name="latest_version">नवीनतम: %1$s</string>
<string name="uninstall">स्थापना रद्द करें</string>
<string name="uninstall_magisk_title">Magisk की स्थापना रद्द करें</string>
<string name="uninstall_magisk_msg">सभी मॉड्यूल अक्षम/हटा दिए जाएंगे. रुट और आपका संभावित रूप से एन्क्रिप्ट डाटा हटा दिया जाएगा.</string>
<string name="update">अपडेट करें</string>
<string name="core_only_enabled">(केवल मूल मोड समर्थकृत)</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="reboot_recovery">रिकवरी मोड में रिबूट करें</string>
<string name="reboot_bootloader">बूटलोडर में रिबूट करें</string>
<string name="reboot_download">डाउनलोड में रिबूट करें</string>
<string name="reboot_edl">EDL मोड में रिबूट करें</string>
<!--Repo Fragment-->
<string name="update_available">अपडेट उपलब्ध है</string>
<string name="installed">स्थापित</string>
<string name="not_installed">स्थापित नहीं है</string>
<string name="updated_on">%1$s को अपडेट किया गया</string>
<string name="sorting_order">छँटाई क्रम </string>
<string name="sort_by_name">नाम द्वारा छांटें</string>
<string name="sort_by_update">आखिरी अपडेट द्वारा छांटें</string>
<!--Log Fragment-->
<string name="menuSaveLog">अभिलेख सेव करें</string>
<string name="menuReload">पुनः लोड करें</string>
<string name="menuClearLog">अभिलेख साफ़ करें</string>
<string name="logs_cleared">अभिलेख सफलतापूर्वक साफ़ हो गया.</string>
<!--About Activity-->
<string name="app_changelog">परिवर्तन अभिलेख</string>
<!-- System Components, Notifications -->
<string name="update_channel">Magisk की अपडेट</string>
<string name="progress_channel">प्रगति सूचनाएँ</string>
<string name="download_complete">डाउनलोड सम्पन्न हुआ</string>
<string name="download_file_error">फ़ाइल डाउनलोड करने में त्रुटि</string>
<string name="download_open_parent">मूल फ़ोल्डर में दिखाएँ</string>
<string name="download_open_self">फाइल दिखाएँ</string>
<string name="magisk_update_title">Magisk की अपडेट उपलब्ध है!</string>
<string name="manager_update_title">Magisk Manager की अपडेट उपलब्ध है!</string>
<!-- Installation -->
<string name="manager_download_install">डाउनलोड और स्थापित करने के लिए दबाएँ.</string>
<string name="download_zip_only">खाली Zip डाउनलोड करें</string>
<string name="direct_install">सीधा स्थापित करें (अनुशंसित)</string>
<string name="install_inactive_slot">निष्क्रिय स्लॉट में स्थापित करें (OTA के बाद)</string>
<string name="install_inactive_slot_msg">आपके डिवाइस को रीबूट के बाद वर्तमान निष्क्रिय स्लॉट में बूट करने के लिए मजबूर किया जाएगा!\nOTA होने के बाद ही इस विकल्प का उपयोग करें.\nजारी रखें?</string>
<string name="select_method">विधि का चयन करें</string>
<string name="setup_title">अतिरिक्त सेटअप</string>
<string name="select_patch_file">एक फ़ाइल का चयन और पैच करें</string>
<string name="patch_file_msg">एक कच्ची इमेज चुनें (*.img) या एक ODIN tarfile (*.tar)</string>
<string name="reboot_delay_toast">5 सेकंड में रिबूट हो रहा है …</string>
<!--Toasts, Dialogs-->
<string name="repo_install_title">%1$s को स्थापित करें</string>
<string name="repo_install_msg">क्या आप %1$s को स्थापित करना चाहते हैं ?</string>
<string name="download">डाउनलोड</string>
<string name="reboot">रिबूट</string>
<string name="settings_reboot_toast">सेटिंग्स लागू करने के लिए रिबूट करें.</string>
<string name="release_notes">रिलीज नोट्स</string>
<string name="repo_cache_cleared">Repo cache साफ़ हो गया</string>
<string name="dtbo_patched_title">DTBO पैच कर दिया गया!</string>
<string name="dtbo_patched_reboot">Magisk Manager ने dtbo.img को पैच कर दिया. कृपया रिबूट करें.</string>
<string name="flashing">फ़्लैश हो रहा है…</string>
<string name="done">हो गया!</string>
<string name="failure">विफल हुआ</string>
<string name="hide_manager_title">Magisk Manager छुप रहा है…</string>
<string name="hide_manager_fail_toast">Magisk Manager छुपने में असफल रहा.</string>
<string name="open_link_failed_toast">लिंक खोलने के लिए कोई एप्लिकेशन नहीं मिला.</string>
<string name="warning">चेतावनी</string>
<string name="complete_uninstall">पूरी तरह से स्थापना रद्द करें</string>
<string name="restore_img">इमेजेज को पुनर्स्थापित करें</string>
<string name="restore_img_msg">वापस लाया जा रहा…</string>
<string name="restore_done">वापस ले आया गया!</string>
<string name="restore_fail">स्टॉक बैकअप मौजूद नहीं है!</string>
<string name="proprietary_title">मालिकाना कोड डाउनलोड करें</string>
<string name="proprietary_notice">Magisk Manager FOSS है और उस्में Google का मालिकाना SafetyNet API कोड शामिल नहीं है.\n\nक्या आप Magisk Manager को SafetyNet चेक के लिए एक्सटेंशन (GoogleApiClient शामिल) डाउनलोड करने की अनुमति देंगे ?</string>
<string name="setup_fail">सेटअप असफल हुआ.</string>
<string name="env_fix_title">अतिरिक्त सेटअप की आवश्यकता है</string>
<string name="env_fix_msg">ठीक से काम करने के लिए आपके डिवाइस को Magisk के लिए अतिरिक्त सेटअप की आवश्यकता है. यह Magisk सेटअप zip डाउनलोड करेगा, क्या आप आगे बढ़ना चाहते हैं?</string>
<string name="setup_msg">पर्यावरण सेटअप चल रहा है…</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_download_path_title">डाउनलोड करने की जगह</string>
<string name="settings_download_path_message">%1$s में फाइल्स रखी जाएँगी</string>
<string name="settings_clear_cache_title">Repo Cache साफ़ करें</string>
<string name="settings_clear_cache_summary">ऑनलाइन Repo के लिए Cached जानकारी साफ़ करें. यह एप्लिकेशन को ऑनलाइन रिफ्रेश होने के लिए मजबूर करता है.</string>
<string name="settings_hide_manager_title">Magisk Manager को छुपाएं</string>
<string name="settings_hide_manager_summary">Magisk Manager को क्रमरहित नाम से फिर से पैकेज करें.</string>
<string name="settings_restore_manager_title">Magisk Manager को पुनर्स्थापित करें</string>
<string name="settings_restore_manager_summary">Magisk Manager को अपने मूल पैकेज नाम से पुनर्स्थापित करें</string>
<string name="language">भाषा</string>
<string name="system_default">(सिस्टम डिफ़ॉल्ट)</string>
<string name="settings_update">सेटिंग्स अपडेट करें</string>
<string name="settings_check_update_title">अपडेट के लिए जाँच करें</string>
<string name="settings_check_update_summary">समय-समय पर बैकग्राउंड में अपडेट की जांच करते रहें.</string>
<string name="settings_update_channel_title">अपडेट का चैनल</string>
<string name="settings_update_stable">स्थिर</string>
<string name="settings_update_beta">बीटा</string>
<string name="settings_update_custom">कस्टम</string>
<string name="settings_update_custom_msg">एक कस्टम URL डालें</string>
<string name="settings_core_only_title">Magisk का केवल मूल मोड</string>
<string name="settings_core_only_summary">केवल मुख्य विशेषताएं सक्षम करें. MagiskSU और MagiskHide अभी भी सक्षम रहेंगे, लेकिन कोई मॉड्यूल लोड नहीं किया जाएगा.</string>
<string name="settings_magiskhide_summary">पता लगाने के विभिन्न रूपों से Magisk को छुपाएं.</string>
<string name="settings_hosts_title">सिस्टमलेस होस्ट्स</string>
<string name="settings_hosts_summary">एडब्लॉक ऍप्लिकेशन्स के लिए सिस्टमलेस होस्ट्स का समर्थन</string>
<string name="settings_hosts_toast">सिस्टमलेस होस्ट्स का मॉड्यूल जोड़ दिया गया</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_15">15 सेकंड्‌स</string>
<string name="settings_su_request_20">20 सेकंड्‌स</string>
<string name="settings_su_request_30">30 सेकंड्‌स</string>
<string name="settings_su_request_45">45 सेकंड्‌स</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$d सेकंड्‌स</string>
<string name="settings_su_reauth_title">अपग्रेड के बाद फिर से प्रमाणित करें</string>
<string name="settings_su_reauth_summary">एप्लीकेशन अपग्रेड होने के बाद उत्तम उपयोगकर्ता की अनुमतियों को फिर से प्रमाणित करें</string>
<string name="settings_su_fingerprint_title">फिंगरप्रिंट प्रमाणीकरण सक्षम करें</string>
<string name="settings_su_fingerprint_summary">उत्तम उपयोगकर्ता के अनुरोधों की अनुमति के लिए फिंगरप्रिंट स्कैनर का उपयोग करें</string>
<string name="auth_fingerprint">फिंगरप्रिंट को प्रमाणित करें</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="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="disable_fingerprint">कोई फ़िंगरप्रिंट नहीं सेट किया गया या डिवाइस का समर्थन नहीं है.</string>
<string name="settings_download_path_error">फोल्डर बनाने में त्रुटि. यह स्टोरेज रूट डायरेक्टरी से एक्सेस होना चाहिए और फाइल नहीं होना चाहिए.</string>
<!--Superuser-->
<string name="su_request_title">उत्तम उपयोगकर्ता का अनुरोध</string>
<string name="deny">इंकार करें</string>
<string name="prompt">आदेश</string>
<string name="grant">अनुमति दें</string>
<string name="su_warning">यह आपके डिवाइस की पूरी पहुँच की अनुमति देगा. यदि आप सुनिश्चित नहीं हैं तो इंकार करें!</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_revoke_title">वापस लें?</string>
<string name="su_revoke_msg">%1$s के अधिकारों को वापस लेने की पुष्टि करें?</string>
<string name="toast">पॉप-अप नोट</string>
<string name="none">कोई नहीं</string>
<string name="auth_fail">प्रमाणीकरण विफल हुआ</string>
<!--Superuser logs-->
<string name="pid">PID: %1$d</string>
<string name="target_uid">लक्ष्य UID: %1$d</string>
<string name="command">Command: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">सिस्टम ऍप्लिकेशन्स दिखाएं</string>
</resources>

View File

@@ -55,7 +55,6 @@
<string name="app_changelog">Popis izmjena aplikacije</string>
<!--Toasts, Dialogs-->
<string name="close">Zatvori</string>
<string name="repo_install_title">Instaliraj %1$s</string>
<string name="repo_install_msg">Da li želite instalirati %1$s sada?</string>
<string name="download">Preuzmi</string>

View File

@@ -86,7 +86,6 @@
<string name="reboot_delay_toast">Me-reboot dalam 5 detik…</string>
<!--Toasts, Dialogs-->
<string name="close">Tutup</string>
<string name="repo_install_title">Pasang %1$s</string>
<string name="repo_install_msg">Apakah Anda ingin memasang %1$s sekarang?</string>
<string name="download">Unduh</string>
@@ -181,7 +180,6 @@
<string name="global_summary">Semua sesi root menggunakan mount ruang nama global.</string>
<string name="requester_summary">Sesi root akan mewarisi ruang nama peminta mereka.</string>
<string name="isolate_summary">Setiap sesi root akan memiliki ruang nama tersendiri.</string>
<string name="android_o_not_support">Tidak mendukung Android 8.0+.</string>
<string name="disable_fingerprint">Tidak ada sidik jari diatur atau tidak ada dukungan perangkat.</string>
<string name="settings_download_path_error">Kesalahan membuat folder. Folder harus dapat diakses dari direktori penyimpanan root dan bukan merupakan file.</string>

View File

@@ -1,223 +1,225 @@
<resources>
<!--Welcome Activity-->
<string name="modules">Moduli</string>
<string name="downloads">Download</string>
<string name="superuser">Superuser</string>
<string name="log">Registro eventi</string>
<string name="settings">Impostazioni</string>
<string name="install">Installa</string>
<string name="unsupport_magisk_title">Versione di Magisk non supportata</string>
<string name="unsupport_magisk_message">Questa versione di Magisk Manager non supporta versioni di Magisk inferiori alla v18.0.\n\nPuoi aggiornare manualmente Magisk o tornare a una versione meno recente dell\'app.</string>
<!--Welcome Activity-->
<string name="modules">Moduli</string>
<string name="downloads">Download</string>
<string name="superuser">Superuser</string>
<string name="log">Registro eventi</string>
<string name="settings">Impostazioni</string>
<string name="install">Installa</string>
<string name="unsupport_magisk_title">Versione di Magisk non supportata</string>
<string name="unsupport_magisk_message">Questa versione di Magisk Manager non supporta versioni di Magisk inferiori alla v18.0.\n\nPuoi aggiornare manualmente Magisk o tornare a una versione meno recente dell\'app.</string>
<!--Status Fragment-->
<string name="magisk_version_error">Magisk non è installato.</string>
<string name="checking_for_updates">Controllo aggiornamenti…</string>
<string name="invalid_update_channel">Canale di aggiornamento non valido</string>
<string name="safetyNet_check_text">Tocca per controllare SafetyNet</string>
<string name="checking_safetyNet_status">Controllo stato SafetyNet…</string>
<string name="safetyNet_check_success">Controllo SafetyNet Superato</string>
<string name="safetyNet_api_error">Errore API SafetyNet</string>
<string name="safetyNet_res_invalid">La risposta non è valida.</string>
<string name="magisk_up_to_date">Magisk è aggiornato</string>
<string name="manager_up_to_date">Magisk Manager è aggiornato</string>
<string name="advanced_settings_title">Impostazioni avanzate</string>
<string name="keep_force_encryption">Mantieni crittografia forzata</string>
<string name="keep_dm_verity">Mantieni AVB 2.0/dm-verity</string>
<string name="current_installed">Installata: %1$s</string>
<string name="latest_version">Ultima: %1$s</string>
<string name="uninstall">Disinstalla</string>
<string name="uninstall_magisk_title">Disinstalla Magisk</string>
<string name="uninstall_magisk_msg">Tutti i moduli verranno disabilitati/rimossi. Il root verrà rimosso e i tuoi dati potrebbero essere criptati, nel caso non lo siano già.</string>
<string name="update">Aggiorna</string>
<string name="core_only_enabled">(Modalità solo Core abilitata)</string>
<!--Status Fragment-->
<string name="magisk_version_error">Magisk non è installato.</string>
<string name="checking_for_updates">Controllo aggiornamenti…</string>
<string name="invalid_update_channel">Canale di aggiornamento non valido</string>
<string name="safetyNet_check_text">Tocca per controllare SafetyNet</string>
<string name="checking_safetyNet_status">Controllo stato SafetyNet…</string>
<string name="safetyNet_check_success">Controllo SafetyNet Superato</string>
<string name="safetyNet_api_error">Errore API SafetyNet</string>
<string name="safetyNet_res_invalid">La risposta non è valida</string>
<string name="magisk_up_to_date">Magisk è aggiornato</string>
<string name="manager_up_to_date">Magisk Manager è aggiornato</string>
<string name="advanced_settings_title">Impostazioni avanzate</string>
<string name="keep_force_encryption">Mantieni crittografia forzata</string>
<string name="keep_dm_verity">Mantieni AVB 2.0/dm-verity</string>
<string name="current_installed">Installata: %1$s</string>
<string name="latest_version">Ultima: %1$s</string>
<string name="uninstall">Disinstalla</string>
<string name="uninstall_magisk_title">Disinstalla Magisk</string>
<string name="uninstall_magisk_msg">Tutti i moduli verranno disabilitati/rimossi!\nIl root verrà rimosso e i tuoi dati potrebbero essere criptati, nel caso non lo siano già.</string>
<string name="update">Aggiorna</string>
<string name="core_only_enabled">(Modalità solo Core abilitata)</string>
<!--Module Fragment-->
<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>
<string name="remove_file_deleted">Il modulo non sarà rimosso al prossimo riavvio.</string>
<string name="disable_file_created">Il modulo sarà disabilitato 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="reboot_recovery">Riavvia in Recovery</string>
<string name="reboot_bootloader">Riavvia in Bootloader</string>
<string name="reboot_download">Riavvia in Download Mode</string>
<!--Module Fragment-->
<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>
<string name="remove_file_deleted">Il modulo non sarà rimosso al prossimo riavvio.</string>
<string name="disable_file_created">Il modulo sarà disabilitato 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="reboot_recovery">Riavvia in Recovery</string>
<string name="reboot_bootloader">Riavvia in Bootloader</string>
<string name="reboot_download">Riavvia in Download Mode</string>
<!--Repo Fragment-->
<string name="update_available">Aggiornamento disponibile</string>
<string name="installed">Installato</string>
<string name="not_installed">Non installato</string>
<string name="updated_on">Aggiornato il: %1$s</string>
<string name="sorting_order">Ordinamento</string>
<string name="sort_by_name">Ordina per nome</string>
<string name="sort_by_update">Ordina per ultimo aggiornamento</string>
<!--Repo Fragment-->
<string name="update_available">Aggiornamento disponibile</string>
<string name="installed">Installato</string>
<string name="not_installed">Non installato</string>
<string name="updated_on">Aggiornato il: %1$s</string>
<string name="sorting_order">Ordinamento</string>
<string name="sort_by_name">Ordina per nome</string>
<string name="sort_by_update">Ordina per ultimo aggiornamento</string>
<!--Log Fragment-->
<string name="menuSaveLog">Salva registro eventi</string>
<string name="menuReload">Ricarica</string>
<string name="menuClearLog">Svuota il registro eventi</string>
<string name="logs_cleared">Registro eventi svuotato correttamente.</string>
<!--Log Fragment-->
<string name="menuSaveLog">Salva registro eventi</string>
<string name="menuReload">Ricarica</string>
<string name="menuClearLog">Svuota il registro eventi</string>
<string name="logs_cleared">Registro eventi svuotato correttamente.</string>
<!--About Activity-->
<string name="app_changelog">Novità</string>
<string name="app_changelog">Novità</string>
<!-- System Components, Notifications -->
<string name="update_channel">Aggiornamenti Magisk</string>
<string name="progress_channel">Notifiche di avanzamento</string>
<string name="download_complete">Download completato</string>
<string name="update_channel">Aggiornamenti Magisk</string>
<string name="progress_channel">Notifiche di avanzamento</string>
<string name="download_complete">Download completato</string>
<string name="download_file_error">Errore durante il download del file</string>
<string name="download_open_parent">Mostra nella cartella padre</string>
<string name="download_open_self">Mostra file</string>
<string name="magisk_update_title">È disponibile un aggiornamento di Magisk!</string>
<string name="manager_update_title">È disponibile un aggiornamento di Magisk Manager!</string>
<string name="download_open_self">Mostra file</string>
<string name="magisk_update_title">È disponibile un aggiornamento di Magisk!</string>
<string name="manager_update_title">È disponibile un aggiornamento di Magisk Manager!</string>
<!-- Installation -->
<string name="manager_download_install">Apri questa notifica per scaricare e installare.</string>
<string name="download_zip_only">Scarica solo il file zip</string>
<string name="direct_install">Installazione diretta (raccomandata)</string>
<string name="install_inactive_slot">Installa nello slot inattivo (dopo un OTA)</string>
<string name="install_inactive_slot_msg">Questo dispositivo verrà FORZATO ad avviarsi usando lo slot inattivo!\nUsa questo metodo solo dopo che un OTA è stato installato.\nVuoi continuare?</string>
<string name="select_method">Seleziona un metodo</string>
<string name="setup_title">Configurazione aggiuntiva</string>
<string name="select_patch_file">Seleziona e aggiorna un file</string>
<string name="patch_file_msg">Seleziona un\'immagine in formato .img o un file ODIN .tar</string>
<string name="reboot_delay_toast">Riavvio fra 5 secondi…</string>
<!--Toasts, Dialogs-->
<string name="close">Chiudi</string>
<string name="repo_install_title">Installazione di %1$s</string>
<string name="repo_install_msg">Vuoi installare %1$s?</string>
<string name="download">Download</string>
<string name="reboot">Riavvia</string>
<string name="settings_reboot_toast">Riavvia per applicare i cambiamenti.</string>
<string name="release_notes">Note di rilascio</string>
<string name="repo_cache_cleared">La cache delle repository è stata svuotata</string>
<!-- Installation -->
<string name="manager_download_install">Apri questa notifica per scaricare e installare</string>
<string name="download_zip_only">Scarica solo il file zip</string>
<string name="direct_install">Installazione diretta (raccomandata)</string>
<string name="install_inactive_slot">Installa nello slot inattivo (dopo un OTA)</string>
<string name="install_inactive_slot_msg">Questo dispositivo verrà FORZATO ad avviarsi usando lo slot inattivo!\nUsa questo metodo solo dopo che un OTA è stato installato.\nVuoi continuare?</string>
<string name="select_method">Seleziona un metodo</string>
<string name="setup_title">Configurazione aggiuntiva</string>
<string name="select_patch_file">Seleziona e aggiorna un file</string>
<string name="patch_file_msg">Seleziona un\'immagine in formato .img o un file ODIN .tar</string>
<string name="reboot_delay_toast">Riavvio fra 5 secondi…</string>
<!--Toasts, Dialogs-->
<string name="repo_install_title">Installazione di %1$s</string>
<string name="repo_install_msg">Vuoi installare %1$s?</string>
<string name="download">Download</string>
<string name="reboot">Riavvia</string>
<string name="settings_reboot_toast">Riavvia per applicare i cambiamenti</string>
<string name="release_notes">Note di rilascio</string>
<string name="repo_cache_cleared">La cache delle repository è stata svuotata</string>
<string name="dtbo_patched_title">DTBO è stato aggiornato!</string>
<string name="dtbo_patched_reboot">Magisk Manager ha aggiornato dtbo.img. Riavvia per completare.</string>
<string name="flashing">Flash in corso…</string>
<string name="done">Completato!</string>
<string name="failure">Fallito</string>
<string name="hide_manager_title">Nascondendo Magisk Manager…</string>
<string name="hide_manager_fail_toast">Non è stato possibile nascondere Magisk Manager.</string>
<string name="open_link_failed_toast">Nessuna app disponibile per aprire il link.</string>
<string name="warning">Attenzione</string>
<string name="complete_uninstall">Disinstallazione completa</string>
<string name="restore_img">Ripristina Immagini</string>
<string name="restore_img_msg">Ripristino…</string>
<string name="restore_done">Ripristino completato!</string>
<string name="restore_fail">Non esiste un\'immagine originale di boot!</string>
<string name="proprietary_title">Scarica codice proprietario</string>
<string name="proprietary_notice">Magisk Manager è FOSS e non contiene codice proprietario delle API Google SafetyNet.\n\nVuoi scaricare un\'estensione (contenente GoogleApiClient) per controllare lo stato di SafetyNet?</string>
<string name="setup_fail">Configurazione fallita.</string>
<string name="env_fix_title">Configurazione aggiuntiva richiesta</string>
<string name="env_fix_msg">Il tuo dispositivo necessita di una configurazione aggiuntiva per far funzionare Magisk correttamente. Verrà scaricato il file zip di Magisk, vuoi procedere ora?</string>
<string name="setup_msg">Configurazione dell\'ambiente in corso…</string>
<string name="dtbo_patched_reboot">Magisk Manager ha aggiornato dtbo.img. Riavvia per completare.</string>
<string name="flashing">Flash in corso…</string>
<string name="done">Completato!</string>
<string name="failure">Fallito</string>
<string name="hide_manager_title">Nascondendo Magisk Manager…</string>
<string name="hide_manager_fail_toast">Non è stato possibile nascondere Magisk Manager.</string>
<string name="open_link_failed_toast">Nessuna app disponibile per aprire il link</string>
<string name="warning">Attenzione</string>
<string name="complete_uninstall">Disinstallazione completa</string>
<string name="restore_img">Ripristina Immagini</string>
<string name="restore_img_msg">Ripristino…</string>
<string name="restore_done">Ripristino completato!</string>
<string name="restore_fail">Non esiste un\'immagine originale di boot!</string>
<string name="proprietary_title">Scarica codice proprietario</string>
<string name="proprietary_notice">Magisk Manager è FOSS e non contiene codice proprietario delle API Google SafetyNet.\n\nVuoi scaricare un\'estensione (contenente GoogleApiClient) per controllare lo stato di SafetyNet?</string>
<string name="setup_fail">Configurazione fallita</string>
<string name="env_fix_title">Configurazione aggiuntiva richiesta</string>
<string name="env_fix_msg">Il tuo dispositivo necessita di una configurazione aggiuntiva per far funzionare Magisk correttamente. Verrà scaricato il file zip di Magisk, vuoi procedere ora?</string>
<string name="setup_msg">Configurazione dell\'ambiente in corso…</string>
<!--Settings Activity -->
<string name="settings_general_category">Generale</string>
<string name="settings_dark_theme_title">Tema scuro</string>
<string name="settings_dark_theme_summary">Abilita il tema scuro.</string>
<string name="settings_dark_theme_title">Tema scuro</string>
<string name="settings_dark_theme_summary">Abilita il tema scuro</string>
<string name="settings_download_path_title">Percorso di download</string>
<string name="settings_download_path_message">I file verranno salvati in %1$s</string>
<string name="settings_clear_cache_title">Svuota cache repository</string>
<string name="settings_clear_cache_summary">Svuota la cache delle repository. Questa opzione forza l\'aggiornamento online dell\'app.</string>
<string name="settings_hide_manager_title">Nascondi Magisk Manager</string>
<string name="settings_hide_manager_summary">Reinstalla Magisk Manager con un nome pacchetto casuale.</string>
<string name="settings_restore_manager_title">Ripristina Magisk Manager</string>
<string name="settings_restore_manager_summary">Ripristina Magisk Manager con il nome pacchetto originale</string>
<string name="language">Lingua</string>
<string name="system_default">(Sistema)</string>
<string name="settings_update">Impostazioni aggiornamento</string>
<string name="settings_check_update_title">Controlla aggiornamenti</string>
<string name="settings_check_update_summary">Controlla automaticamente gli aggiornamenti in background.</string>
<string name="settings_update_channel_title">Canale di aggiornamento</string>
<string name="settings_update_stable">Stabile</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Personalizzato</string>
<string name="settings_update_custom_msg">Inserisci un URL personalizzato</string>
<string name="settings_core_only_title">Modalità Magisk Core</string>
<string name="settings_core_only_summary">Abilita solo le funzioni principali. Nessun modulo verrà caricato. MagiskSU e MagiskHide rimarranno abilitati</string>
<string name="settings_magiskhide_summary">Nasconde Magisk da numerose rilevazioni.</string>
<string name="settings_hosts_title">Host systemless</string>
<string name="settings_hosts_summary">Supporto a host systemless per le app che bloccano le pubblicità.</string>
<string name="settings_hosts_toast">Aggiunto modulo per host systemless</string>
<string name="settings_clear_cache_title">Svuota cache repository</string>
<string name="settings_clear_cache_summary">Svuota la cache delle repository. Questa opzione forza l\'aggiornamento online dell\'app</string>
<string name="settings_hide_manager_title">Nascondi Magisk Manager</string>
<string name="settings_hide_manager_summary">Reinstalla Magisk Manager con un nome pacchetto e app casuali</string>
<string name="settings_restore_manager_title">Ripristina Magisk Manager</string>
<string name="settings_restore_manager_summary">Ripristina Magisk Manager con il nome pacchetto e app originali</string>
<string name="language">Lingua</string>
<string name="system_default">(Sistema)</string>
<string name="settings_update">Impostazioni aggiornamento</string>
<string name="settings_check_update_title">Controlla aggiornamenti</string>
<string name="settings_check_update_summary">Controlla automaticamente gli aggiornamenti in background</string>
<string name="settings_update_channel_title">Canale di aggiornamento</string>
<string name="settings_update_stable">Stabile</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Personalizzato</string>
<string name="settings_update_custom_msg">Inserisci un URL personalizzato</string>
<string name="settings_core_only_title">Modalità Magisk Core</string>
<string name="settings_core_only_summary">Abilita solo le funzioni principali. Nessun modulo verrà caricato. MagiskSU e MagiskHide rimarranno abilitati</string>
<string name="settings_magiskhide_summary">Nasconde Magisk da numerose rilevazioni</string>
<string name="settings_hosts_title">Host systemless</string>
<string name="settings_hosts_summary">Supporto a host systemless per le app che bloccano le pubblicità</string>
<string name="settings_hosts_toast">Aggiunto modulo per host systemless</string>
<string name="settings_app_name">Inserisci il nome desiderato per l\'app</string>
<string name="settings_app_name_hint">Nuovo nome</string>
<string name="settings_app_name_helper">L\'app sarà ricreata con questo nome</string>
<string name="settings_app_name_error">Formato non valido</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>
<string name="settings_su_request_15">15 secondi</string>
<string name="settings_su_request_20">20 secondi</string>
<string name="settings_su_request_30">30 secondi</string>
<string name="settings_su_request_45">45 secondi</string>
<string name="settings_su_request_60">60 secondi</string>
<string name="superuser_access">Accesso Superuser</string>
<string name="auto_response">Accesso predefinito</string>
<string name="request_timeout">Timeout richiesta</string>
<string name="superuser_notification">Notifica Superuser</string>
<string name="request_timeout_summary">%1$d secondi</string>
<string name="settings_su_reauth_title">Riautentica dopo aggiornamento</string>
<string name="settings_su_reauth_summary">Riautentica i permessi Superuser dopo un aggiornamento dell\'app</string>
<string name="settings_su_fingerprint_title">Abilita autenticazione impronta</string>
<string name="settings_su_fingerprint_summary">Utilizza il sensore di impronte per accettare le richieste Superuser</string>
<string name="auth_fingerprint">Conferma impronta</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>
<string name="settings_su_request_15">15 secondi</string>
<string name="settings_su_request_20">20 secondi</string>
<string name="settings_su_request_30">30 secondi</string>
<string name="settings_su_request_45">45 secondi</string>
<string name="settings_su_request_60">60 secondi</string>
<string name="superuser_access">Accesso Superuser</string>
<string name="auto_response">Accesso predefinito</string>
<string name="request_timeout">Timeout richiesta</string>
<string name="superuser_notification">Notifica Superuser</string>
<string name="request_timeout_summary">%1$d secondi</string>
<string name="settings_su_reauth_title">Riautentica dopo aggiornamento</string>
<string name="settings_su_reauth_summary">Riautentica i permessi Superuser dopo un aggiornamento dell\'app</string>
<string name="settings_su_fingerprint_title">Abilita autenticazione impronta</string>
<string name="settings_su_fingerprint_summary">Utilizza il sensore di impronte per accettare le richieste Superuser</string>
<string name="auth_fingerprint">Conferma impronta</string>
<string name="multiuser_mode">Modalità multiutente</string>
<string name="settings_owner_only">Solo proprietario del dispositivo</string>
<string name="settings_owner_manage">Gestito dal proprietario utente</string>
<string name="settings_user_independent">Idipendente dall\'utente</string>
<string name="owner_only_summary">Solo il proprietario ha i permessi di root.</string>
<string name="owner_manage_summary">Solo il proprietario può gestire accesso root e ricevere richieste.</string>
<string name="user_indepenent_summary">Ogni utente ha le sue regole di root indpendenti.</string>
<string name="multiuser_mode">Modalità multiutente</string>
<string name="settings_owner_only">Solo proprietario del dispositivo</string>
<string name="settings_owner_manage">Gestito dal proprietario utente</string>
<string name="settings_user_independent">Idipendente dall\'utente</string>
<string name="owner_only_summary">Solo il proprietario ha i permessi di root</string>
<string name="owner_manage_summary">Solo il proprietario può gestire accesso root e ricevere richieste</string>
<string name="user_indepenent_summary">Ogni utente ha le sue regole di root indpendenti</string>
<string name="mount_namespace_mode">Modalità mount namespace</string>
<string name="settings_ns_global">Namespace globale</string>
<string name="settings_ns_requester">Namespace ereditato</string>
<string name="settings_ns_isolate">Namespace isolato</string>
<string name="global_summary">Tutte le sessioni di root erediteranno il namespace globale.</string>
<string name="requester_summary">Le sessioni di root erediteranno il namespace del loro richiedente.</string>
<string name="isolate_summary">Ogni sessione di root avrà il suo namespace isolato.</string>
<string name="android_o_not_support">Non è supportato da Android 8.0+.</string>
<string name="disable_fingerprint">Non è presente alcuna impronta o il dispositivo non è supportato.</string>
<string name="settings_download_path_error">Errore durante la creazione della cartella. Deve essere accessibile dalla radice della memoria di archiviazione e non essere un file.</string>
<string name="mount_namespace_mode">Modalità mount namespace</string>
<string name="settings_ns_global">Namespace globale</string>
<string name="settings_ns_requester">Namespace ereditato</string>
<string name="settings_ns_isolate">Namespace isolato</string>
<string name="global_summary">Tutte le sessioni di root erediteranno il namespace globale</string>
<string name="requester_summary">Le sessioni di root erediteranno il namespace del loro richiedente</string>
<string name="isolate_summary">Ogni sessione di root avrà il suo namespace isolato</string>
<string name="disable_fingerprint">Non è presente alcuna impronta o il dispositivo non è supportato</string>
<string name="settings_download_path_error">Errore durante la creazione della cartella. Deve essere accessibile dalla radice della memoria di archiviazione e non essere un file.</string>
<!--Superuser-->
<string name="su_request_title">Richiesta Superuser</string>
<!--Superuser-->
<string name="su_request_title">Richiesta Superuser</string>
<string name="deny">Nega</string>
<string name="prompt">Chiedi</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>
<string name="once">Una volta</string>
<string name="tenmin">10 minuti</string>
<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="no_apps_found">Nessuna app trovata</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">Registro eventi abilitato per %1$s</string>
<string name="su_snack_log_off">Registro eventi non abilitato per %1$s</string>
<string name="prompt">Chiedi</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>
<string name="once">Una volta</string>
<string name="tenmin">10 minuti</string>
<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="no_apps_found">Nessuna app trovata</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">Registro eventi abilitato per %1$s</string>
<string name="su_snack_log_off">Registro eventi non abilitato per %1$s</string>
<string name="su_revoke_title">Vuoi 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>
<string name="auth_fail">Autenticatione fallita</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>
<string name="auth_fail">Autenticatione fallita</string>
<!--Superuser logs-->
<string name="pid">PID: %1$d</string>
<string name="target_uid">UID destinazione: %1$d</string>
<string name="command">Comando: %1$s</string>
<!--Superuser logs-->
<string name="pid">PID: %1$d</string>
<string name="target_uid">UID destinazione: %1$d</string>
<string name="command">Comando: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">Mostra app di sistema</string>
<!-- MagiskHide -->
<string name="show_system_app">Mostra app di sistema</string>
</resources>

View File

@@ -72,7 +72,6 @@
<string name="manager_update_title">Magisk Managerの更新があります</string>
<!--Toasts, Dialogs-->
<string name="close">閉じる</string>
<string name="repo_install_title">%1$s をインストール</string>
<string name="repo_install_msg">%1$s をインストールしますか?</string>
<string name="download">ダウンロード</string>
@@ -169,7 +168,6 @@
<string name="global_summary">すべてのrootセッションがグローバル名前空間を使用します</string>
<string name="requester_summary">rootセッションはリクエスト者の名前空間を継承します</string>
<string name="isolate_summary">rootセッション毎に分離された名前空間を使用します</string>
<string name="android_o_not_support">Android 8.0以降では対応していません</string>
<string name="disable_fingerprint">指紋が登録されていないか、お使いの端末でサポートされていません。</string>
<!--Superuser-->

View File

@@ -83,7 +83,6 @@
<string name="patch_file_msg">원시 이미지 (*.img) 또는 오딘 tar 파일 (*.tar) 선택</string>
<!--Toasts, Dialogs-->
<string name="close">닫기</string>
<string name="repo_install_title">%1$s 설치</string>
<string name="repo_install_msg">정말 %1$s을(를) 설치하시겠습니까?</string>
<string name="download">다운로드</string>
@@ -176,7 +175,6 @@
<string name="global_summary">모든 루트 세션이 전역 마운트 이름공간을 사용합니다.</string>
<string name="requester_summary">루트 세션은 요청자의 이름공간을 상속합니다.</string>
<string name="isolate_summary">각각의 루트 세션은 자신만의 독립된 이름공간을 사용합니다.</string>
<string name="android_o_not_support">안드로이드 8.0 이상 버전에서 사용할 수 없습니다.</string>
<string name="disable_fingerprint">지문이 등록되지 않았거나 기기가 지문 인식을 지원하지 않습니다.</string>
<!--Superuser-->

View File

@@ -61,7 +61,6 @@
<string name="app_changelog">Pakeitimų sąrašas</string>
<!--Toasts, Dialogs-->
<string name="close">Uždaryti</string>
<string name="repo_install_title">Instaliuoti %1$s</string>
<string name="repo_install_msg">Ar jūs norite instaliuoti %1$s?</string>
<string name="download">Atsisiųsti</string>
@@ -156,7 +155,6 @@
<string name="global_summary">Visos root sesijos naudoja globalią vardų sritį</string>
<string name="requester_summary">Root sesijos paveldi jos išprašytojo/s vardų sritį</string>
<string name="isolate_summary">Kiekviena root sesija turi savo izoliuotą vardų sritį</string>
<string name="android_o_not_support">Įrenginiai su Android 8.0+ nepalaiko šio nustatymo</string>
<string name="disable_fingerprint">Jūsų įrenginyje nebuvo surasta pirštų antspaudų arba jūsų įrenginys neturi pirštų antspaudų skaitytuvo</string>
<!--Superuser-->

View File

@@ -84,7 +84,6 @@
<string name="reboot_delay_toast">Рестартирање за 5 секунди…</string>
<!--Toasts, Dialogs-->
<string name="close">Затвори</string>
<string name="repo_install_title">Инсталирај %1$s</string>
<string name="repo_install_msg">Дали сакате да го инсталирате %1$s сега?</string>
<string name="download">Преземи</string>
@@ -175,7 +174,6 @@
<string name="global_summary">Сите рут сесии го користат глобалниот именски простор.</string>
<string name="requester_summary">Рут сесиите ќе го наследат именскиот простор на нивниот барател.</string>
<string name="isolate_summary">Секоја рут сесија ќе има свој изолиран именски простор.</string>
<string name="android_o_not_support">Не е поддржано на Android 8.0+.</string>
<string name="disable_fingerprint">Нема регистрирано отпечатоци од прсти или уредот не ја поддржува оваа функција.</string>
<!--Superuser-->

View File

@@ -69,7 +69,6 @@
<string name="manager_update_title">En Magisk Manager-oppdatering er tilgjengelig!</string>
<!--Toasts, Dialogs-->
<string name="close">Lukk</string>
<string name="repo_install_title">Installer %1$s</string>
<string name="repo_install_msg">Vil du installere %1$s nå?</string>
<string name="download">Last ned</string>
@@ -166,7 +165,6 @@
<string name="global_summary">Alle root-økter benytter det altdekkende monteringsnavnefeltet.</string>
<string name="requester_summary">Root-økter vil arve forespørrerens navnefelt.</string>
<string name="isolate_summary">Hver root-økt vil ha sitt eget isolerte navnefelt.</string>
<string name="android_o_not_support">Støtter ikke Android ≥8.0.</string>
<string name="disable_fingerprint">Ingen fingeravtrykk ble gitt, eller så støttes det ikke av enheten.</string>
<!--Superuser-->

View File

@@ -62,7 +62,6 @@
<string name="app_changelog">App\'s changelog</string>
<!--Toasts, Dialogs-->
<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">Downloaden</string>
@@ -151,7 +150,6 @@
<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>
<string name="android_o_not_support">Ondersteunt geen Android 8.0+</string>
<string name="disable_fingerprint">Geen vingerafdrukken ingesteld, of geen apparaatondersteuning</string>
<!--Superuser-->

View File

@@ -9,12 +9,12 @@
<string name="install">Instaluj</string>
<string name="unsupport_magisk_title">Nieobsługiwana Wersja Magisk</string>
<string name="unsupport_magisk_message">Ta wersja Magisk Managera nie obsługuje wersji Magisk niższej niż v18.0.\n\nMożesz albo ręcznie zaktualizować Magisk lub obniżyć w aplikacji do starszej wersji.</string>
<!--Status Fragment-->
<!--Status Fragment-->
<string name="magisk_version_error">Magisk nie jest zainstalowany.</string>
<string name="checking_for_updates">Sprawdzanie aktualizacji…</string>
<string name="invalid_update_channel">Nieprawidłowy Kanał Aktualizacji</string>
<string name="safetyNet_check_text">Dotknij aby sprawdzić SafetyNet</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">SafetyNet Poprawny</string>
<string name="safetyNet_api_error">SafetyNet API Błędny</string>
@@ -28,11 +28,11 @@
<string name="latest_version">Ostatnia: %1$s</string>
<string name="uninstall">Odinstaluj</string>
<string name="uninstall_magisk_title">Odinstaluj Magisk</string>
<string name="uninstall_magisk_msg">Wszystkie moduły będą wyłączone/usunięte. Root zostanie usunięty i przywrócone szyfrowanie danych, jeśli nie są te dane obecnie szyfrowane</string>
<string name="uninstall_magisk_msg">Wszystkie moduły będą wyłączone/usunięte. Root zostanie usunięty i przywrócone szyfrowanie danych, jeśli nie są te dane obecnie szyfrowane</string>
<string name="update">Pobierz</string>
<string name="core_only_enabled">(Włączony tylko tryb jądra)</string>
<!--Module Fragment-->
<!--Module Fragment-->
<string name="no_info_provided">(Nie umieszczono informacji)</string>
<string name="no_modules_found">Nie znaleziono modułów.</string>
<string name="update_file_created">Moduł zostanie zaktualizowany przy następnym restarcie.</string>
@@ -45,12 +45,12 @@
<string name="reboot_bootloader">Restart do Bootloadera</string>
<string name="reboot_download">Restart do Download</string>
<string name="reboot_edl">Restart do EDL</string>
<!--Repo Fragment-->
<!--Repo Fragment-->
<string name="update_available">Aktualizacja dostępna</string>
<string name="installed">Zainstalowany</string>
<string name="not_installed">Nie zainstalowany</string>
<string name="updated_on">Zaktualizowano: %1$s</string>
<string name="updated_on">Zaktualizowano: %1$s</string>
<string name="sorting_order">Kolejność Sortowania</string>
<string name="sort_by_name">Sortuj po nazwie</string>
<string name="sort_by_update">Sortuj po ostatniej aktualizacji</string>
@@ -71,23 +71,22 @@
<string name="download_file_error">Błąd pobierania pliku</string>
<string name="download_open_parent">Pokaż w folderze nadrzędnym</string>
<string name="download_open_self">Pokaż pliki</string>
<string name="magisk_update_title">Nowa Wersja Magisk Dostępna!</string>
<string name="magisk_update_title">Nowa Wersja Magisk Dostępna!</string>
<string name="manager_update_title">Nowa Wersja Magisk Manager Dostępna!</string>
<!-- Installation -->
<string name="manager_download_install">Naciśnij aby pobrać i zainstalować</string>
<string name="download_zip_only">Pobierz Tylko Zip</string>
<!-- Installation -->
<string name="manager_download_install">Naciśnij aby pobrać i zainstalować</string>
<string name="download_zip_only">Pobierz Tylko Zip</string>
<string name="direct_install">Bezpośrednia instalacja (Zalecane)</string>
<string name="install_inactive_slot">Zainstaluj do Nieaktywnego Slotu (po OTA)</string>
<string name="install_inactive_slot">Zainstaluj do Nieaktywnego Slotu (po OTA)</string>
<string name="install_inactive_slot_msg">Urządzenie będzie MUSIAŁO uruchomić się z bieżącego nieaktywnego slotu po restarcie! /\nUżyj tylko tej opcji po zakończeniu OTA.\nKontynuować?</string>
<string name="select_method">Wybierz Metodę</string>
<string name="setup_title">Dodatkowa konfiguracja</string>
<string name="select_method">Wybierz Metodę</string>
<string name="setup_title">Dodatkowa konfiguracja</string>
<string name="select_patch_file">Wybierz i Wgraj Plik</string>
<string name="patch_file_msg">Wybierz obraz raw (*.img) lub plik ODIN tar (*.tar)</string>
<string name="reboot_delay_toast">Ponowne uruchomienie za 5 sekund…</string>
<!--Toasts, Dialogs-->
<string name="close">Zamknij</string>
<!--Toasts, Dialogs-->
<string name="repo_install_title">Instaluj %1$s</string>
<string name="repo_install_msg">Czy chcesz zainstalować %1$s ?</string>
<string name="download">Pobierz</string>
@@ -100,14 +99,14 @@
<string name="dtbo_patched_reboot">Magisk Manager wgrał dtbo.img. Uruchom ponownie</string>
<string name="flashing">Flashowanie</string>
<string name="done">Gotowe!</string>
<string name="failure">Błąd</string>
<string name="hide_manager_title">Ukryj Magisk Manager…</string>
<string name="failure">Błąd</string>
<string name="hide_manager_title">Ukryj Magisk Manager…</string>
<string name="hide_manager_fail_toast">Błąd Ukrycia Magisk Managera.</string>
<string name="open_link_failed_toast">Nie znaleziono aplikacji pod linkiem.</string>
<string name="open_link_failed_toast">Nie znaleziono aplikacji pod linkiem.</string>
<string name="warning">Uwaga</string>
<string name="complete_uninstall">Odinstalowywanie Zakończone</string>
<string name="restore_img">Przywróć Obraz</string>
<string name="restore_img_msg">Przywracanie…</string>
<string name="restore_img_msg">Przywracanie…</string>
<string name="restore_done">Przywracanie zakończone!</string>
<string name="restore_fail">Stock backup nie istnieje!</string>
<string name="proprietary_title">Pobierz Kod</string>
@@ -123,7 +122,7 @@
<string name="settings_dark_theme_summary">Włącz ciemny motyw</string>
<string name="settings_download_path_title">Pobierz dodatek</string>
<string name="settings_download_path_message">Pliki zostaną zapisane w %1$s</string>
<string name="settings_clear_cache_title">Wyczyść Pamięć Repozytorium</string>
<string name="settings_clear_cache_title">Wyczyść Pamięć Repozytorium</string>
<string name="settings_clear_cache_summary">Wymusza na aplikacji odświeżenie repozytorium online.</string>
<string name="settings_hide_manager_title">Ukryj Magisk Manager</string>
<string name="settings_hide_manager_summary">Przepakowanie Magisk Manager z losową nazwą pakietu</string>
@@ -145,7 +144,7 @@
<string name="settings_hosts_title">Włącz systemless hosts</string>
<string name="settings_hosts_summary">Wsparcie systemless dla aplikacji Adblock</string>
<string name="settings_hosts_toast">Dodano moduł systemless hosts</string>
<string name="settings_su_app_adb">Aplikacje i ADB</string>
<string name="settings_su_app">Tylko Aplikacje</string>
<string name="settings_su_adb">Tylko ADB</string>
@@ -166,8 +165,8 @@
<string name="settings_su_fingerprint_title">Włącz Uwierzytelnienie Odciskiem Palca</string>
<string name="settings_su_fingerprint_summary">Użyj skanera linii papilarnych, aby zezwolić na żądania supersu</string>
<string name="auth_fingerprint">Uwierzytelnianie Odciskiem Palca</string>
<string name="multiuser_mode">Tryb Multiusera</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>
@@ -182,11 +181,10 @@
<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="android_o_not_support">Brak wsparcia dla Androida 8.0+</string>
<string name="disable_fingerprint">Nie ustawiono żadnych odcisków palców lub brak obsługi urządzenia</string>
<string name="settings_download_path_error">Błąd podczas tworzenia folderu. Musi być dostępny z głównego katalogu pamięci i nie może być plikiem.</string>
<!--Superuser-->
<!--Superuser-->
<string name="su_request_title">Prośba o dostęp Superusera</string>
<string name="deny">Odmów</string>
<string name="prompt">Zapytaj</string>
@@ -220,5 +218,5 @@
<!-- MagiskHide -->
<string name="show_system_app">Pokaż aplikacje systemowe</string>
</resources>

View File

@@ -63,7 +63,6 @@
<string name="app_changelog">Registro de mudanças</string>
<!--Toasts, Dialogs-->
<string name="close">Fechar</string>
<string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">Instalar %1$s agora?</string>
<string name="download">Baixar</string>
@@ -153,7 +152,6 @@
<string name="global_summary">Todas as sessões root usam montagem de espaço de nome global</string>
<string name="requester_summary">As sessões root herdarão espaço de nome de seu solicitante</string>
<string name="isolate_summary">Cada sessão root terá seu próprio espaço de nome isolado</string>
<string name="android_o_not_support">Não suporta Android 8.0+</string>
<string name="disable_fingerprint">Nenhuma impressão digital foi definida ou o dispostivo não tem suporte</string>
<!--Superuser-->

View File

@@ -53,7 +53,6 @@
<string name="app_changelog">Lista de alterações da aplicação</string>
<!--Toasts, Dialogs-->
<string name="close">Fechar</string>
<string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">Deseja instalar%1$s agora?</string>
<string name="download">Transferir</string>

View File

@@ -87,7 +87,6 @@
<string name="reboot_delay_toast">Repornire în 5 secunde…</string>
<!--Toasts, Dialogs-->
<string name="close">Închide</string>
<string name="repo_install_title">Instalează %1$s</string>
<string name="repo_install_msg">Vrei să instalezi acum %1$s?</string>
<string name="download">Descarcă</string>
@@ -182,7 +181,6 @@
<string name="global_summary">Toate sesiunile de root folosesc 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="android_o_not_support">Nu suportă Android 8.0+.</string>
<string name="disable_fingerprint">Nu au fost setate amprente sau scannerul de amprentă lipsește.</string>
<string name="settings_download_path_error">Eroare la crearea dosarului. Acesta trebuie să fie accesibil din directorul rădăcină al stocării și nu trebuie să fie un fișier.</string>

View File

@@ -18,18 +18,18 @@
<string name="checking_safetyNet_status">Проверка статуса SafetyNet…</string>
<string name="safetyNet_check_success">Результат проверки SafetyNet</string>
<string name="safetyNet_api_error">Ошибка SafetyNet API</string>
<string name="safetyNet_res_invalid">Некорректный ответ.</string>
<string name="safetyNet_res_invalid">Некорректный ответ</string>
<string name="magisk_up_to_date">Magisk актуален</string>
<string name="manager_up_to_date">Magisk Manager актуален</string>
<string name="advanced_settings_title">Расширенные опции</string>
<string name="keep_force_encryption">Сохранить принудительное шифрование</string>
<string name="keep_dm_verity">Сохранить AVB 2.0/dm-verity</string>
<string name="recovery_mode">Режим Recovery</string>
<string name="current_installed">Установлена: %1$s</string>
<string name="latest_version">Последняя: %1$s</string>
<string name="keep_force_encryption">Не отключать шифрование /data</string>
<string name="keep_dm_verity">Не отключать AVB 2.0/dm-verity</string>
<string name="recovery_mode">Режим установки в recovery</string>
<string name="current_installed">Установлен: %1$s</string>
<string name="latest_version">Последний: %1$s</string>
<string name="uninstall">Удаление</string>
<string name="uninstall_magisk_title">Удаление Magisk</string>
<string name="uninstall_magisk_msg">Все модули будут отключены/удалены. Root-права будут удалены. Шифрование будет активировано.</string>
<string name="uninstall_magisk_msg">Все модули будут отключены/удалены!\nRoot-права будут удалены!\nШифрование будет активировано!</string>
<string name="update">Обновить</string>
<string name="core_only_enabled">(Активирован режим Magisk Core)</string>
@@ -76,24 +76,23 @@
<string name="manager_update_title">Доступно обновление Magisk Manager!</string>
<!-- Installation -->
<string name="manager_download_install">Нажмите, чтобы загрузить и установить.</string>
<string name="download_zip_only">Загрузка установочного ZIP</string>
<string name="manager_download_install">Нажмите, чтобы загрузить и установить</string>
<string name="download_zip_only">Только загрузка ZIP</string>
<string name="direct_install">Прямая установка (Рекомендуется)</string>
<string name="install_inactive_slot">Установка в неактивный слот (После OTA)</string>
<string name="install_inactive_slot_msg">Ваше устройство будет принудительно перезагружено в неактивный слот!\nИспользуйте эту опцию только при установке OTA.\nПродолжить?</string>
<string name="install_inactive_slot">Установка во второй слот (OTA)</string>
<string name="install_inactive_slot_msg">Ваше устройство будет принудительно перезагружено в неактивный (противоположный) слот!\nИспользуйте эту опцию только при интеграции после OTA.\nПродолжить?</string>
<string name="select_method">Выбор способа</string>
<string name="setup_title">Дополнительная установка</string>
<string name="select_patch_file">Выбрать и пропатчить файл</string>
<string name="select_patch_file">Вручную пропатчить образ</string>
<string name="patch_file_msg">Выберите файл образа (*.img) или архив ODIN (*.tar)</string>
<string name="reboot_delay_toast">Перезагрузка через 5 секунд…</string>
<!--Toasts, Dialogs-->
<string name="close">Закрыть</string>
<string name="repo_install_title">Установка %1$s</string>
<string name="repo_install_msg">Установить %1$s ?</string>
<string name="download">Скачать</string>
<string name="reboot">Перезагрузка</string>
<string name="settings_reboot_toast">Для применения настроек перезагрузите устройство.</string>
<string name="settings_reboot_toast">Для применения настроек перезагрузите устройство</string>
<string name="release_notes">О версии</string>
<string name="repo_cache_cleared">Кэш репозитория очищен</string>
@@ -102,9 +101,9 @@
<string name="flashing">Прошивка…</string>
<string name="done">Завершено!</string>
<string name="failure">Ошибка</string>
<string name="hide_manager_title">Маскировка Magisk Manager…</string>
<string name="hide_manager_title">Скрытие Magisk Manager…</string>
<string name="hide_manager_fail_toast">Не удалось пересобрать Magisk Manager</string>
<string name="open_link_failed_toast">Не найдено приложений для открытия ссылки.</string>
<string name="open_link_failed_toast">Не найдено приложений для открытия ссылки</string>
<string name="warning">Предупреждение</string>
<string name="complete_uninstall">Полное удаление</string>
<string name="restore_img">Восстановить разделы</string>
@@ -112,8 +111,8 @@
<string name="restore_done">Восстановление завершено!</string>
<string name="restore_fail">Резервная копия отсутствует!</string>
<string name="proprietary_title">Загрузка SafetyNet</string>
<string name="proprietary_notice">Magisk Manager — свободно распространяемый продукт, он не содержит собственный код SafetyNet API от Google.\n\nРазрешить Magisk Manager загрузить расширение для проверки SafetyNet? (содержит GoogleApiClient)</string>
<string name="setup_fail">Ошибка установки.</string>
<string name="proprietary_notice">Magisk Manager — проект с открытым исходным кодом и не содержит проприетарный код SafetyNet API от Google.\n\nРазрешить Magisk Manager загрузить расширение для проверки SafetyNet? (содержит GoogleApiClient)</string>
<string name="setup_fail">Ошибка установки</string>
<string name="env_fix_title">Требуется дополнительная установка</string>
<string name="env_fix_msg">Вашему устройству требуется дополнительная установка Magisk для корректной работы. Будет загружен установочный ZIP Magisk, продолжить?</string>
<string name="setup_msg">Настройка рабочей среды…</string>
@@ -121,32 +120,36 @@
<!--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_summary">Включить тёмное оформление</string>
<string name="settings_download_path_title">Папка загрузки</string>
<string name="settings_download_path_message">Файлы будут загружаться в %1$s</string>
<string name="settings_clear_cache_title">Очистка кэша репозитория</string>
<string name="settings_clear_cache_summary">Очистить кэш репозитория. Будет загружен заново.</string>
<string name="settings_hide_manager_title">Маскировка Magisk Manager</string>
<string name="settings_hide_manager_summary">Пересобрать Magisk Manager со случайным именем пакета.</string>
<string name="settings_clear_cache_summary">Очистить кэш репозитория. Будет загружен заново</string>
<string name="settings_hide_manager_title">Скрытие Magisk Manager</string>
<string name="settings_hide_manager_summary">Пересобрать Magisk Manager со случайным названием и именем пакета</string>
<string name="settings_restore_manager_title">Восстановление Magisk Manager</string>
<string name="settings_restore_manager_summary">Восстановить Magisk Manager с исходным именем пакета.</string>
<string name="settings_restore_manager_summary">Восстановить Magisk Manager с исходным названием и именем пакета</string>
<string name="language">Язык</string>
<string name="system_default">По умолчанию (Системный)</string>
<string name="settings_update">Настройки обновлений</string>
<string name="settings_check_update_title">Проверка обновлений</string>
<string name="settings_check_update_summary">Периодически проверять наличие обновлений в фоновом режиме.</string>
<string name="settings_check_update_summary">Периодически проверять наличие обновлений в фоновом режиме</string>
<string name="settings_update_channel_title">Источник обновлений</string>
<string name="settings_update_stable">Стабильный канал</string>
<string name="settings_update_beta">Beta канал</string>
<string name="settings_update_custom">Сторонний канал</string>
<string name="settings_update_custom_msg">Укажите ссылку</string>
<string name="settings_core_only_title">Magisk Core</string>
<string name="settings_core_only_summary">Активировать только основные возможности. Модули не будут загружены. MagiskSU и Magisk Hide останутся активными.</string>
<string name="settings_magiskhide_summary">Скрыть Magisk от различных обнаружений.</string>
<string name="settings_core_only_summary">Активировать только основные возможности. Модули не будут загружены. MagiskSU и Magisk Hide останутся активными</string>
<string name="settings_magiskhide_summary">Скрывать Magisk от различных обнаружений</string>
<string name="settings_hosts_title">Внесистемные хосты</string>
<string name="settings_hosts_summary">Поддержка внесистемных хостов для приложений, блокирующих рекламу.</string>
<string name="settings_hosts_summary">Поддержка внесистемных хостов для приложений, блокирующих рекламу</string>
<string name="settings_hosts_toast">Добавлен модуль внесистемных хостов</string>
<string name="settings_app_name">Укажите имя приложения</string>
<string name="settings_app_name_hint">Новое имя</string>
<string name="settings_app_name_helper">Приложение будет пересобрано с этим именем</string>
<string name="settings_app_name_error">Некорректный формат</string>
<string name="settings_su_app_adb">Приложения и ADB</string>
<string name="settings_su_app">Только приложения</string>
<string name="settings_su_adb">Только ADB</string>
@@ -163,18 +166,18 @@
<string name="superuser_notification">Уведомления суперпользователя</string>
<string name="request_timeout_summary">%1$d секунд</string>
<string name="settings_su_reauth_title">Повторная аутентификация</string>
<string name="settings_su_reauth_summary">Повторный запрос прав суперпользователя после обновления приложений.</string>
<string name="settings_su_reauth_summary">Повторный запрос прав суперпользователя после обновления приложений</string>
<string name="settings_su_fingerprint_title">Биометрическая аутентификация</string>
<string name="settings_su_fingerprint_summary">Использовать сканер отпечатков пальцев для запросов прав суперпользователя.</string>
<string name="auth_fingerprint">Аутентифицировать отпечаток пальца</string>
<string name="settings_su_fingerprint_summary">Использовать сканер отпечатков пальцев для запросов прав суперпользователя</string>
<string name="auth_fingerprint">Подтвердите отпечаток пальца</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="owner_only_summary">Только владелец имеет Root-доступ</string>
<string name="owner_manage_summary">Только владелец управляет Root-доступом и обрабатывает запросы</string>
<string name="user_indepenent_summary">Каждый пользователь имеет свои собственные правила Root-доступа</string>
<string name="mount_namespace_mode">Настройка пространств имён</string>
<string name="settings_ns_global">Общее пространство имён</string>
@@ -183,18 +186,17 @@
<string name="global_summary">Сессии суперпользователя используют общее пространство имён</string>
<string name="requester_summary">Сессии суперпользователя наследуют пространство имён запрашивающего</string>
<string name="isolate_summary">Сессии суперпользователя используют изолированные пространства имён</string>
<string name="android_o_not_support">Не поддерживается в Android 8.0+</string>
<string name="disable_fingerprint">Не поддерживается устройством или не заданы отпечатки</string>
<string name="settings_download_path_error">Ошибка создания папки. Она должна быть доступна из корневой директории хранилища и не должна быть файлом.</string>
<!--Superuser-->
<string name="su_request_title">Запрос прав суперпользователя</string>
<string name="deny">Отказать</string>
<string name="deny">Запретить</string>
<string name="prompt">Запрос</string>
<string name="grant">Предоставить</string>
<string name="su_warning">Предоставить полный доступ к устройству.\nЕсли не уверены - отклоните данное действие!</string>
<string name="grant">Разрешить</string>
<string name="su_warning">Разрешить полный доступ к устройству?\nЕсли не уверены - отклоните данное действие!</string>
<string name="forever">Навсегда</string>
<string name="once">Сейчас</string>
<string name="once">Единожды</string>
<string name="tenmin">10 мин.</string>
<string name="twentymin">20 мин.</string>
<string name="thirtymin">30 мин.</string>
@@ -220,6 +222,6 @@
<string name="command">Команда: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">Показать системные приложения</string>
<string name="show_system_app">Системные приложения</string>
</resources>

View File

@@ -72,7 +72,6 @@
<string name="manager_update_title">Je dostupná aktualizácia Magisk Manager!</string>
<!--Toasts, Dialogs-->
<string name="close">Zavrieť</string>
<string name="repo_install_title">Nainštalovať %1$s</string>
<string name="repo_install_msg">Chcete teraz nainštalovať %1$s?</string>
<string name="download">Stiahnuť</string>
@@ -167,7 +166,6 @@
<string name="global_summary">Všetky relácie root použijú globálne mount namespace</string>
<string name="requester_summary">Relácie root zdedia namespace od požadovateľa</string>
<string name="isolate_summary">Každá relácia root bude mať vlastný izolovaný namespace</string>
<string name="android_o_not_support">Nepodporuje Android 8.0+</string>
<string name="disable_fingerprint">Neboli odoslané žiadne odtlačky prsta alebo ich zariadenie nepodporuje</string>
<!--Superuser-->

View File

@@ -55,7 +55,6 @@
<string name="app_changelog">Дневник промена апликације</string>
<!--Toasts, Dialogs-->
<string name="close">Затвори</string>
<string name="repo_install_title">Инсталирај %1$s</string>
<string name="repo_install_msg">Да ли желите да инсталирате %1$s?</string>
<string name="download">Преузми</string>

View File

@@ -53,7 +53,6 @@
<string name="app_changelog">Ändringslogg</string>
<!--Toasts, Dialogs-->
<string name="close">Stäng</string>
<string name="repo_install_title">Installera %1$s</string>
<string name="repo_install_msg">Vill du installera %1$s ?</string>
<string name="download">Ladda ner</string>
@@ -62,7 +61,7 @@
<string name="settings_reboot_toast">Starta om för att tillämpa inställningar</string>
<string name="release_notes">Release notes</string>
<string name="repo_cache_cleared">Repo-cache rensad</string>
<string name="manager_update_title">En uppdatering av Magisk maneger finns tillgänglig!</string>
<string name="manager_update_title">En uppdatering av Magisk Manager finns tillgänglig!</string>
<string name="manager_download_install">Tryck för att ladda ner och installera</string>
<string name="update_channel">Magiska uppdateringar</string>
<string name="download_file_error">Fel vid nerladdning av fil</string>

View File

@@ -69,7 +69,6 @@
<string name="manager_update_title">มีการอัพเดต Magisk Manager!</string>
<!--Toasts, Dialogs-->
<string name="close">ปิด</string>
<string name="repo_install_title">ติดตั้ง %1$s</string>
<string name="repo_install_msg">ต้องการติดตั้ง %1$s ตอนนี้หรือไม่?</string>
<string name="download">ดาวน์โหลด</string>
@@ -166,7 +165,6 @@
<string name="global_summary">All root sessions use the global mount namespace.</string>
<string name="requester_summary">Root sessions will inherit their requester\'s namespace.</string>
<string name="isolate_summary">Each root session will have its own isolated namespace.</string>
<string name="android_o_not_support">ไม่รองรับ Android 8.0 ขึ้นไป</string>
<string name="disable_fingerprint">ไม่มีลายนิ้วมือหรืออุปกรณ์แสกน</string>
<!--Superuser-->

View File

@@ -88,7 +88,6 @@
<string name="reboot_delay_toast">5 saniye içinde yeniden başlatılacak...</string>
<!--Toasts, Dialogs-->
<string name="close">Kapat</string>
<string name="repo_install_title">%1$s yükle</string>
<string name="repo_install_msg">%1$s yüklensin mi?</string>
<string name="download">İndir</string>
@@ -147,6 +146,10 @@
<string name="settings_hosts_summary">Reklam engelleme uygulamaları için sistemsiz host desteği</string>
<string name="settings_hosts_toast">Sistemsiz host modülü eklendi</string>
<string name="settings_app_name">İstediğiniz uygulama adını yazın</string>
<string name="settings_app_name_hint">Yeni ad</string>
<string name="settings_app_name_helper">Uygulama bu ad ile yeniden paketlenecek</string>
<string name="settings_app_name_error">Geçersiz format</string>
<string name="settings_su_app_adb">Uygulamalar ve ADB</string>
<string name="settings_su_app">Sadece uygulamalar</string>
<string name="settings_su_adb">Sadece ADB</string>
@@ -183,9 +186,8 @@
<string name="global_summary">Tüm kök oturumları genel bağlama ad alanını kullanır</string>
<string name="requester_summary">Kök oturumları, istekte bulunanın ad alanını devralır</string>
<string name="isolate_summary">Her bir kök oturumunun kendi izole ad alanı olacaktır</string>
<string name="android_o_not_support">Android 8.0 ve üzerinde desteklenmiyor</string>
<string name="disable_fingerprint">Parmak izi ayarlanmadı veya cihaz desteği yok</string>
<string name="settings_download_path_error">Klasör oluşturma hatası. Depolama kök dizininden erişilebilir olmalı ve bir dosya olmamalıdır.</string>
<string name="settings_download_path_error">Klasör oluşturma hatası. Depolama kök dizininden erişilebilir olmalı ve bir dosya olmamalıdır.</string>
<!--Superuser-->
<string name="su_request_title">Yetkili Kullanıcı İsteği</string>

View File

@@ -88,7 +88,6 @@
<string name="reboot_delay_toast">Перезавантаження через 5 секунд…</string>
<!--Toasts, Dialogs-->
<string name="close">Закрити</string>
<string name="repo_install_title">Встановити %1$s</string>
<string name="repo_install_msg">Бажаєте встановити %1$s ?</string>
<string name="download">Завантажити</string>
@@ -106,8 +105,8 @@
<string name="hide_manager_fail_toast">Не вдалося приховати Magisk Manager.</string>
<string name="open_link_failed_toast">Не знайдено програм для відкриття посилання.</string>
<string name="warning">Попередження</string>
<string name="complete_uninstall">Видалення виконано</string>
<string name="restore_img">Відновити образи</string>
<string name="complete_uninstall">Повне видалення</string>
<string name="restore_img">Відновити розділи</string>
<string name="restore_img_msg">Відновлення…</string>
<string name="restore_done">Відновлення завершено!</string>
<string name="restore_fail">Немає резервної копії оригінального boot образу</string>
@@ -140,13 +139,17 @@
<string name="settings_update_beta">Бета реліз</string>
<string name="settings_update_custom">Власний</string>
<string name="settings_update_custom_msg">Вставте власний URL</string>
<string name="settings_core_only_title">Режим ядра Magisk</string>
<string name="settings_core_only_title">Режим Magisk Core</string>
<string name="settings_core_only_summary">Увімкнути тільки можливості ядра. MagiskSU i Magisk Hide залишуться увімкненими, проте ніякі модулі не будуть завантажені.</string>
<string name="settings_magiskhide_summary">Приховати Magisk від різних форм виявлень.</string>
<string name="settings_hosts_title">Позасистемні хости</string>
<string name="settings_hosts_summary">Підтримка позасистемних хостів для програм блокування реклами.</string>
<string name="settings_hosts_toast">Додано модуль позасистемних хостів</string>
<string name="settings_app_name">Введіть бажане ім\'я застосунку</string>
<string name="settings_app_name_hint">Нове ім\'я</string>
<string name="settings_app_name_helper">Застосунок буде перезібрано з цим ім\'ям</string>
<string name="settings_app_name_error">Неправильний формат</string>
<string name="settings_su_app_adb">Програми і ADB</string>
<string name="settings_su_app">Програми</string>
<string name="settings_su_adb">ADB</string>
@@ -183,7 +186,6 @@
<string name="global_summary">Всі сеанси Суперкористувача використовують глобальний простір імен.</string>
<string name="requester_summary">Сеанси Суперкористувача наслідують простір імен запитувача.</string>
<string name="isolate_summary">Кожнен сеанс Суперкористувача має власний ізольований простір імен.</string>
<string name="android_o_not_support">Не працює на Android 8.0+.</string>
<string name="disable_fingerprint">Немає відбитків пальця або пристрій не підтримується.</string>
<string name="settings_download_path_error">Помилка створення папки. Вона повинна бути доступна з кореневої директорії сховища і не повинна бути файлом.</string>

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