Compare commits

...

119 Commits

Author SHA1 Message Date
Hen Ry
fe8997efae Fix 2021-01-10 20:17:20 -08:00
Arbri çoçka
23455c722c fix in Values-sq 2021-01-10 20:16:57 -08:00
topjohnwu
5ce29c30d2 Fix sepolicy copying 2021-01-10 20:16:02 -08:00
topjohnwu
70d67728fd Add global toggle for ptrace monitor 2021-01-10 19:27:54 -08:00
topjohnwu
e546884b08 Remove isolated process handling in ptrace
Impossible to achieve only through ptrace
2021-01-10 17:18:42 -08:00
topjohnwu
b36e6d987d Reorganize MagiskHide code
Prepare for zygote injection hiding
2021-01-10 17:11:00 -08:00
topjohnwu
53c3dd5e8b Auto track JNI method hooks 2021-01-10 05:07:17 -08:00
topjohnwu
da723b207a Allow 3rd party code to load pre-specializing
Magisk's policy is to never allow 3rd party code to be loaded in the
zygote daemon process so we have 100% control over injection and hiding.
However, this makes it impossible for 3rd party modules to run anything
before process specialization, which includes the ability to modify the
arguments being sent to these original nativeForkAndXXX methods.

The trick here is to fork before calling the original nativeForkAndXXX
methods, and hook `fork` in libandroid_runtime.so to skip the next
invocation; basically, we're moving the responsibility of process
forking to our own hands.
2021-01-10 01:25:30 -08:00
topjohnwu
e050f77198 Don't hook SystemProperties#set
Doesn't seem necessary
2021-01-09 20:39:59 -08:00
topjohnwu
540b4b7ea9 Update pre/post hooks implementation 2021-01-09 17:41:25 -08:00
topjohnwu
bbef22daf7 More macro magic to automate more code 2021-01-09 04:28:26 -08:00
topjohnwu
9ed110c91b Add JNI hooks to critical methods 2021-01-08 05:25:44 -08:00
topjohnwu
a30d510eb1 Use xHook to hook functions in PLT 2021-01-08 00:53:24 -08:00
topjohnwu
ef98eaed8f Proper injection entry and unloading 2021-01-06 23:59:05 -08:00
topjohnwu
2a257f327c Sanitize /proc/PID/environ 2021-01-06 23:41:37 -08:00
topjohnwu
4060c2107c Add preliminary zygote code injection support
Prototyping the injection setup and a clean "self unloading" mechanism.
2021-01-06 22:21:17 -08:00
topjohnwu
cd23d27048 Fix remote_write implementation 2021-01-06 21:56:29 -08:00
topjohnwu
18b86e4fd2 Update Android.mk for test binary
Make Android Studio happy
2021-01-05 00:01:02 -08:00
topjohnwu
5f2e22a259 Support remote function call with ptrace
End up not used for anything, but keep it for good
2021-01-02 21:29:45 -08:00
topjohnwu
4e97b18977 Move libsystemproperties to external 2020-12-31 15:06:19 -08:00
topjohnwu
f9bde347bc Convert indentation to spaces
The tab war is lost
2020-12-30 22:11:24 -08:00
Billy Laws
947a7d6a2f Support rootwait cmdline parameter on legacy SAR
On devices where the primary storage is slow to probe it makes sense to
wait forever for the system partition to mount, this emulates the
kernel's behaviour when waiting for rootfs on SAR if the rootwait
parameter is supplied.

This issue was encountered with some SD cards on the Nintendo Switch.
2020-12-30 16:43:28 -08:00
Björn Engel
872ab2e99b Change translation for next
Nächste sounds a little bit strange.
2020-12-30 16:41:22 -08:00
kubalav
90b8813bb7 Fixed typo 2020-12-30 16:41:01 -08:00
Arbri çoçka
88d0f63294 Fix text in strings_sq 2020-12-30 16:40:47 -08:00
topjohnwu
79fa0d3a90 Hide selection improvements 2020-12-30 16:40:22 -08:00
topjohnwu
8e61080a4a Preparation for hiding isolated processes 2020-12-30 15:55:53 -08:00
topjohnwu
3f9a64417b Disable gradle daemon on Windows CI 2020-12-29 02:46:57 -08:00
topjohnwu
eb959379e8 Prevent resource ID clash 2020-12-29 02:39:47 -08:00
topjohnwu
41a644afb9 Open source stub APK loader
Close #3537
2020-12-29 01:44:02 -08:00
topjohnwu
6b42db943d Better bug report details 2020-12-28 17:03:20 -08:00
topjohnwu
1c325459eb Only run CI when it matters 2020-12-28 16:38:25 -08:00
John Wu
6d88d8ad95 Add issue templates 2020-12-28 16:26:10 -08:00
topjohnwu
246997f273 Update links 2020-12-28 15:58:53 -08:00
topjohnwu
b6144ae582 Add v21.2 release notes 2020-12-28 15:35:09 -08:00
Arbri çoçka
afe17c73b4 Update strings.xml
Fix same text in Values-sq
2020-12-28 15:29:27 -08:00
topjohnwu
b51b884fc7 Fix module installs in recovery
Close #3494
2020-12-28 00:25:01 -08:00
topjohnwu
d3e4b29e62 Update README.md 2020-12-27 22:36:03 -08:00
dark-basic
24059e7403 Update Stub-es version 2020-12-27 22:09:03 -08:00
dark-basic
107a2a6682 Update String-es 2020-12-27 22:08:34 -08:00
Arbri çoçka
56b4ab6672 Fix any text in strings sq 2020-12-27 22:07:44 -08:00
topjohnwu
4662454938 More attempts to fix gradle cache on Windows 2020-12-27 20:13:50 -08:00
topjohnwu
db4f78d463 Unblock signals before executing commands 2020-12-27 15:05:39 -08:00
topjohnwu
880de21596 Update Github Actions
Disable gradle daemon on Windows and always upload artifacts
2020-12-27 04:02:20 -08:00
topjohnwu
622dd84c9e Fix uninstaller zip 2020-12-26 22:45:05 -08:00
topjohnwu
f983bfc883 Embed keys into dex files 2020-12-26 21:33:30 -08:00
topjohnwu
45cdb3fdb0 Update dependencies 2020-12-26 17:05:12 -08:00
topjohnwu
9a707236b8 Move signing code into main app sources 2020-12-26 17:03:10 -08:00
topjohnwu
e9e6ad3bb0 Sign zips with apksigner 2020-12-26 16:04:41 -08:00
topjohnwu
ab78a81d15 Fix GitHub actions 2020-12-25 15:54:47 -08:00
John Wu
18340099b7 Add GitHub actions
Enable GitHub actions to run CI on all 3 platforms
2020-12-25 15:01:02 -08:00
topjohnwu
a013696a41 Default to config.prop in buildSrc 2020-12-25 13:03:25 -08:00
topjohnwu
8a2a6d9232 Make versionCode unconfigurable 2020-12-25 05:34:15 -08:00
topjohnwu
12aa6d86e4 Make config.prop optional 2020-12-24 04:46:31 -08:00
topjohnwu
7d08969d28 Fix strings 2020-12-23 01:33:46 -08:00
Fs00
dda4aa8488 Translate missing Italian strings 2020-12-22 23:33:20 -08:00
binarynoise
cdaef3d801 Update install.md
I wanted to share my experiences with rooting my S10e.
2020-12-22 23:32:53 -08:00
amninder singh
9159166128 Update strings.xml
Updating strings.xml
regarding #3566 adding punjabi translation
2020-12-22 23:32:01 -08:00
Arbri çoçka
dc0882e043 fixing some errors in sq strings 2020-12-22 23:31:40 -08:00
amninder singh
c811f015ef Added Punjabi Translation
- Written in Gurmukhi Script containing different foreign punctuations both inscript and Phonetic
2020-12-22 23:31:12 -08:00
nkh0472
d8f0b66fe1 Improve Correctness and Clarity of guides.md 2020-12-22 23:30:37 -08:00
Mohd Faraz
dc3d57deba utils_functions: Added a check for the system_root
now on addon while flashing recovery usign mount point /system_root by which this is causing a flashing error.
Let's first check and unmount /system_root if mounted

Signed-off-by: Mohd Faraz <androiabledroid@gmail.com>
2020-12-22 23:30:14 -08:00
topjohnwu
d089698475 Don't use root for logging getprop
Might contain sensitive info that shouldn't be shared
2020-12-19 23:09:36 -08:00
vvb2060
8ed2dd6687 Skip query for log files and patched boot file 2020-12-19 22:26:10 -08:00
vvb2060
50305ca1fe Support save manager log 2020-12-19 22:25:44 -08:00
vvb2060
3e91567636 Add a suffix to magisk_patched.img
prevent it from being used as input file
2020-12-19 21:53:16 -08:00
vvb2060
0b4dd63d36 Stub module always use release build 2020-12-19 21:02:05 -08:00
vvb2060
38d0f85deb Avoid unnecessary builds 2020-12-19 15:57:11 -08:00
vvb2060
c5b452f369 Get boot config properly
https://android.googlesource.com/platform/system/core/+/refs/tags/android-11.0.0_r16/fs_mgr/fs_mgr_boot_config.cpp#93
2020-12-19 15:55:33 -08:00
vvb2060
6ce9225f52 Check block dev ro status
magisk is shared object, use static busybox instead
2020-12-19 14:12:12 -08:00
vvb2060
13a8820603 Double check $DATA_DE 2020-12-19 14:08:32 -08:00
vvb2060
503997a09a Trim out \r 2020-12-19 14:08:06 -08:00
vvb2060
17efdff134 remove_system_su only on recovery mode
We may mount su to /system/bin/su
2020-12-19 13:59:08 -08:00
vvb2060
984f32f994 Move copy_sepolicy_rules to manager
We don’t need it when patch boot
2020-12-19 13:58:53 -08:00
topjohnwu
eee7f097e3 Make post-fs-data scripts block at most 35 secs 2020-12-17 16:54:53 -08:00
topjohnwu
086059ec30 Make sure boot stages are mutually exclusive 2020-12-15 03:40:37 -08:00
topjohnwu
7ff22c68c7 Only try to install APK when no manager is active 2020-12-09 02:15:16 -08:00
topjohnwu
1232113772 Update preference migration implementation
Only try to read preference through content provider when the app
is fresh install and a previous package ID is set. Also catch all
Exceptions to prevent crashing the app.

This prevents malicious settings injection and crashes when multiple
manager is installed.

Fix #3542
2020-12-09 02:07:58 -08:00
vvb2060
039d4936cb Disable superuser fragment properly 2020-12-09 01:16:30 -08:00
topjohnwu
784dd80965 Update MediaStoreUtils 2020-12-09 01:15:56 -08:00
vvb2060
1ffe9bd83b Fix update channel without description on release build 2020-12-09 00:40:33 -08:00
topjohnwu
0c28b23224 Fix install_module command 2020-12-09 00:37:15 -08:00
vvb2060
ec1af9dc1e Delete useless arrays 2020-12-09 00:17:58 -08:00
vvb2060
ff4cea229a Check environment on emulator
We need to test modules on emulator.
2020-12-09 00:16:27 -08:00
vvb2060
3f81f9371f Disable installation while downloading metadata 2020-12-09 00:16:13 -08:00
vvb2060
60e89a7d22 Ignore manager not installed state 2020-12-09 00:15:58 -08:00
vvb2060
c50daa5c9e Allow restore boot when no network 2020-12-09 00:15:41 -08:00
topjohnwu
58d00ab863 Remove some warnings 2020-12-07 00:06:02 -08:00
topjohnwu
ce916459c5 Fix strings 2020-12-07 00:04:41 -08:00
Antikruk
4094d560ab Belarusian update 2020-12-06 23:50:33 -08:00
RikkaW
4dbf7eb04b Fix spacing in module filter list 2020-12-06 23:49:23 -08:00
RikkaW
a39577c44d Fix extra spacing in module list 2020-12-06 23:49:23 -08:00
osm0sis
125ee46685 scripts: fix find_manager_apk
- the strings fallback was broken when the preceding character changed from 5 to ! recently, this new regex should cover any preceding character going forward
2020-12-06 23:49:03 -08:00
osm0sis
ce84f1762c scripts: fix sloppy/unpredictable cmd && this || that statements
- be a bit more POSIX to avoid any potential issues when full shell stdout/err are redirected
- actual logic chains remain unchanged
2020-12-06 23:48:43 -08:00
Hafitz Setya
a687d1347b Tidying up IN 2020-12-06 23:48:01 -08:00
Arbri çoçka
6d9db20614 Create strings.xml 2020-12-06 23:46:18 -08:00
topjohnwu
c62dfc1bcc Make logging less error prone 2020-12-06 23:09:24 -08:00
topjohnwu
aabe2696fe Cleanup implementations 2020-12-06 03:07:47 -08:00
topjohnwu
ae0d605310 Make sure patch_rootdir does not cause crashes 2020-12-06 02:19:57 -08:00
topjohnwu
2a694596b5 Better error handling and logging 2020-12-05 10:23:49 -08:00
topjohnwu
ff0a76606e Detect 2SI after system_root mount on legacy SAR 2020-12-04 03:06:21 -08:00
topjohnwu
dead74801d Setup log file when manually starting daemon 2020-12-04 01:07:47 -08:00
topjohnwu
ab207a1bb3 va_list cannot be reused on x86 2020-12-03 20:53:19 -08:00
topjohnwu
f152e8c33d Directly log to log file 2020-12-03 20:15:18 -08:00
topjohnwu
797ba4fbf4 Make sure all logging ends with newline 2020-12-02 00:55:22 -08:00
topjohnwu
a848f10bba Update Kotlin 2020-11-23 12:35:24 -08:00
topjohnwu
552ec1eb35 Header v3 does not have name entry 2020-11-20 22:52:09 -08:00
topjohnwu
1385d2a4f4 Fix strings 2020-11-19 23:34:02 -08:00
RikkaW
3b5c9abf7a Remove filterTouchesWhenObscured in Magisk dialog
Fix #3363
2020-11-19 23:32:23 -08:00
tzagim
e0fa032bd3 Update HE strings and fix typos 2020-11-19 23:29:47 -08:00
omerakgoz34
7b69650fcd app: Update Turkish translations 2020-11-19 23:27:54 -08:00
kubalav
08a8df489f Slovak language formating 2020-11-19 23:27:07 -08:00
cristisilaghi
9f35a8a520 Update Romanian 2020-11-19 23:26:38 -08:00
RikkaW
0df891b336 Handle window insets with a new way
For example, switching pages in home should only have scale and alpha animations, but a "translate y" animation shows. This is because Data Binding is triggered later (like "in the next frame"), causing the animation runs before view attribute changes.

This commit introduces WindowInsetsHelper class and use it to handle all window insets. With the help of LayoutInflaterFactory from the previous commit, we can control insets behavior by adding our attributes to the XML and anything is done by WindowInsetsHelper class.

As changes are highly coupling, this commit also contains new ItemDecoration for lists, replacing the random combination of padding and empty drawable. And "fixEdgeEffect" extension for RecyclerView, making edge effects respect padding.
2020-11-19 23:24:39 -08:00
RikkaW
385853a290 Introduce LayoutInflaterFactory
This add the ability touch layout XML instantiates process. And most importantly, we can access AttributeSet, making custom view attribute possible.

Some other changes requires this.
2020-11-19 23:24:39 -08:00
RikkaW
fa3ef8a1c1 Significantly simplify MagiskDialog layout
The goal of original implementation, wrap view again and again, seems to be use the shadow and customizable round corners from MaterialCardView. But this can be done with use MaterialShapeDrawable which used in MaterialCardView directly. This will significantly simplify the layout and MagiskDialog class.
2020-11-19 23:21:36 -08:00
RikkaW
c93ada03c7 Implement Edge-to-edge with newer APIs
The implementation adds a "Base" family styles, making creating themes across multiple API versions more clearer and easier.
2020-11-19 23:21:36 -08:00
topjohnwu
0064b01ae0 Trim out \r from string
Fix #3490
2020-11-15 06:30:29 -08:00
topjohnwu
1469b82aa2 Update README 2020-11-13 04:38:17 -08:00
253 changed files with 15303 additions and 12057 deletions

28
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,28 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
## READ BEFORE OPENING ISSUES
All bug reports require you to **USE CANARY BUILDS**. Please include the version name and version code in the bug report.
If you experience a bootloop, attach a `dmesg` (kernel logs) when the device refuse to boot. This may very likely require a custom kernel on some devices as `last_kmsg` or `pstore ramoops` are usually not enabled by default. In addition, please also upload the result of `cat /proc/mounts` when your device is working correctly **WITHOUT ROOT**.
If you experience issues during installation, in recovery, upload the recovery logs, or in Magisk Manager, upload the install logs. Please also upload the `boot.img` or `recovery.img` that you are using for patching.
If you experience a crash of Magisk Manager, dump the full `logcat` **when the crash happens**. **DO NOT** upload `magisk.log`.
If you experience other issues related to Magisk, upload `magisk.log`, and preferably also include a boot `logcat` (start dumping `logcat` when the device boots up)
**DO NOT** open issues regarding root detection.
**DO NOT** ask for instructions.
**DO NOT** report issues if you have any modules installed.
Without following the rules above, your issue will be closed without explanation.

94
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,94 @@
name: Magisk Build
on:
push:
branches: [ master ]
paths:
- 'app/**'
- 'native/**'
- 'stub/**'
- 'buildSrc/**'
- 'build.py'
- 'gradle.properties'
pull_request:
branches: [ master ]
workflow_dispatch:
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest, macOS-latest ]
steps:
- name: Check out
uses: actions/checkout@v2
with:
submodules: 'recursive'
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: '11'
- name: Set up Python 3
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set up GitHub env (Windows)
if: runner.os == 'Windows'
run: |
$oldAndroidPath = $env:ANDROID_SDK_ROOT
$sdk_root = "C:\Android"
New-Item -Path $sdk_root -ItemType SymbolicLink -Value $oldAndroidPath
$ndk_ver = Select-String -Path "gradle.properties" -Pattern "^magisk.fullNdkVersion=" | % { $_ -replace ".*=" }
echo "ANDROID_SDK_ROOT=$sdk_root" >> $env:GITHUB_ENV
echo "ANDROID_HOME=$sdk_root" >> $env:GITHUB_ENV
echo "MAGISK_NDK_VERSION=$ndk_ver" >> $env:GITHUB_ENV
echo "GRADLE_OPTS=-Dorg.gradle.daemon=false" >> $env:GITHUB_ENV
- name: Set up GitHub env (Unix)
if: runner.os != 'Windows'
run: |
ndk_ver=$(sed -n 's/^magisk.fullNdkVersion=//p' gradle.properties)
echo ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT >> $GITHUB_ENV
echo MAGISK_NDK_VERSION=$ndk_ver >> $GITHUB_ENV
- name: Cache Gradle
uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle-
- name: Cache NDK
id: ndk-cache
uses: actions/cache@v2
with:
path: ${{ env.ANDROID_SDK_ROOT }}/ndk/magisk
key: ${{ runner.os }}-ndk-${{ env.MAGISK_NDK_VERSION }}
- name: Set up NDK
if: steps.ndk-cache.outputs.cache-hit != 'true'
run: python build.py ndk
- name: Build release
run: python build.py -vr all
- name: Build debug
run: python build.py -v all
# Only upload artifacts built on Linux
- name: Upload build artifact
if: runner.os == 'Linux'
uses: actions/upload-artifact@v2
with:
name: ${{ github.sha }}
path: out

3
.gitmodules vendored
View File

@@ -25,6 +25,9 @@
[submodule "pcre"] [submodule "pcre"]
path = native/jni/external/pcre path = native/jni/external/pcre
url = https://android.googlesource.com/platform/external/pcre url = https://android.googlesource.com/platform/external/pcre
[submodule "xhook"]
path = native/jni/external/xhook
url = https://github.com/iqiyi/xHook.git
[submodule "termux-elf-cleaner"] [submodule "termux-elf-cleaner"]
path = tools/termux-elf-cleaner path = tools/termux-elf-cleaner
url = https://github.com/termux/termux-elf-cleaner.git url = https://github.com/termux/termux-elf-cleaner.git

View File

@@ -15,11 +15,11 @@ Here are some feature highlights:
## Downloads ## Downloads
[![](https://img.shields.io/badge/Magisk%20Manager-v8.0.2-green)](https://github.com/topjohnwu/Magisk/releases/download/manager-v8.0.2/MagiskManager-v8.0.2.apk) [![](https://img.shields.io/badge/Magisk%20Manager-v8.0.4-green)](https://github.com/topjohnwu/Magisk/releases/download/manager-v8.0.4/MagiskManager-v8.0.4.apk)
[![](https://img.shields.io/badge/Magisk%20Manager-Canary-red)](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-debug.apk) [![](https://img.shields.io/badge/Magisk%20Manager-Canary-red)](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-debug.apk)
<br> <br>
[![](https://img.shields.io/badge/Magisk-v20.4-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v20.4) [![](https://img.shields.io/badge/Magisk-v20.4-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v20.4)
[![](https://img.shields.io/badge/Magisk%20Beta-v21.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v21.0) [![](https://img.shields.io/badge/Magisk%20Beta-v21.2-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v21.2)
## Useful Links ## Useful Links
@@ -58,11 +58,11 @@ For Magisk Manager crashes, record and upload the logcat when the crash occurs.
- Windows: Add `C:\Path\To\Android Studio\jre\bin` to environment variable `PATH` - Windows: Add `C:\Path\To\Android Studio\jre\bin` to environment variable `PATH`
- Set environment variable `ANDROID_SDK_ROOT` to the Android SDK folder (can be found in Android Studio settings) - Set environment variable `ANDROID_SDK_ROOT` to the Android SDK folder (can be found in Android Studio settings)
- Run `./build.py ndk` to let the script download and install NDK for you - Run `./build.py ndk` to let the script download and install NDK for you
- Set configurations in `config.prop`. A sample `config.prop.sample` is provided.
- To start building, run `build.py` to see your options. \ - To start building, run `build.py` to see your options. \
For each action, use `-h` to access help (e.g. `./build.py all -h`) For each action, use `-h` to access help (e.g. `./build.py all -h`)
- To start development, open the project in Android Studio. Both app (Kotlin/Java) and native (C++/C) source code can be properly developed using the IDE, but *always* use `build.py` for building. - To start development, open the project in Android Studio. Both app (Kotlin/Java) and native (C++/C) source code can be properly developed using the IDE, but *always* use `build.py` for building.
- `build.py` builds in debug mode by default. If you want release builds (with `-r, --release`), you need a Java Keystore to sign APKs and zips. For more information, check [Google's Documentation](https://developer.android.com/studio/publish/app-signing.html#generate-key). - Optionally, set custom configs with `config.prop`. A sample `config.prop.sample` is provided.
- To sign APKs and zips with your own private keys, set signing configs in `config.prop`. For more info, check [Google's Documentation](https://developer.android.com/studio/publish/app-signing.html#generate-key).
## Translation Contributions ## Translation Contributions

View File

@@ -1,7 +1,9 @@
import java.io.PrintStream
plugins { plugins {
id("com.android.application") id("com.android.application")
kotlin("android") kotlin("android")
kotlin("android.extensions") kotlin("plugin.parcelize")
kotlin("kapt") kotlin("kapt")
id("androidx.navigation.safeargs.kotlin") id("androidx.navigation.safeargs.kotlin")
} }
@@ -20,12 +22,11 @@ android {
applicationId = "com.topjohnwu.magisk" applicationId = "com.topjohnwu.magisk"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
multiDexEnabled = true multiDexEnabled = true
versionName = Config["appVersion"] versionName = Config.appVersion
versionCode = Config["appVersionCode"]?.toInt() versionCode = Config.appVersionCode
buildConfigField("int", "LATEST_MAGISK", Config["versionCode"] ?: "Integer.MAX_VALUE")
javaCompileOptions.annotationProcessorOptions.arguments( javaCompileOptions.annotationProcessorOptions.arguments(
mapOf("room.incremental" to "true") mapOf("room.incremental" to "true")
) )
} }
@@ -64,28 +65,61 @@ android {
} }
} }
androidExtensions { tasks["preBuild"]?.dependsOn(tasks.register("copyUtils", Copy::class) {
isExperimental = true
}
val copyUtils = tasks.register("copyUtils", Copy::class) {
from(rootProject.file("scripts/util_functions.sh")) from(rootProject.file("scripts/util_functions.sh"))
into("src/main/res/raw") into("src/main/res/raw")
} })
tasks["preBuild"]?.dependsOn(copyUtils) android.applicationVariants.all {
val keysDir = rootProject.file("tools/keys")
val outSrcDir = File(buildDir, "generated/source/keydata/$name")
val outSrc = File(outSrcDir, "com/topjohnwu/signing/KeyData.java")
fun PrintStream.newField(name: String, file: File) {
println("public static byte[] $name() {")
print("byte[] buf = {")
val bytes = file.readBytes()
print(bytes.joinToString(",") { "(byte)(${it.toInt() and 0xff})" })
println("};")
println("return buf;")
println("}")
}
val genSrcTask = tasks.register("generate${name.capitalize()}KeyData") {
inputs.dir(keysDir)
outputs.file(outSrc)
doLast {
outSrc.parentFile.mkdirs()
PrintStream(outSrc).use {
it.println("package com.topjohnwu.signing;")
it.println("public final class KeyData {")
it.newField("testCert", File(keysDir, "testkey.x509.pem"))
it.newField("testKey", File(keysDir, "testkey.pk8"))
it.newField("verityCert", File(keysDir, "verity.x509.pem"))
it.newField("verityKey", File(keysDir, "verity.pk8"))
it.println("}")
}
}
}
registerJavaGeneratingTask(genSrcTask.get(), outSrcDir)
}
dependencies { dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
implementation(kotlin("stdlib")) implementation(kotlin("stdlib"))
implementation(project(":app:shared")) implementation(project(":app:shared"))
implementation(project(":app:signing"))
implementation("com.github.topjohnwu:jtar:1.0.0") implementation("com.github.topjohnwu:jtar:1.0.0")
implementation("com.github.topjohnwu:indeterminate-checkbox:1.0.7") implementation("com.github.topjohnwu:indeterminate-checkbox:1.0.7")
implementation("com.github.topjohnwu:lz4-java:1.7.1") implementation("com.github.topjohnwu:lz4-java:1.7.1")
implementation("com.jakewharton.timber:timber:4.7.1") implementation("com.jakewharton.timber:timber:4.7.1")
val vBC = "1.68"
implementation("org.bouncycastle:bcprov-jdk15on:${vBC}")
implementation("org.bouncycastle:bcpkix-jdk15on:${vBC}")
val vBAdapt = "4.0.0" val vBAdapt = "4.0.0"
val bindingAdapter = "me.tatarka.bindingcollectionadapter2:bindingcollectionadapter" val bindingAdapter = "me.tatarka.bindingcollectionadapter2:bindingcollectionadapter"
implementation("${bindingAdapter}:${vBAdapt}") implementation("${bindingAdapter}:${vBAdapt}")
@@ -124,7 +158,7 @@ dependencies {
implementation("com.squareup.moshi:moshi:${vMoshi}") implementation("com.squareup.moshi:moshi:${vMoshi}")
kapt("com.squareup.moshi:moshi-kotlin-codegen:${vMoshi}") kapt("com.squareup.moshi:moshi-kotlin-codegen:${vMoshi}")
val vRoom = "2.3.0-alpha03" val vRoom = "2.3.0-alpha04"
implementation("androidx.room:room-runtime:${vRoom}") implementation("androidx.room:room-runtime:${vRoom}")
implementation("androidx.room:room-ktx:${vRoom}") implementation("androidx.room:room-ktx:${vRoom}")
kapt("androidx.room:room-compiler:${vRoom}") kapt("androidx.room:room-compiler:${vRoom}")
@@ -136,7 +170,7 @@ dependencies {
implementation("androidx.biometric:biometric:1.0.1") implementation("androidx.biometric:biometric:1.0.1")
implementation("androidx.constraintlayout:constraintlayout:2.0.4") implementation("androidx.constraintlayout:constraintlayout:2.0.4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.browser:browser:1.2.0") implementation("androidx.browser:browser:1.3.0")
implementation("androidx.preference:preference:1.1.1") implementation("androidx.preference:preference:1.1.1")
implementation("androidx.recyclerview:recyclerview:1.1.0") implementation("androidx.recyclerview:recyclerview:1.1.0")
implementation("androidx.fragment:fragment-ktx:1.2.5") implementation("androidx.fragment:fragment-ktx:1.2.5")

View File

@@ -1 +0,0 @@
/build

View File

@@ -1,35 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
id("java-library")
id("java")
id("com.github.johnrengelman.shadow") version "6.0.0"
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
val jar by tasks.getting(Jar::class) {
manifest {
attributes["Main-Class"] = "com.topjohnwu.signing.ZipSigner"
}
}
val shadowJar by tasks.getting(ShadowJar::class) {
archiveBaseName.set("zipsigner")
archiveClassifier.set(null as String?)
archiveVersion.set("4.0")
}
repositories {
jcenter()
}
dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
api("org.bouncycastle:bcprov-jdk15on:1.67")
api("org.bouncycastle:bcpkix-jdk15on:1.67")
}

View File

@@ -1,49 +0,0 @@
package com.topjohnwu.signing;
import java.io.FileInputStream;
import java.io.InputStream;
public class BootSigner {
public static void main(String[] args) throws Exception {
if (args.length > 0 && "-verify".equals(args[0])) {
String certPath = "";
if (args.length >= 2) {
/* args[1] is the path to a public key certificate */
certPath = args[1];
}
boolean signed = SignBoot.verifySignature(System.in,
certPath.isEmpty() ? null : new FileInputStream(certPath));
System.exit(signed ? 0 : 1);
} else if (args.length > 0 && "-sign".equals(args[0])) {
InputStream cert = null;
InputStream key = null;
String name = "/boot";
if (args.length >= 3) {
cert = new FileInputStream(args[1]);
key = new FileInputStream(args[2]);
}
if (args.length == 2) {
name = args[1];
} else if (args.length >= 4) {
name = args[3];
}
boolean success = SignBoot.doSignature(name, System.in, System.out, cert, key);
System.exit(success ? 0 : 1);
} else {
System.err.println(
"BootSigner <actions> [args]\n" +
"Input from stdin, outputs to stdout\n" +
"\n" +
"Actions:\n" +
" -verify [x509.pem]\n" +
" verify image, cert is optional\n" +
" -sign [x509.pem] [pk8] [name]\n" +
" sign image, name, cert and key pair are optional\n" +
" name should be /boot (default) or /recovery\n"
);
}
}
}

View File

@@ -1,81 +0,0 @@
package com.topjohnwu.signing;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class ZipSigner {
private static void usage() {
System.err.println("ZipSigner usage:");
System.err.println(" zipsigner.jar input.jar output.jar");
System.err.println(" sign jar with AOSP test keys");
System.err.println(" zipsigner.jar x509.pem pk8 input.jar output.jar");
System.err.println(" sign jar with certificate / private key pair");
System.err.println(" zipsigner.jar keyStore keyStorePass alias keyPass input.jar output.jar");
System.err.println(" sign jar with Java KeyStore");
System.exit(2);
}
private static void sign(JarMap input, FileOutputStream output) throws Exception {
sign(SignApk.class.getResourceAsStream("/keys/testkey.x509.pem"),
SignApk.class.getResourceAsStream("/keys/testkey.pk8"), input, output);
}
private static void sign(InputStream certIs, InputStream keyIs,
JarMap input, FileOutputStream output) throws Exception {
X509Certificate cert = CryptoUtils.readCertificate(certIs);
PrivateKey key = CryptoUtils.readPrivateKey(keyIs);
SignApk.sign(cert, key, input, output);
}
private static void sign(String keyStore, String keyStorePass, String alias, String keyPass,
JarMap in, FileOutputStream out) throws Exception {
KeyStore ks;
try {
ks = KeyStore.getInstance("JKS");
try (InputStream is = new FileInputStream(keyStore)) {
ks.load(is, keyStorePass.toCharArray());
}
} catch (KeyStoreException|IOException|CertificateException|NoSuchAlgorithmException e) {
ks = KeyStore.getInstance("PKCS12");
try (InputStream is = new FileInputStream(keyStore)) {
ks.load(is, keyStorePass.toCharArray());
}
}
X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
PrivateKey key = (PrivateKey) ks.getKey(alias, keyPass.toCharArray());
SignApk.sign(cert, key, in, out);
}
public static void main(String[] args) throws Exception {
if (args.length != 2 && args.length != 4 && args.length != 6)
usage();
Security.insertProviderAt(new BouncyCastleProvider(), 1);
try (JarMap in = JarMap.open(args[args.length - 2], false);
FileOutputStream out = new FileOutputStream(args[args.length - 1])) {
if (args.length == 2) {
sign(in, out);
} else if (args.length == 4) {
try (InputStream cert = new FileInputStream(args[0]);
InputStream key = new FileInputStream(args[1])) {
sign(cert, key, in, out);
}
} else if (args.length == 6) {
sign(args[0], args[1], args[2], args[3], in, out);
}
}
}
}

View File

@@ -12,7 +12,7 @@
<application <application
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:name="a.e" android:name="a.e"
android:allowBackup="true" android:allowBackup="false"
tools:ignore="UnusedAttribute,GoogleAppIndexingWarning"> tools:ignore="UnusedAttribute,GoogleAppIndexingWarning">
<!-- Splash --> <!-- Splash -->

View File

@@ -8,10 +8,10 @@ import com.topjohnwu.magisk.core.SplashActivity
import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.ui.MainActivity import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.signing.BootSigner import com.topjohnwu.signing.SignBoot
fun main(args: Array<String>) { fun main(args: Array<String>) {
BootSigner.main(args) SignBoot.main(args)
} }
class b : MainActivity() class b : MainActivity()

View File

@@ -1,5 +1,8 @@
package com.topjohnwu.magisk.arch package com.topjohnwu.magisk.arch
import android.content.res.Resources
import android.graphics.Color
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent import android.view.KeyEvent
import android.view.View import android.view.View
@@ -14,6 +17,7 @@ import androidx.navigation.fragment.NavHostFragment
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.base.BaseActivity import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.ui.inflater.LayoutInflaterFactory
import com.topjohnwu.magisk.ui.theme.Theme import com.topjohnwu.magisk.ui.theme.Theme
abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> : abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
@@ -41,6 +45,8 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
layoutInflater.factory2 = LayoutInflaterFactory(delegate)
setTheme(themeRes) setTheme(themeRes)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -59,6 +65,31 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
directionsDispatcher.value = null directionsDispatcher.value = null
} }
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window?.decorView?.let {
it.systemUiVisibility = (it.systemUiVisibility
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
window?.decorView?.post {
// If navigation bar is short enough (gesture navigation enabled), make it transparent
if (window.decorView.rootWindowInsets?.systemWindowInsetBottom ?: 0 < Resources.getSystem().displayMetrics.density * 40) {
window.navigationBarColor = Color.TRANSPARENT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.navigationBarDividerColor = Color.TRANSPARENT
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
window.isNavigationBarContrastEnforced = false
window.isStatusBarContrastEnforced = false
}
}
}
}
}
} }
fun setContentView() { fun setContentView() {
@@ -66,8 +97,6 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
it.setVariable(BR.viewModel, viewModel) it.setVariable(BR.viewModel, viewModel)
it.lifecycleOwner = this it.lifecycleOwner = this
} }
ensureInsets()
} }
fun setAccessibilityDelegate(delegate: View.AccessibilityDelegate?) { fun setAccessibilityDelegate(delegate: View.AccessibilityDelegate?) {

View File

@@ -1,12 +1,9 @@
package com.topjohnwu.magisk.arch package com.topjohnwu.magisk.arch
import android.view.View import android.view.View
import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
interface BaseUIComponent<VM : BaseViewModel>: LifecycleOwner { interface BaseUIComponent<VM : BaseViewModel> : LifecycleOwner {
val viewRoot: View val viewRoot: View
val viewModel: VM val viewModel: VM
@@ -17,47 +14,8 @@ interface BaseUIComponent<VM : BaseViewModel>: LifecycleOwner {
} }
} }
fun consumeSystemWindowInsets(insets: Insets): Insets? = null
/** /**
* Called for all [ViewEvent]s published by associated viewModel. * Called for all [ViewEvent]s published by associated viewModel.
*/ */
fun onEventDispatched(event: ViewEvent) {} fun onEventDispatched(event: ViewEvent) {}
fun ensureInsets() {
ViewCompat.setOnApplyWindowInsetsListener(viewRoot) { _, insets ->
insets.asInsets()
.also { viewModel.insets = it }
.let { consumeSystemWindowInsets(it) }
?.subtractBy(insets) ?: insets
}
if (ViewCompat.isAttachedToWindow(viewRoot)) {
ViewCompat.requestApplyInsets(viewRoot)
} else {
viewRoot.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewDetachedFromWindow(v: View) = Unit
override fun onViewAttachedToWindow(v: View) {
ViewCompat.requestApplyInsets(v)
}
})
}
}
private fun WindowInsetsCompat.asInsets() = Insets.of(
systemWindowInsetLeft,
systemWindowInsetTop,
systemWindowInsetRight,
systemWindowInsetBottom
)
private fun Insets.subtractBy(insets: WindowInsetsCompat) =
WindowInsetsCompat.Builder(insets).setSystemWindowInsets(
Insets.of(
insets.systemWindowInsetLeft - left,
insets.systemWindowInsetTop - top,
insets.systemWindowInsetRight - right,
insets.systemWindowInsetBottom - bottom
)
).build()
} }

View File

@@ -24,8 +24,6 @@ abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
override val viewRoot: View get() = binding.root override val viewRoot: View get() = binding.root
private val navigation get() = activity.navigation private val navigation get() = activity.navigation
override fun consumeSystemWindowInsets(insets: Insets) = insets
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
startObserveEvents() startObserveEvents()
@@ -65,7 +63,6 @@ abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
return true return true
} }
}) })
ensureInsets()
} }
override fun onResume() { override fun onResume() {

View File

@@ -18,7 +18,6 @@ import com.topjohnwu.magisk.ktx.inject
import com.topjohnwu.magisk.ui.theme.Theme import com.topjohnwu.magisk.ui.theme.Theme
import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParser
import java.io.File import java.io.File
import java.io.IOException
import java.io.InputStream import java.io.InputStream
object Config : PreferenceModel, DBConfig { object Config : PreferenceModel, DBConfig {
@@ -159,12 +158,13 @@ object Config : PreferenceModel, DBConfig {
private const val SU_FINGERPRINT = "su_fingerprint" private const val SU_FINGERPRINT = "su_fingerprint"
fun load(pkg: String) { fun load(pkg: String?) {
try { // Only try to load prefs when fresh install and a previous package name is set
if (pkg != null && prefs.all.isEmpty()) runCatching {
context.contentResolver.openInputStream(Provider.PREFS_URI(pkg))?.use { context.contentResolver.openInputStream(Provider.PREFS_URI(pkg))?.use {
prefs.edit { parsePrefs(it) } prefs.edit { parsePrefs(it) }
} }
} catch (e: IOException) {} }
prefs.edit { prefs.edit {
// Settings migration // Settings migration

View File

@@ -16,8 +16,6 @@ object Const {
const val BOOTCTL_REVISION = "18ab78817087c337ae0edd1ecac38aec49217880" const val BOOTCTL_REVISION = "18ab78817087c337ae0edd1ecac38aec49217880"
// Misc // Misc
const val ANDROID_MANIFEST = "AndroidManifest.xml"
const val MAGISK_INSTALL_LOG_FILENAME = "magisk_install_log_%s.log"
val USER_ID = Process.myUid() / 100000 val USER_ID = Process.myUid() / 100000
object Version { object Version {
@@ -27,6 +25,7 @@ object Const {
fun atLeast_20_2() = Info.env.magiskVersionCode >= 20200 || isCanary() fun atLeast_20_2() = Info.env.magiskVersionCode >= 20200 || isCanary()
fun atLeast_20_4() = Info.env.magiskVersionCode >= 20400 || isCanary() fun atLeast_20_4() = Info.env.magiskVersionCode >= 20400 || isCanary()
fun atLeast_21_0() = Info.env.magiskVersionCode >= 21000 || isCanary() fun atLeast_21_0() = Info.env.magiskVersionCode >= 21000 || isCanary()
fun atLeast_21_2() = Info.env.magiskVersionCode >= 21200 || isCanary()
fun isCanary() = Info.env.magiskVersionCode % 100 != 0 fun isCanary() = Info.env.magiskVersionCode % 100 != 0
} }
@@ -38,7 +37,6 @@ object Const {
// notifications // notifications
const val MAGISK_UPDATE_NOTIFICATION_ID = 4 const val MAGISK_UPDATE_NOTIFICATION_ID = 4
const val APK_UPDATE_NOTIFICATION_ID = 5 const val APK_UPDATE_NOTIFICATION_ID = 5
const val HIDE_MANAGER_NOTIFICATION_ID = 8
const val UPDATE_NOTIFICATION_CHANNEL = "update" const val UPDATE_NOTIFICATION_CHANNEL = "update"
const val PROGRESS_NOTIFICATION_CHANNEL = "progress" const val PROGRESS_NOTIFICATION_CHANNEL = "progress"
const val CHECK_MAGISK_UPDATE_WORKER_ID = "magisk_update" const val CHECK_MAGISK_UPDATE_WORKER_ID = "magisk_update"
@@ -58,7 +56,7 @@ object Const {
object Key { object Key {
// intents // intents
const val OPEN_SECTION = "section" const val OPEN_SECTION = "section"
const val HIDDEN_PKG = "hidden_pkg" const val PREV_PKG = "prev_pkg"
} }
object Value { object Value {

View File

@@ -48,10 +48,10 @@ open class SplashActivity : Activity() {
// Pre-initialize root shell // Pre-initialize root shell
Shell.getShell() Shell.getShell()
val hiddenPackage = intent.getStringExtra(Const.Key.HIDDEN_PKG) val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)
Config.load(hiddenPackage ?: APPLICATION_ID) Config.load(prevPkg)
handleRepackage(hiddenPackage) handleRepackage(prevPkg)
Notifications.setup(this) Notifications.setup(this)
UpdateCheckService.schedule(this) UpdateCheckService.schedule(this)
Shortcuts.setupDynamic(this) Shortcuts.setupDynamic(this)

View File

@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.core.download
import android.net.Uri import android.net.Uri
import android.os.Parcelable import android.os.Parcelable
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
sealed class Action : Parcelable { sealed class Action : Parcelable {

View File

@@ -12,8 +12,8 @@ import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.core.utils.MediaStoreUtils import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.ktx.cachedFile import com.topjohnwu.magisk.ktx.cachedFile
import com.topjohnwu.magisk.ktx.get import com.topjohnwu.magisk.ktx.get
import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
private fun cachedFile(name: String) = get<Context>().cachedFile(name).apply { delete() }.toUri() private fun cachedFile(name: String) = get<Context>().cachedFile(name).apply { delete() }.toUri()
@@ -101,7 +101,6 @@ sealed class Subject : Parcelable {
Action.Download -> Download() Action.Download -> Download()
Action.Uninstall -> Uninstall() Action.Uninstall -> Uninstall()
Action.EnvFix, is Action.Flash, is Action.Patch -> Internal(config) Action.EnvFix, is Action.Flash, is Action.Patch -> Internal(config)
else -> throw IllegalArgumentException()
} }
} }

View File

@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.core.model
import android.os.Parcelable import android.os.Parcelable
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class UpdateInfo( data class UpdateInfo(

View File

@@ -27,13 +27,13 @@ class LocalModule(path: String) : Module() {
val dir = "$PERSIST/$id" val dir = "$PERSIST/$id"
if (enable) { if (enable) {
disableFile.delete() disableFile.delete()
if (Const.Version.isCanary()) if (Const.Version.atLeast_21_2())
Shell.su("copy_sepolicy_rules").submit() Shell.su("copy_sepolicy_rules").submit()
else else
Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit() Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
} else { } else {
!disableFile.createNewFile() !disableFile.createNewFile()
if (Const.Version.isCanary()) if (Const.Version.atLeast_21_2())
Shell.su("copy_sepolicy_rules").submit() Shell.su("copy_sepolicy_rules").submit()
else else
Shell.su("rm -rf $dir").submit() Shell.su("rm -rf $dir").submit()
@@ -45,13 +45,13 @@ class LocalModule(path: String) : Module() {
set(remove) { set(remove) {
if (remove) { if (remove) {
removeFile.createNewFile() removeFile.createNewFile()
if (Const.Version.isCanary()) if (Const.Version.atLeast_21_2())
Shell.su("copy_sepolicy_rules").submit() Shell.su("copy_sepolicy_rules").submit()
else else
Shell.su("rm -rf $PERSIST/$id").submit() Shell.su("rm -rf $PERSIST/$id").submit()
} else { } else {
!removeFile.delete() !removeFile.delete()
if (Const.Version.isCanary()) if (Const.Version.atLeast_21_2())
Shell.su("copy_sepolicy_rules").submit() Shell.su("copy_sepolicy_rules").submit()
else else
Shell.su("cp -af $ruleFile $PERSIST/$id").submit() Shell.su("cp -af $ruleFile $PERSIST/$id").submit()

View File

@@ -7,7 +7,7 @@ import com.topjohnwu.magisk.core.model.ModuleJson
import com.topjohnwu.magisk.data.repository.NetworkService import com.topjohnwu.magisk.data.repository.NetworkService
import com.topjohnwu.magisk.ktx.get import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.ktx.legalFilename import com.topjohnwu.magisk.ktx.legalFilename
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
import java.text.DateFormat import java.text.DateFormat
import java.util.* import java.util.*

View File

@@ -33,6 +33,7 @@ object HideAPK {
private const val ALPHA = "abcdefghijklmnopqrstuvwxyz" private const val ALPHA = "abcdefghijklmnopqrstuvwxyz"
private const val ALPHADOTS = "$ALPHA....." private const val ALPHADOTS = "$ALPHA....."
private const val APP_NAME = "Magisk Manager" private const val APP_NAME = "Magisk Manager"
private const val ANDROID_MANIFEST = "AndroidManifest.xml"
// Some arbitrary limit // Some arbitrary limit
const val MAX_LABEL_LENGTH = 32 const val MAX_LABEL_LENGTH = 32
@@ -71,7 +72,7 @@ object HideAPK {
): Boolean { ): Boolean {
try { try {
val jar = JarMap.open(apk) val jar = JarMap.open(apk)
val je = jar.getJarEntry(Const.ANDROID_MANIFEST) val je = jar.getJarEntry(ANDROID_MANIFEST)
val xml = AXML(jar.getRawData(je)) val xml = AXML(jar.getRawData(je))
if (!xml.findAndPatch(APPLICATION_ID to pkg, APP_NAME to label.toString())) if (!xml.findAndPatch(APPLICATION_ID to pkg, APP_NAME to label.toString()))
@@ -123,6 +124,7 @@ object HideAPK {
Config.suManager = pkg Config.suManager = pkg
grantUriPermission(pkg, APK_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION) grantUriPermission(pkg, APK_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
grantUriPermission(pkg, PREFS_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION) grantUriPermission(pkg, PREFS_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.putExtra(Const.Key.PREV_PKG, packageName)
startActivity(intent) startActivity(intent)
} }
@@ -167,7 +169,7 @@ object HideAPK {
Config.suManager = "" Config.suManager = ""
grantUriPermission(APPLICATION_ID, APK_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION) grantUriPermission(APPLICATION_ID, APK_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
grantUriPermission(APPLICATION_ID, PREFS_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION) grantUriPermission(APPLICATION_ID, PREFS_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.putExtra(Const.Key.HIDDEN_PKG, packageName) intent.putExtra(Const.Key.PREV_PKG, packageName)
startActivity(intent) startActivity(intent)
} }

View File

@@ -8,8 +8,10 @@ import android.widget.Toast
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import androidx.core.os.postDelayed import androidx.core.os.postDelayed
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.utils.MediaStoreUtils import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
@@ -40,6 +42,8 @@ import org.koin.core.inject
import timber.log.Timber import timber.log.Timber
import java.io.* import java.io.*
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.security.SecureRandom
import java.util.*
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
@@ -107,6 +111,8 @@ abstract class MagiskInstallImpl : KoinComponent {
} }
console.add("- Device platform: " + Build.CPU_ABI) console.add("- Device platform: " + Build.CPU_ABI)
console.add("- Magisk Manager: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
console.add("- Install target: ${Info.remote.magisk.version} (${Info.remote.magisk.versionCode})")
try { try {
ZipInputStream(zipUri.inputStream().buffered()).use { zi -> ZipInputStream(zipUri.inputStream().buffered()).use { zi ->
@@ -225,7 +231,7 @@ abstract class MagiskInstallImpl : KoinComponent {
private fun handleFile(uri: Uri): Boolean { private fun handleFile(uri: Uri): Boolean {
val outStream: OutputStream val outStream: OutputStream
val outFile: MediaStoreUtils.UriFile var outFile: MediaStoreUtils.UriFile? = null
// Process input file // Process input file
try { try {
@@ -237,27 +243,40 @@ abstract class MagiskInstallImpl : KoinComponent {
return false return false
} }
src.reset() src.reset()
val alpha = "abcdefghijklmnopqrstuvwxyz"
val alphaNum = "$alpha${alpha.toUpperCase(Locale.ROOT)}0123456789"
val random = SecureRandom()
val suffix = StringBuilder()
for (i in 1..5) {
suffix.append(alphaNum[random.nextInt(alphaNum.length)])
}
val filename = "magisk_patched_$suffix"
outStream = if (magic.contentEquals("ustar".toByteArray())) { outStream = if (magic.contentEquals("ustar".toByteArray())) {
outFile = MediaStoreUtils.getFile("magisk_patched.tar") outFile = MediaStoreUtils.getFile("$filename.tar", true)
handleTar(src, outFile.uri.outputStream()) handleTar(src, outFile!!.uri.outputStream())
} else { } else {
// Raw image // Raw image
srcBoot = File(installDir, "boot.img").path srcBoot = File(installDir, "boot.img").path
console.add("- Copying image to cache") console.add("- Copying image to cache")
FileOutputStream(srcBoot).use { src.copyTo(it) } FileOutputStream(srcBoot).use { src.copyTo(it) }
outFile = MediaStoreUtils.getFile("magisk_patched.img") outFile = MediaStoreUtils.getFile("$filename.img", true)
outFile.uri.outputStream() outFile!!.uri.outputStream()
} }
} }
} catch (e: IOException) { } catch (e: IOException) {
console.add("! Process error") console.add("! Process error")
outFile?.delete()
Timber.e(e) Timber.e(e)
return false return false
} }
// Patch file // Patch file
if (!patchBoot()) if (!patchBoot()) {
outFile!!.delete()
return false return false
}
// Output file // Output file
try { try {
@@ -276,6 +295,7 @@ abstract class MagiskInstallImpl : KoinComponent {
console.add("****************************") console.add("****************************")
} catch (e: IOException) { } catch (e: IOException) {
console.add("! Failed to output to $outFile") console.add("! Failed to output to $outFile")
outFile!!.delete()
Timber.e(e) Timber.e(e)
return false return false
} }
@@ -325,7 +345,7 @@ abstract class MagiskInstallImpl : KoinComponent {
val signed = File(installDir, "signed.img") val signed = File(installDir, "signed.img")
try { try {
withStreams(SuFileInputStream(patched), signed.outputStream().buffered()) { withStreams(SuFileInputStream(patched), signed.outputStream().buffered()) {
input, out -> SignBoot.doSignature("/boot", input, out, null, null) input, out -> SignBoot.doSignature(null, null, input, out, "/boot")
} }
} catch (e: IOException) { } catch (e: IOException) {
console.add("! Unable to sign image") console.add("! Unable to sign image")
@@ -339,6 +359,13 @@ abstract class MagiskInstallImpl : KoinComponent {
return true return true
} }
private fun copySepolicyRules(): Boolean {
if (Info.remote.magisk.versionCode >= 21100) return true
// Copy existing rules for migration
"copy_sepolicy_rules".sh()
return true
}
private fun flashBoot(): Boolean { private fun flashBoot(): Boolean {
if (!"direct_install $installDir $srcBoot".sh().isSuccess) if (!"direct_install $installDir $srcBoot".sh().isSuccess)
return false return false
@@ -373,10 +400,11 @@ abstract class MagiskInstallImpl : KoinComponent {
protected fun doPatchFile(patchFile: Uri) = extractZip() && handleFile(patchFile) protected fun doPatchFile(patchFile: Uri) = extractZip() && handleFile(patchFile)
protected fun direct() = findImage() && extractZip() && patchBoot() && flashBoot() protected fun direct() = findImage() && extractZip() && patchBoot() &&
copySepolicyRules() && flashBoot()
protected suspend fun secondSlot() = protected suspend fun secondSlot() = findSecondaryImage() && extractZip() &&
findSecondaryImage() && extractZip() && patchBoot() && flashBoot() && postOTA() patchBoot() && copySepolicyRules() && flashBoot() && postOTA()
protected fun fixEnv(zip: Uri): Boolean { protected fun fixEnv(zip: Uri): Boolean {
installDir = SuFile("/data/adb/magisk") installDir = SuFile("/data/adb/magisk")

View File

@@ -7,10 +7,12 @@ import android.util.Base64OutputStream
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.signing.CryptoUtils.readCertificate import com.topjohnwu.signing.CryptoUtils.readCertificate
import com.topjohnwu.signing.CryptoUtils.readPrivateKey import com.topjohnwu.signing.CryptoUtils.readPrivateKey
import com.topjohnwu.signing.KeyData
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.math.BigInteger import java.math.BigInteger
import java.security.KeyPairGenerator import java.security.KeyPairGenerator
@@ -58,10 +60,10 @@ class Keygen(context: Context) : CertKeyProvider {
class TestProvider : CertKeyProvider { class TestProvider : CertKeyProvider {
override val cert by lazy { override val cert by lazy {
readCertificate(javaClass.getResourceAsStream("/keys/testkey.x509.pem")) readCertificate(ByteArrayInputStream(KeyData.testCert()))
} }
override val key by lazy { override val key by lazy {
readPrivateKey(javaClass.getResourceAsStream("/keys/testkey.pk8")) readPrivateKey(ByteArrayInputStream(KeyData.testKey()))
} }
} }

View File

@@ -1,6 +1,5 @@
package com.topjohnwu.magisk.core.utils package com.topjohnwu.magisk.core.utils
import android.annotation.SuppressLint
import android.content.ContentResolver import android.content.ContentResolver
import android.content.ContentUris import android.content.ContentUris
import android.content.ContentValues import android.content.ContentValues
@@ -40,15 +39,17 @@ object MediaStoreUtils {
private val relativePath get() = relativePath(Config.downloadDir) private val relativePath get() = relativePath(Config.downloadDir)
@RequiresApi(api = 29) @RequiresApi(api = 30)
@Throws(IOException::class) @Throws(IOException::class)
private fun insertFile(displayName: String): MediaStoreFile { private fun insertFile(displayName: String): MediaStoreFile {
val values = ContentValues() val values = ContentValues()
values.put(MediaStore.MediaColumns.RELATIVE_PATH, relativePath) values.put(MediaStore.MediaColumns.RELATIVE_PATH, relativePath)
values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName) values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)
// before Android 11, MediaStore can not rename new file when file exists, // When a file with the same name exists and was not created by us:
// insert will return null. use newFile() instead. // - Before Android 11, insert will return null
// - On Android 11+, the system will automatically create a new name
// Thus the reason to restrict this method call to API 30+
val fileUri = cr.insert(tableUri, values) ?: throw IOException("Can't insert $displayName.") val fileUri = cr.insert(tableUri, values) ?: throw IOException("Can't insert $displayName.")
val projection = arrayOf(MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DATA) val projection = arrayOf(MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DATA)
@@ -65,14 +66,8 @@ object MediaStoreUtils {
throw IOException("Can't insert $displayName.") throw IOException("Can't insert $displayName.")
} }
@RequiresApi(api = 29)
private fun queryFile(displayName: String): UriFile? { private fun queryFile(displayName: String): UriFile? {
if (Build.VERSION.SDK_INT < 30) {
// Fallback to file based I/O pre Android 11
val parent = File(Environment.getExternalStorageDirectory(), relativePath)
parent.mkdirs()
return LegacyUriFile(File(parent, displayName))
}
val projection = arrayOf(MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DATA) val projection = arrayOf(MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DATA)
// Before Android 10, we wrote the DISPLAY_NAME field when insert, so it can be used. // Before Android 10, we wrote the DISPLAY_NAME field when insert, so it can be used.
val selection = "${MediaStore.MediaColumns.DISPLAY_NAME} == ?" val selection = "${MediaStore.MediaColumns.DISPLAY_NAME} == ?"
@@ -92,11 +87,17 @@ object MediaStoreUtils {
return null return null
} }
@SuppressLint("NewApi")
@Throws(IOException::class) @Throws(IOException::class)
fun getFile(displayName: String): UriFile { fun getFile(displayName: String, skipQuery: Boolean = false): UriFile {
return queryFile(displayName) ?: if (Build.VERSION.SDK_INT < 30) {
/* this code path will never happen pre 29 */ insertFile(displayName) // Fallback to file based I/O pre Android 11
val parent = File(Environment.getExternalStorageDirectory(), relativePath)
parent.mkdirs()
return LegacyUriFile(File(parent, displayName))
}
return if (skipQuery) insertFile(displayName)
else queryFile(displayName) ?: insertFile(displayName)
} }
fun Uri.inputStream() = cr.openInputStream(this) ?: throw FileNotFoundException() fun Uri.inputStream() = cr.openInputStream(this) ?: throw FileNotFoundException()

View File

@@ -0,0 +1,193 @@
@file:Suppress("unused")
package com.topjohnwu.magisk.ktx
import android.graphics.Canvas
import android.graphics.Rect
import android.view.View
import android.widget.EdgeEffect
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.R
fun RecyclerView.addInvalidateItemDecorationsObserver() {
adapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
invalidateItemDecorations()
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
invalidateItemDecorations()
}
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
invalidateItemDecorations()
}
})
}
fun RecyclerView.addVerticalPadding(paddingTop: Int = 0, paddingBottom: Int = 0) {
addItemDecoration(VerticalPaddingDecoration(paddingTop, paddingBottom))
}
private class VerticalPaddingDecoration(private val paddingTop: Int = 0, private val paddingBottom: Int = 0) : RecyclerView.ItemDecoration() {
private var allowTop: Boolean = true
private var allowBottom: Boolean = true
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val adapter = parent.adapter ?: return
val position = parent.getChildAdapterPosition(view)
val count = adapter.itemCount
if (position == 0 && allowTop) {
outRect.top = paddingTop
} else if (position == count - 1 && allowBottom) {
outRect.bottom = paddingBottom
}
}
}
fun RecyclerView.addSimpleItemDecoration(
left: Int = 0,
top: Int = 0,
right: Int = 0,
bottom: Int = 0,
) {
addItemDecoration(SimpleItemDecoration(left, top, right, bottom))
}
private class SimpleItemDecoration(
private val left: Int = 0,
private val top: Int = 0,
private val right: Int = 0,
private val bottom: Int = 0
) : RecyclerView.ItemDecoration() {
private var allowLeft: Boolean = true
private var allowTop: Boolean = true
private var allowRight: Boolean = true
private var allowBottom: Boolean = true
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
if (parent.adapter == null) {
return
}
if (allowLeft) {
outRect.left = left
}
if (allowTop) {
outRect.top = top
}
if (allowRight) {
outRect.right = right
}
if (allowBottom) {
outRect.top = bottom
}
}
}
fun RecyclerView.fixEdgeEffect(overScrollIfContentScrolls: Boolean = true, alwaysClipToPadding: Boolean = true) {
if (overScrollIfContentScrolls) {
val listener = OverScrollIfContentScrollsListener()
addOnLayoutChangeListener(listener)
setTag(R.id.tag_rikka_recyclerView_OverScrollIfContentScrollsListener, listener)
} else {
val listener = getTag(R.id.tag_rikka_recyclerView_OverScrollIfContentScrollsListener) as? OverScrollIfContentScrollsListener
if (listener != null) {
removeOnLayoutChangeListener(listener)
setTag(R.id.tag_rikka_recyclerView_OverScrollIfContentScrollsListener, null)
}
}
edgeEffectFactory = if (alwaysClipToPadding && !clipToPadding) {
AlwaysClipToPaddingEdgeEffectFactory()
} else {
RecyclerView.EdgeEffectFactory()
}
}
private class OverScrollIfContentScrollsListener : View.OnLayoutChangeListener {
private var show = true
override fun onLayoutChange(v: View, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) {
if (shouldDrawOverScroll(v as RecyclerView) != show) {
show = !show
if (show) {
v.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS)
} else {
v.setOverScrollMode(View.OVER_SCROLL_NEVER)
}
}
}
fun shouldDrawOverScroll(recyclerView: RecyclerView): Boolean {
if (recyclerView.layoutManager == null || recyclerView.adapter == null || recyclerView.adapter!!.itemCount == 0) {
return false
}
if (recyclerView.layoutManager is LinearLayoutManager) {
val itemCount = recyclerView.layoutManager!!.itemCount
val firstPosition: Int = (recyclerView.layoutManager as LinearLayoutManager?)!!.findFirstCompletelyVisibleItemPosition()
val lastPosition: Int = (recyclerView.layoutManager as LinearLayoutManager?)!!.findLastCompletelyVisibleItemPosition()
return firstPosition != 0 || lastPosition != itemCount - 1
}
return true
}
}
private class AlwaysClipToPaddingEdgeEffectFactory : RecyclerView.EdgeEffectFactory() {
override fun createEdgeEffect(view: RecyclerView, direction: Int): EdgeEffect {
return object : EdgeEffect(view.context) {
private var ensureSize = false
private fun ensureSize() {
if (ensureSize) return
ensureSize = true
when (direction) {
DIRECTION_LEFT -> {
setSize(view.measuredHeight - view.paddingTop - view.paddingBottom,
view.measuredWidth - view.paddingLeft - view.paddingRight)
}
DIRECTION_TOP -> {
setSize(view.measuredWidth - view.paddingLeft - view.paddingRight,
view.measuredHeight - view.paddingTop - view.paddingBottom)
}
DIRECTION_RIGHT -> {
setSize(view.measuredHeight - view.paddingTop - view.paddingBottom,
view.measuredWidth - view.paddingLeft - view.paddingRight)
}
DIRECTION_BOTTOM -> {
setSize(view.measuredWidth - view.paddingLeft - view.paddingRight,
view.measuredHeight - view.paddingTop - view.paddingBottom)
}
}
}
override fun draw(c: Canvas): Boolean {
ensureSize()
val restore = c.save()
when (direction) {
DIRECTION_LEFT -> {
c.translate(view.paddingBottom.toFloat(), 0f)
}
DIRECTION_TOP -> {
c.translate(view.paddingLeft.toFloat(), view.paddingTop.toFloat())
}
DIRECTION_RIGHT -> {
c.translate(-view.paddingTop.toFloat(), 0f)
}
DIRECTION_BOTTOM -> {
c.translate(view.paddingRight.toFloat(), view.paddingBottom.toFloat())
}
}
val res = super.draw(c)
c.restoreToCount(restore)
return res
}
}
}
}

View File

@@ -7,9 +7,11 @@ import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import android.content.Intent import android.content.Intent
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.ComponentInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.PackageManager.* import android.content.pm.PackageManager.*
import android.content.pm.ServiceInfo
import android.content.pm.ServiceInfo.FLAG_ISOLATED_PROCESS
import android.content.pm.ServiceInfo.FLAG_USE_APP_ZYGOTE
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import android.database.Cursor import android.database.Cursor
@@ -57,32 +59,10 @@ import java.lang.reflect.Array as JArray
val packageName: String get() = get<Context>().packageName val packageName: String get() = get<Context>().packageName
val ApplicationInfo.processes: List<String> @SuppressLint("InlinedApi") get() { val ServiceInfo.isIsolated get() = (flags and FLAG_ISOLATED_PROCESS) != 0
val pm = get<PackageManager>()
val appProcessName = processName ?: packageName @get:SuppressLint("InlinedApi")
val baseFlag = MATCH_DISABLED_COMPONENTS or MATCH_UNINSTALLED_PACKAGES val ServiceInfo.useAppZygote get() = (flags and FLAG_USE_APP_ZYGOTE) != 0
val packageInfo = try {
val request = GET_ACTIVITIES or GET_SERVICES or GET_RECEIVERS or GET_PROVIDERS
pm.getPackageInfo(packageName, baseFlag or request)
} catch (e: NameNotFoundException) { // EdXposed hooked, issue#3276
return listOf(appProcessName)
} catch (e: Exception) {
// Exceed binder data transfer limit, fetch each component type separately
pm.getPackageInfo(packageName, baseFlag).apply {
runCatching { activities = pm.getPackageInfo(packageName, GET_ACTIVITIES).activities }
runCatching { services = pm.getPackageInfo(packageName, GET_SERVICES).services }
runCatching { receivers = pm.getPackageInfo(packageName, GET_RECEIVERS).receivers }
runCatching { providers = pm.getPackageInfo(packageName, GET_PROVIDERS).providers }
}
}
fun Array<out ComponentInfo>.processNames() = map { it.processName ?: appProcessName }
return with(packageInfo) {
activities?.processNames().orEmpty() +
services?.processNames().orEmpty() +
receivers?.processNames().orEmpty() +
providers?.processNames().orEmpty()
}
}
fun Context.rawResource(id: Int) = resources.openRawResource(id) fun Context.rawResource(id: Int) = resources.openRawResource(id)

View File

@@ -10,7 +10,6 @@ import android.view.WindowManager
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.view.forEach import androidx.core.view.forEach
import androidx.core.view.setPadding
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.navigation.NavDirections import androidx.navigation.NavDirections
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
@@ -26,9 +25,9 @@ import com.topjohnwu.magisk.ui.home.HomeFragmentDirections
import com.topjohnwu.magisk.utils.HideBottomViewOnScrollBehavior import com.topjohnwu.magisk.utils.HideBottomViewOnScrollBehavior
import com.topjohnwu.magisk.utils.HideTopViewOnScrollBehavior import com.topjohnwu.magisk.utils.HideTopViewOnScrollBehavior
import com.topjohnwu.magisk.utils.HideableBehavior import com.topjohnwu.magisk.utils.HideableBehavior
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
class MainViewModel : BaseViewModel() class MainViewModel : BaseViewModel()
@@ -39,14 +38,6 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
override val viewModel by viewModel<MainViewModel>() override val viewModel by viewModel<MainViewModel>()
override val navHost: Int = R.id.main_nav_host override val navHost: Int = R.id.main_nav_host
//This temporarily fixes unwanted feature of BottomNavigationView - where the view applies
//padding on itself given insets are not consumed beforehand. Unfortunately the listener
//implementation doesn't favor us against the design library, so on re-create it's often given
//upper hand.
private val navObserver = ViewTreeObserver.OnGlobalLayoutListener {
binding.mainNavigation.setPadding(0)
}
private var isRootFragment = true private var isRootFragment = true
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -100,8 +91,6 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
(currentFragment as? ReselectionTarget)?.onReselected() (currentFragment as? ReselectionTarget)?.onReselected()
} }
binding.mainNavigation.viewTreeObserver.addOnGlobalLayoutListener(navObserver)
val section = if (intent.action == ACTION_APPLICATION_PREFERENCES) Const.Nav.SETTINGS val section = if (intent.action == ACTION_APPLICATION_PREFERENCES) Const.Nav.SETTINGS
else intent.getStringExtra(Const.Key.OPEN_SECTION) else intent.getStringExtra(Const.Key.OPEN_SECTION)
getScreen(section)?.navigate() getScreen(section)?.navigate()
@@ -116,16 +105,11 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
binding.mainNavigation.menu.apply { binding.mainNavigation.menu.apply {
findItem(R.id.superuserFragment)?.isEnabled = Info.env.isActive findItem(R.id.superuserFragment)?.isEnabled = Utils.showSuperUser()
findItem(R.id.logFragment)?.isEnabled = Info.env.isActive findItem(R.id.logFragment)?.isEnabled = Info.env.isActive
} }
} }
override fun onDestroy() {
binding.mainNavigation.viewTreeObserver.removeOnGlobalLayoutListener(navObserver)
super.onDestroy()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
android.R.id.home -> onBackPressed() android.R.id.home -> onBackPressed()

View File

@@ -13,18 +13,17 @@ import com.topjohnwu.magisk.arch.itemBindingOf
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.tasks.FlashZip import com.topjohnwu.magisk.core.tasks.FlashZip
import com.topjohnwu.magisk.core.tasks.MagiskInstaller import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.databinding.RvBindingAdapter import com.topjohnwu.magisk.databinding.RvBindingAdapter
import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ktx.* import com.topjohnwu.magisk.ktx.*
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.superuser.CallbackList import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class FlashViewModel( class FlashViewModel(
args: FlashFragmentArgs, args: FlashFragmentArgs,
@@ -106,18 +105,16 @@ class FlashViewModel(
} }
private fun savePressed() = withExternalRW { private fun savePressed() = withExternalRW {
viewModelScope.launch { viewModelScope.launch(Dispatchers.IO) {
withContext(Dispatchers.IO) { val name = "magisk_install_log_%s.log".format(now.toTime(timeFormatStandard))
val name = Const.MAGISK_INSTALL_LOG_FILENAME.format(now.toTime(timeFormatStandard)) val file = MediaStoreUtils.getFile(name, true)
val file = MediaStoreUtils.getFile(name) file.uri.outputStream().bufferedWriter().use { writer ->
file.uri.outputStream().bufferedWriter().use { writer -> logItems.forEach {
logItems.forEach { writer.write(it)
writer.write(it) writer.newLine()
writer.newLine()
}
} }
SnackbarEvent(file.toString()).publish()
} }
SnackbarEvent(file.toString()).publish()
} }
} }

View File

@@ -1,47 +0,0 @@
package com.topjohnwu.magisk.ui.hide
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.ktx.getLabel
class HideTarget(line: String) {
val packageName: String
val process: String
init {
val split = line.split(Regex("\\|"), 2)
packageName = split[0]
process = split.getOrElse(1) { packageName }
}
}
class HideAppInfo(info: ApplicationInfo, pm: PackageManager)
: ApplicationInfo(info), Comparable<HideAppInfo> {
val label = info.getLabel(pm)
val iconImage: Drawable = info.loadIcon(pm)
override fun compareTo(other: HideAppInfo) = comparator.compare(this, other)
companion object {
private val comparator = compareBy<HideAppInfo>(
{ it.label.toLowerCase(currentLocale) },
{ it.packageName }
)
}
}
data class HideProcessInfo(
val name: String,
val packageName: String,
val isHidden: Boolean
)
class HideAppTarget(
val info: HideAppInfo,
val processes: List<HideProcessInfo>
) : Comparable<HideAppTarget> {
override fun compareTo(other: HideAppTarget) = compareValuesBy(this, other) { it.info }
}

View File

@@ -12,6 +12,9 @@ import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.databinding.FragmentHideMd2Binding import com.topjohnwu.magisk.databinding.FragmentHideMd2Binding
import com.topjohnwu.magisk.ktx.addSimpleItemDecoration
import com.topjohnwu.magisk.ktx.addVerticalPadding
import com.topjohnwu.magisk.ktx.fixEdgeEffect
import com.topjohnwu.magisk.ktx.hideKeyboard import com.topjohnwu.magisk.ktx.hideKeyboard
import com.topjohnwu.magisk.utils.MotionRevealHelper import com.topjohnwu.magisk.utils.MotionRevealHelper
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
@@ -49,6 +52,21 @@ class HideFragment : BaseUIFragment<HideViewModel, FragmentHideMd2Binding>() {
} }
}) })
val resource = requireContext().resources
val l_50 = resource.getDimensionPixelSize(R.dimen.l_50)
val l1 = resource.getDimensionPixelSize(R.dimen.l1)
binding.hideContent.addVerticalPadding(
l_50,
l1 + resource.getDimensionPixelSize(R.dimen.internal_action_bar_size)
)
binding.hideContent.addSimpleItemDecoration(
left = l1,
top = l_50,
right = l1,
bottom = l_50,
)
binding.hideContent.fixEdgeEffect()
val lama = binding.hideContent.layoutManager ?: return val lama = binding.hideContent.layoutManager ?: return
lama.isAutoMeasureEnabled = false lama.isAutoMeasureEnabled = false
} }

View File

@@ -0,0 +1,105 @@
package com.topjohnwu.magisk.ui.hide
import android.annotation.SuppressLint
import android.content.pm.ApplicationInfo
import android.content.pm.ComponentInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.*
import android.content.pm.ServiceInfo
import android.graphics.drawable.Drawable
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.ktx.getLabel
import com.topjohnwu.magisk.ktx.isIsolated
import com.topjohnwu.magisk.ktx.useAppZygote
class CmdlineHiddenItem(line: String) {
val packageName: String
val process: String
init {
val split = line.split(Regex("\\|"), 2)
packageName = split[0]
process = split.getOrElse(1) { packageName }
}
}
const val ISOLATED_MAGIC = "isolated"
@SuppressLint("InlinedApi")
class HideAppInfo(info: ApplicationInfo, pm: PackageManager, hideList: List<CmdlineHiddenItem>)
: ApplicationInfo(info), Comparable<HideAppInfo> {
val label = info.getLabel(pm)
val iconImage: Drawable = info.loadIcon(pm)
val processes = fetchProcesses(pm, hideList)
override fun compareTo(other: HideAppInfo) = comparator.compare(this, other)
private fun fetchProcesses(
pm: PackageManager,
hideList: List<CmdlineHiddenItem>
): List<HideProcessInfo> {
// Fetch full PackageInfo
val baseFlag = MATCH_DISABLED_COMPONENTS or MATCH_UNINSTALLED_PACKAGES
val packageInfo = try {
val request = GET_ACTIVITIES or GET_SERVICES or GET_RECEIVERS or GET_PROVIDERS
pm.getPackageInfo(packageName, baseFlag or request)
} catch (e: NameNotFoundException) {
// EdXposed hooked, issue#3276
return emptyList()
} catch (e: Exception) {
// Exceed binder data transfer limit, fetch each component type separately
pm.getPackageInfo(packageName, baseFlag).apply {
runCatching { activities = pm.getPackageInfo(packageName, baseFlag or GET_ACTIVITIES).activities }
runCatching { services = pm.getPackageInfo(packageName, baseFlag or GET_SERVICES).services }
runCatching { receivers = pm.getPackageInfo(packageName, baseFlag or GET_RECEIVERS).receivers }
runCatching { providers = pm.getPackageInfo(packageName, baseFlag or GET_PROVIDERS).providers }
}
}
val hidden = hideList.filter { it.packageName == packageName || it.packageName == ISOLATED_MAGIC }
fun createProcess(name: String, pkg: String = packageName): HideProcessInfo {
return HideProcessInfo(name, pkg, hidden.any { it.process == name })
}
var haveAppZygote = false
fun Array<out ComponentInfo>.processes() = map { createProcess(it.processName) }
fun Array<ServiceInfo>.processes() = map {
if (it.isIsolated) {
if (it.useAppZygote) {
haveAppZygote = true
// Using app zygote, don't need to track the process
null
} else {
createProcess("${it.processName}:${it.name}", ISOLATED_MAGIC)
}
} else {
createProcess(it.processName)
}
}
return with(packageInfo) {
activities?.processes().orEmpty() +
services?.processes().orEmpty() +
receivers?.processes().orEmpty() +
providers?.processes().orEmpty() +
listOf(if (haveAppZygote) createProcess("${processName}_zygote") else null)
}.filterNotNull().distinctBy { it.name }.sortedBy { it.name }
}
companion object {
private val comparator = compareBy<HideAppInfo>(
{ it.label.toLowerCase(currentLocale) },
{ it.packageName }
)
}
}
data class HideProcessInfo(
val name: String,
val packageName: String,
var isHidden: Boolean
) {
val isIsolated get() = name == ISOLATED_MAGIC
val isAppZygote get() = name.endsWith("_zygote")
}

View File

@@ -12,14 +12,13 @@ import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlin.math.roundToInt import kotlin.math.roundToInt
class HideItem( class HideRvItem(
app: HideAppTarget val info: HideAppInfo
) : ObservableItem<HideItem>(), Comparable<HideItem> { ) : ObservableItem<HideRvItem>(), Comparable<HideRvItem> {
override val layoutRes = R.layout.item_hide_md2 override val layoutRes get() = R.layout.item_hide_md2
val info = app.info val processes = info.processes.map { HideProcessRvItem(it) }
val processes = app.processes.map { HideProcessItem(it) }
@get:Bindable @get:Bindable
var isExpanded = false var isExpanded = false
@@ -41,11 +40,10 @@ class HideItem(
if (value == true) { if (value == true) {
processes processes
.filterNot { it.isHidden } .filterNot { it.isHidden }
.filter { isExpanded || it.process.name == it.process.packageName } .filter { isExpanded || it.defaultSelection }
} else { } else {
processes processes
.filter { it.isHidden } .filter { it.isHidden }
.filter { isExpanded || it.process.name == it.process.packageName }
}.forEach { it.toggle() } }.forEach { it.toggle() }
} }
@@ -69,14 +67,19 @@ class HideItem(
else -> null else -> null
} }
} else { } else {
processes.find { it.isHidden && it.process.name == it.process.packageName } != null val defaultProcesses = processes.filter { it.defaultSelection }
when (defaultProcesses.count { it.isHidden }) {
0 -> false
defaultProcesses.size -> true
else -> null
}
} }
} }
override fun compareTo(other: HideItem) = comparator.compare(this, other) override fun compareTo(other: HideRvItem) = comparator.compare(this, other)
companion object { companion object {
private val comparator = compareBy<HideItem>( private val comparator = compareBy<HideRvItem>(
{ it.itemsChecked == 0 }, { it.itemsChecked == 0 },
{ it.info } { it.info }
) )
@@ -84,16 +87,17 @@ class HideItem(
} }
class HideProcessItem( class HideProcessRvItem(
val process: HideProcessInfo val process: HideProcessInfo
) : ObservableItem<HideProcessItem>() { ) : ObservableItem<HideProcessRvItem>() {
override val layoutRes = R.layout.item_hide_process_md2 override val layoutRes get() = R.layout.item_hide_process_md2
@get:Bindable @get:Bindable
var isHidden = process.isHidden var isHidden
set(value) = set(value, field, { field = it }, BR.hidden) { get() = process.isHidden
val arg = if (isHidden) "add" else "rm" set(value) = set(value, process.isHidden, { process.isHidden = it }, BR.hidden) {
val arg = if (it) "add" else "rm"
val (name, pkg) = process val (name, pkg) = process
Shell.su("magiskhide --$arg $pkg $name").submit() Shell.su("magiskhide --$arg $pkg $name").submit()
} }
@@ -102,7 +106,10 @@ class HideProcessItem(
isHidden = !isHidden isHidden = !isHidden
} }
override fun contentSameAs(other: HideProcessItem) = process == other.process val defaultSelection get() =
override fun itemSameAs(other: HideProcessItem) = process.name == other.process.name process.isIsolated || process.isAppZygote || process.name == process.packageName
override fun contentSameAs(other: HideProcessRvItem) = process == other.process
override fun itemSameAs(other: HideProcessRvItem) = process.name == other.process.name
} }

View File

@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.ui.hide
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
import android.os.Process import android.os.Process
import androidx.databinding.Bindable import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
@@ -14,7 +15,6 @@ import com.topjohnwu.magisk.arch.itemBindingOf
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.ktx.get import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.ktx.packageName import com.topjohnwu.magisk.ktx.packageName
import com.topjohnwu.magisk.ktx.processes
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@@ -45,11 +45,11 @@ class HideViewModel : BaseViewModel(), Queryable {
submitQuery() submitQuery()
} }
val items = filterableListOf<HideItem>() val items = filterableListOf<HideRvItem>()
val itemBinding = itemBindingOf<HideItem> { val itemBinding = itemBindingOf<HideRvItem> {
it.bindExtra(BR.viewModel, this) it.bindExtra(BR.viewModel, this)
} }
val itemInternalBinding = itemBindingOf<HideProcessItem> { val itemInternalBinding = itemBindingOf<HideProcessRvItem> {
it.bindExtra(BR.viewModel, this) it.bindExtra(BR.viewModel, this)
} }
@@ -62,14 +62,13 @@ class HideViewModel : BaseViewModel(), Queryable {
state = State.LOADING state = State.LOADING
val (apps, diff) = withContext(Dispatchers.Default) { val (apps, diff) = withContext(Dispatchers.Default) {
val pm = get<PackageManager>() val pm = get<PackageManager>()
val hides = Shell.su("magiskhide --ls").exec().out.map { HideTarget(it) } val hideList = Shell.su("magiskhide --ls").exec().out.map { CmdlineHiddenItem(it) }
val apps = pm.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES) val apps = pm.getInstalledApplications(MATCH_UNINSTALLED_PACKAGES)
.asSequence() .asSequence()
.filter { it.enabled && !blacklist.contains(it.packageName) } .filter { it.enabled && !blacklist.contains(it.packageName) }
.map { HideAppInfo(it, pm) } .map { HideAppInfo(it, pm, hideList) }
.map { createTarget(it, hides) }
.filter { it.processes.isNotEmpty() } .filter { it.processes.isNotEmpty() }
.map { HideItem(it) } .map { HideRvItem(it) }
.toList() .toList()
.sorted() .sorted()
apps to items.calculateDiff(apps) apps to items.calculateDiff(apps)
@@ -80,18 +79,6 @@ class HideViewModel : BaseViewModel(), Queryable {
// --- // ---
private fun createTarget(info: HideAppInfo, hideList: List<HideTarget>): HideAppTarget {
val pkg = info.packageName
val hidden = hideList.filter { it.packageName == pkg }
val processNames = info.processes.distinct()
val processes = processNames.map { name ->
HideProcessInfo(name, pkg, hidden.any { name == it.process })
}
return HideAppTarget(info, processes)
}
// ---
override fun query() { override fun query() {
items.filter { items.filter {
fun showHidden() = it.itemsChecked != 0 fun showHidden() = it.itemsChecked != 0

View File

@@ -1,6 +1,5 @@
package com.topjohnwu.magisk.ui.home package com.topjohnwu.magisk.ui.home
import android.os.Build
import androidx.databinding.Bindable import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.BuildConfig
@@ -68,8 +67,7 @@ class HomeViewModel(
set(value) = set(value, field, { field = it }, BR.stateManagerProgress) set(value) = set(value, field, { field = it }, BR.stateManagerProgress)
@get:Bindable @get:Bindable
val showUninstall get() = val showUninstall get() = Info.env.isActive && state != State.LOADING
Info.env.magiskVersionCode > 0 && stateMagisk != MagiskState.LOADING && isConnected.get()
@get:Bindable @get:Bindable
val showSafetyNet get() = Info.hasGMS && isConnected.get() val showSafetyNet get() = Info.hasGMS && isConnected.get()
@@ -82,8 +80,6 @@ class HomeViewModel(
override fun refresh() = viewModelScope.launch { override fun refresh() = viewModelScope.launch {
state = State.LOADING state = State.LOADING
notifyPropertyChanged(BR.showUninstall)
notifyPropertyChanged(BR.showSafetyNet)
svc.fetchUpdate()?.apply { svc.fetchUpdate()?.apply {
state = State.LOADED state = State.LOADED
stateMagisk = when { stateMagisk = when {
@@ -93,7 +89,6 @@ class HomeViewModel(
} }
stateManager = when { stateManager = when {
!app.isUpdateChannelCorrect && isConnected.get() -> MagiskState.NOT_INSTALLED
app.isObsolete -> MagiskState.OBSOLETE app.isObsolete -> MagiskState.OBSOLETE
else -> MagiskState.UP_TO_DATE else -> MagiskState.UP_TO_DATE
} }
@@ -107,6 +102,8 @@ class HomeViewModel(
ensureEnv() ensureEnv()
} }
} ?: apply { state = State.LOADING_FAILED } } ?: apply { state = State.LOADING_FAILED }
notifyPropertyChanged(BR.showUninstall)
notifyPropertyChanged(BR.showSafetyNet)
} }
val showTest = false val showTest = false
@@ -127,14 +124,18 @@ class HomeViewModel(
fun onDeletePressed() = UninstallDialog().publish() fun onDeletePressed() = UninstallDialog().publish()
fun onManagerPressed() = fun onManagerPressed() = when (state) {
if (isConnected.get()) ManagerInstallDialog().publish() State.LOADED -> ManagerInstallDialog().publish()
else SnackbarEvent(R.string.no_connection).publish() State.LOADING -> SnackbarEvent(R.string.loading).publish()
else -> SnackbarEvent(R.string.no_connection).publish()
}
fun onMagiskPressed() = if (isConnected.get()) withExternalRW { fun onMagiskPressed() = when (state) {
HomeFragmentDirections.actionHomeFragmentToInstallFragment().publish() State.LOADED -> withExternalRW {
} else { HomeFragmentDirections.actionHomeFragmentToInstallFragment().publish()
SnackbarEvent(R.string.no_connection).publish() }
State.LOADING -> SnackbarEvent(R.string.loading).publish()
else -> SnackbarEvent(R.string.no_connection).publish()
} }
fun onSafetyNetPressed() = fun onSafetyNetPressed() =
@@ -150,17 +151,7 @@ class HomeViewModel(
MagiskState.NOT_INSTALLED, MagiskState.NOT_INSTALLED,
MagiskState.LOADING MagiskState.LOADING
) )
if (invalidStates.any { it == stateMagisk } || shownDialog) return
// Don't bother checking env when magisk is not installed, loading or already has been shown
if (
invalidStates.any { it == stateMagisk } ||
shownDialog ||
// don't care for emulators either
Build.DEVICE.orEmpty().contains("generic") ||
Build.PRODUCT.orEmpty().contains("generic")
) {
return
}
val result = Shell.su("env_check").await() val result = Shell.su("env_check").await()
if (!result.isSuccess) { if (!result.isSuccess) {
@@ -171,8 +162,6 @@ class HomeViewModel(
private val MagiskJson.isObsolete private val MagiskJson.isObsolete
get() = Info.env.isActive && Info.env.magiskVersionCode < versionCode get() = Info.env.isActive && Info.env.magiskVersionCode < versionCode
private val ManagerJson.isUpdateChannelCorrect
get() = versionCode > 0
private val ManagerJson.isObsolete private val ManagerJson.isObsolete
get() = BuildConfig.VERSION_CODE < versionCode get() = BuildConfig.VERSION_CODE < versionCode

View File

@@ -0,0 +1,88 @@
package com.topjohnwu.magisk.ui.inflater
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.view.InflateException
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AppCompatDelegate
import androidx.collection.SimpleArrayMap
import java.lang.reflect.Constructor
open class LayoutInflaterFactory(private val delegate: AppCompatDelegate) : LayoutInflater.Factory2 {
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
return onCreateView(null, name, context, attrs)
}
override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? {
val view = delegate.createView(parent, name, context, attrs)
?: LayoutInflaterFactoryDefaultImpl.createViewFromTag(context, name, attrs)
onViewCreated(view, parent, name, context, attrs)
return view
}
open fun onViewCreated(view: View?, parent: View?, name: String, context: Context, attrs: AttributeSet) {
if (view == null) return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
WindowInsetsHelper.attach(view, attrs)
}
}
}
private object LayoutInflaterFactoryDefaultImpl {
private val constructorSignature = arrayOf(
Context::class.java, AttributeSet::class.java)
private val classPrefixList = arrayOf(
"android.widget.",
"android.view.",
"android.webkit."
)
private val constructorMap = SimpleArrayMap<String, Constructor<out View?>>()
fun createViewFromTag(context: Context, name: String, attrs: AttributeSet): View? {
var name = name
if (name == "view") {
name = attrs.getAttributeValue(null, "class")
}
return try {
if (-1 == name.indexOf('.')) {
for (prefix in classPrefixList) {
val view: View? = createViewByPrefix(context, name, attrs, prefix)
if (view != null) {
return view
}
}
null
} else {
createViewByPrefix(context, name, attrs, null)
}
} catch (e: Exception) {
null
}
}
@Throws(ClassNotFoundException::class, InflateException::class)
private fun createViewByPrefix(context: Context, name: String, attrs: AttributeSet, prefix: String?): View? {
var constructor = constructorMap[name]
return try {
if (constructor == null) { // Class not found in the cache, see if it's real, and try to add it
val clazz = Class.forName(
if (prefix != null) prefix + name else name,
false,
context.classLoader).asSubclass(View::class.java)
constructor = clazz.getConstructor(*constructorSignature)
constructorMap.put(name, constructor)
}
constructor!!.isAccessible = true
constructor.newInstance(context, attrs)
} catch (e: Exception) {
null
}
}
}

View File

@@ -0,0 +1,284 @@
@file:Suppress("unused")
package com.topjohnwu.magisk.ui.inflater
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.graphics.Rect
import android.os.Build
import android.util.AttributeSet
import android.view.Gravity.*
import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.Insets
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.topjohnwu.magisk.R
private typealias ApplyInsetsCallback<T> = (insets: Insets, left: Boolean, top: Boolean, right: Boolean, bottom: Boolean) -> T
private class ApplyInsets(private val out: Rect) : ApplyInsetsCallback<Unit> {
override fun invoke(insets: Insets, left: Boolean, top: Boolean, right: Boolean, bottom: Boolean) {
out.left += if (left) insets.left else 0
out.top += if (top) insets.top else 0
out.right += if (right) insets.right else 0
out.bottom += if (bottom) insets.bottom else 0
}
}
private class ConsumeInsets : ApplyInsetsCallback<Insets> {
override fun invoke(insets: Insets, left: Boolean, top: Boolean, right: Boolean, bottom: Boolean): Insets {
val insetsLeft = if (left) 0 else insets.left
val insetsTop = if (top) 0 else insets.top
val insetsRight = if (right) 0 else insets.right
val insetsBottom = if (bottom) 0 else insets.bottom
return Insets.of(insetsLeft, insetsTop, insetsRight, insetsBottom)
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
open class WindowInsetsHelper private constructor(
private val view: View,
private val fitSystemWindows: Int,
private val layout_fitsSystemWindowsInsets: Int,
private val consumeSystemWindows: Int) : OnApplyWindowInsetsListener {
internal var initialPaddingLeft: Int = view.paddingLeft
internal var initialPaddingTop: Int = view.paddingTop
internal var initialPaddingRight: Int = view.paddingRight
internal var initialPaddingBottom: Int = view.paddingBottom
private var initialMargin = false
internal var initialMarginLeft: Int = 0
internal var initialMarginTop: Int = 0
internal var initialMarginRight: Int = 0
internal var initialMarginBottom: Int = 0
internal var initialMarginStart: Int = 0
internal var initialMarginEnd: Int = 0
private var lastInsets: WindowInsetsCompat? = null
open fun setInitialPadding(left: Int, top: Int, right: Int, bottom: Int) {
initialPaddingLeft = left
initialPaddingTop = top
initialPaddingRight = right
initialPaddingBottom = bottom
lastInsets?.let { applyWindowInsets(it) }
}
open fun setInitialPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) {
val isRTL = view.layoutDirection == View.LAYOUT_DIRECTION_RTL
if (isRTL) {
setInitialPadding(start, top, end, bottom)
} else {
setInitialPadding(start, top, end, bottom)
}
}
open fun setInitialMargin(left: Int, top: Int, right: Int, bottom: Int) {
initialPaddingLeft = left
initialPaddingTop = top
initialPaddingRight = right
initialPaddingBottom = bottom
lastInsets?.let { applyWindowInsets(it) }
}
open fun setInitialMarginRelative(start: Int, top: Int, end: Int, bottom: Int) {
initialMarginStart = start
initialMarginTop = top
initialMarginEnd = end
initialMarginBottom = bottom
lastInsets?.let { applyWindowInsets(it) }
}
@SuppressLint("RtlHardcoded")
private fun <T> applyInsets(insets: Insets, fit: Int, callback: ApplyInsetsCallback<T>): T {
val relativeMode = (fit and RELATIVE_LAYOUT_DIRECTION) == RELATIVE_LAYOUT_DIRECTION
val isRTL = view.layoutDirection == View.LAYOUT_DIRECTION_RTL
val left: Boolean
val top = fit and TOP == TOP
val right: Boolean
val bottom = fit and BOTTOM == BOTTOM
if (relativeMode) {
val start = fit and START == START
val end = fit and END == END
left = (!isRTL && start) || (isRTL && end)
right = (!isRTL && end) || (isRTL && start)
} else {
left = fit and LEFT == LEFT
right = fit and RIGHT == RIGHT
}
return callback.invoke(insets, left, top, right, bottom)
}
private fun applyWindowInsets(windowInsets: WindowInsetsCompat): WindowInsetsCompat {
if (fitSystemWindows != 0) {
val padding = Rect(initialPaddingLeft, initialPaddingTop, initialPaddingRight, initialPaddingBottom)
applyInsets(windowInsets.systemWindowInsets, fitSystemWindows, ApplyInsets(padding))
view.setPadding(padding.left, padding.top, padding.right, padding.bottom)
}
if (layout_fitsSystemWindowsInsets != 0) {
if (!initialMargin) {
initialMarginLeft = (view.layoutParams as? ViewGroup.MarginLayoutParams)?.leftMargin ?: 0
initialMarginTop = (view.layoutParams as? ViewGroup.MarginLayoutParams)?.topMargin ?: 0
initialMarginRight = (view.layoutParams as? ViewGroup.MarginLayoutParams)?.rightMargin ?: 0
initialMarginBottom = (view.layoutParams as? ViewGroup.MarginLayoutParams)?.bottomMargin ?: 0
initialMarginStart = (view.layoutParams as? ViewGroup.MarginLayoutParams)?.marginStart ?: 0
initialMarginEnd = (view.layoutParams as? ViewGroup.MarginLayoutParams)?.marginEnd ?: 0
initialMargin = true
}
val margin = if ((layout_fitsSystemWindowsInsets and RELATIVE_LAYOUT_DIRECTION) == RELATIVE_LAYOUT_DIRECTION)
Rect(initialMarginLeft, initialMarginTop, initialMarginRight, initialMarginBottom)
else
Rect(initialMarginStart, initialMarginTop, initialMarginEnd, initialMarginBottom)
applyInsets(windowInsets.systemWindowInsets, layout_fitsSystemWindowsInsets, ApplyInsets(margin))
val lp = view.layoutParams
if (lp is ViewGroup.MarginLayoutParams) {
lp.topMargin = margin.top
lp.bottomMargin = margin.bottom
if ((layout_fitsSystemWindowsInsets and RELATIVE_LAYOUT_DIRECTION) == RELATIVE_LAYOUT_DIRECTION) {
lp.marginStart = margin.left
lp.marginEnd = margin.right
} else {
lp.leftMargin = margin.left
lp.rightMargin = margin.right
}
view.layoutParams = lp
}
}
val systemWindowInsets = if (consumeSystemWindows != 0) applyInsets(windowInsets.systemWindowInsets, consumeSystemWindows, ConsumeInsets()) else windowInsets.systemWindowInsets
return WindowInsetsCompat.Builder(windowInsets)
.setSystemWindowInsets(systemWindowInsets)
.build()
}
override fun onApplyWindowInsets(view: View, insets: WindowInsetsCompat): WindowInsetsCompat {
if (lastInsets == insets) {
return insets
}
lastInsets = insets
return applyWindowInsets(insets)
}
companion object {
@JvmStatic
fun attach(view: View, attrs: AttributeSet) {
val a = view.context.obtainStyledAttributes(attrs, R.styleable.WindowInsetsHelper, 0, 0)
val edgeToEdge = a.getBoolean(R.styleable.WindowInsetsHelper_edgeToEdge, false)
val fitsSystemWindowsInsets = a.getInt(R.styleable.WindowInsetsHelper_fitsSystemWindowsInsets, 0)
val layout_fitsSystemWindowsInsets = a.getInt(R.styleable.WindowInsetsHelper_layout_fitsSystemWindowsInsets, 0)
val consumeSystemWindowsInsets = a.getInt(R.styleable.WindowInsetsHelper_consumeSystemWindowsInsets, 0)
a.recycle()
attach(view, edgeToEdge, fitsSystemWindowsInsets, layout_fitsSystemWindowsInsets, consumeSystemWindowsInsets)
}
@JvmStatic
fun attach(view: View, edgeToEdge: Boolean, fitsSystemWindowsInsets: Int, layout_fitsSystemWindowsInsets: Int, consumeSystemWindowsInsets: Int) {
if (edgeToEdge) {
view.systemUiVisibility = (view.systemUiVisibility
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)
}
if (fitsSystemWindowsInsets == 0 && layout_fitsSystemWindowsInsets == 0 && consumeSystemWindowsInsets == 0) {
return
}
val listener = WindowInsetsHelper(view, fitsSystemWindowsInsets, layout_fitsSystemWindowsInsets, consumeSystemWindowsInsets)
ViewCompat.setOnApplyWindowInsetsListener(view, listener)
view.setTag(R.id.tag_rikka_material_WindowInsetsHelper, listener)
if (!view.isAttachedToWindow) {
view.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) {
v.removeOnAttachStateChangeListener(this)
v.requestApplyInsets()
}
override fun onViewDetachedFromWindow(v: View) = Unit
})
}
}
}
}
val View.windowInsetsHelper: WindowInsetsHelper?
get() {
val value = getTag(R.id.tag_rikka_material_WindowInsetsHelper)
return if (value is WindowInsetsHelper) value else null
}
val View.initialPaddingLeft: Int
get() = windowInsetsHelper?.initialPaddingLeft ?: 0
val View.initialPaddingTop: Int
get() = windowInsetsHelper?.initialPaddingTop ?: 0
val View.initialPaddingRight: Int
get() = windowInsetsHelper?.initialPaddingRight ?: 0
val View.initialPaddingBottom: Int
get() = windowInsetsHelper?.initialPaddingBottom ?: 0
val View.initialPaddingStart: Int
get() = if (layoutDirection == View.LAYOUT_DIRECTION_RTL) initialPaddingRight else initialPaddingLeft
val View.initialPaddingEnd: Int
get() = if (layoutDirection == View.LAYOUT_DIRECTION_RTL) initialPaddingLeft else initialPaddingRight
fun View.setInitialPadding(left: Int, top: Int, right: Int, bottom: Int) {
windowInsetsHelper?.setInitialPadding(left, top, right, bottom)
}
fun View.setInitialPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) {
windowInsetsHelper?.setInitialPaddingRelative(start, top, end, bottom)
}
val View.initialMarginLeft: Int
get() = windowInsetsHelper?.initialMarginLeft ?: 0
val View.initialMarginTop: Int
get() = windowInsetsHelper?.initialMarginTop ?: 0
val View.initialMarginRight: Int
get() = windowInsetsHelper?.initialMarginRight ?: 0
val View.initialMarginBottom: Int
get() = windowInsetsHelper?.initialMarginBottom ?: 0
val View.initialMarginStart: Int
get() = windowInsetsHelper?.initialMarginStart ?: 0
val View.initialMarginEnd: Int
get() = windowInsetsHelper?.initialMarginEnd ?: 0
fun View.setInitialMargin(left: Int, top: Int, right: Int, bottom: Int) {
windowInsetsHelper?.setInitialMargin(left, top, right, bottom)
}
fun View.setInitialMarginRelative(start: Int, top: Int, end: Int, bottom: Int) {
windowInsetsHelper?.setInitialMarginRelative(start, top, end, bottom)
}

View File

@@ -9,6 +9,9 @@ import androidx.core.view.isVisible
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding
import com.topjohnwu.magisk.ktx.addSimpleItemDecoration
import com.topjohnwu.magisk.ktx.addVerticalPadding
import com.topjohnwu.magisk.ktx.fixEdgeEffect
import com.topjohnwu.magisk.ui.MainActivity import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.utils.MotionRevealHelper import com.topjohnwu.magisk.utils.MotionRevealHelper
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
@@ -42,6 +45,21 @@ class LogFragment : BaseUIFragment<LogViewModel, FragmentLogMd2Binding>() {
binding.logFilterToggle.setOnClickListener { binding.logFilterToggle.setOnClickListener {
isMagiskLogVisible = true isMagiskLogVisible = true
} }
val resource = requireContext().resources
val l_50 = resource.getDimensionPixelSize(R.dimen.l_50)
val l1 = resource.getDimensionPixelSize(R.dimen.l1)
binding.logFilterSuperuser.logSuperuser.addVerticalPadding(
0,
l1
)
binding.logFilterSuperuser.logSuperuser.addSimpleItemDecoration(
left = l1,
top = l_50,
right = l1,
bottom = l_50,
)
binding.logFilterSuperuser.logSuperuser.fixEdgeEffect()
} }

View File

@@ -3,20 +3,24 @@ package com.topjohnwu.magisk.ui.log
import androidx.databinding.Bindable import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.arch.diffListOf import com.topjohnwu.magisk.arch.diffListOf
import com.topjohnwu.magisk.arch.itemBindingOf import com.topjohnwu.magisk.arch.itemBindingOf
import com.topjohnwu.magisk.data.repository.LogRepository import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.core.utils.MediaStoreUtils import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.data.repository.LogRepository
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ktx.now
import com.topjohnwu.magisk.ktx.timeFormatStandard
import com.topjohnwu.magisk.ktx.toTime
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import com.topjohnwu.magisk.view.TextItem import com.topjohnwu.magisk.view.TextItem
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.*
class LogViewModel( class LogViewModel(
private val repo: LogRepository private val repo: LogRepository
@@ -54,14 +58,23 @@ class LogViewModel(
fun saveMagiskLog() = withExternalRW { fun saveMagiskLog() = withExternalRW {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val now = Calendar.getInstance() val filename = "magisk_log_%s.log".format(now.toTime(timeFormatStandard))
val filename = "magisk_log_%04d%02d%02d_%02d%02d%02d.log".format( val logFile = MediaStoreUtils.getFile(filename, true)
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1, logFile.uri.outputStream().bufferedWriter().use { file ->
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY), file.write("---System Properties---\n\n")
now.get(Calendar.MINUTE), now.get(Calendar.SECOND)
) ProcessBuilder("getprop").start()
val logFile = MediaStoreUtils.getFile(filename) .inputStream.reader().use { it.copyTo(file) }
logFile.uri.outputStream().writer().use { it.write(consoleText) }
file.write("\n---Magisk Logs---\n")
file.write("${Info.env.magiskVersionString} (${Info.env.magiskVersionCode})\n\n")
file.write(consoleText)
file.write("\n---Manager Logs---\n")
file.write("${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})\n\n")
ProcessBuilder("logcat", "-d").start()
.inputStream.reader().use { it.copyTo(file) }
}
SnackbarEvent(logFile.toString()).publish() SnackbarEvent(logFile.toString()).publish()
} }
} }

View File

@@ -13,7 +13,7 @@ import com.topjohnwu.magisk.arch.ReselectionTarget
import com.topjohnwu.magisk.arch.ViewEvent import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.download.BaseDownloader import com.topjohnwu.magisk.core.download.BaseDownloader
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import com.topjohnwu.magisk.ktx.hideKeyboard import com.topjohnwu.magisk.ktx.*
import com.topjohnwu.magisk.ui.MainActivity import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import com.topjohnwu.magisk.utils.MotionRevealHelper import com.topjohnwu.magisk.utils.MotionRevealHelper
@@ -62,6 +62,40 @@ class ModuleFragment : BaseUIFragment<ModuleViewModel, FragmentModuleMd2Binding>
if (newState != RecyclerView.SCROLL_STATE_IDLE) hideKeyboard() if (newState != RecyclerView.SCROLL_STATE_IDLE) hideKeyboard()
} }
}) })
val resource = requireContext().resources
val l_50 = resource.getDimensionPixelSize(R.dimen.l_50)
val l1 = resource.getDimensionPixelSize(R.dimen.l1)
binding.moduleList.apply {
addVerticalPadding(
l_50,
l1 + l_50 + resource.getDimensionPixelSize(R.dimen.internal_action_bar_size)
)
addSimpleItemDecoration(
left = l1,
top = l_50,
right = l1,
bottom = l_50,
)
fixEdgeEffect()
post {
addInvalidateItemDecorationsObserver()
}
}
binding.moduleFilterInclude.moduleFilterList.apply {
addVerticalPadding(
l_50,
l_50
)
addSimpleItemDecoration(
left = l1,
top = l_50,
right = l1,
bottom = l_50,
)
fixEdgeEffect()
}
} }
override fun onDestroyView() { override fun onDestroyView() {

View File

@@ -158,7 +158,7 @@ sealed class BaseSettingsItem : ObservableItem<BaseSettingsItem>() {
runCatching { getStringArray(id) }.getOrDefault(emptyArray()) runCatching { getStringArray(id) }.getOrDefault(emptyArray())
override fun onPressed(view: View, callback: Callback) { override fun onPressed(view: View, callback: Callback) {
if (entries.isEmpty() || entryValues.isEmpty()) return if (entries.isEmpty()) return
super.onPressed(view, callback) super.onPressed(view, callback)
} }

View File

@@ -5,6 +5,9 @@ import android.view.View
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.databinding.FragmentSettingsMd2Binding import com.topjohnwu.magisk.databinding.FragmentSettingsMd2Binding
import com.topjohnwu.magisk.ktx.addSimpleItemDecoration
import com.topjohnwu.magisk.ktx.addVerticalPadding
import com.topjohnwu.magisk.ktx.fixEdgeEffect
import com.topjohnwu.magisk.ktx.setOnViewReadyListener import com.topjohnwu.magisk.ktx.setOnViewReadyListener
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
@@ -24,6 +27,21 @@ class SettingsFragment : BaseUIFragment<SettingsViewModel, FragmentSettingsMd2Bi
binding.settingsList.setOnViewReadyListener { binding.settingsList.setOnViewReadyListener {
binding.settingsList.scrollToPosition(0) binding.settingsList.scrollToPosition(0)
} }
val resource = requireContext().resources
val l_50 = resource.getDimensionPixelSize(R.dimen.l_50)
val l1 = resource.getDimensionPixelSize(R.dimen.l1)
binding.settingsList.addVerticalPadding(
0,
l1
)
binding.settingsList.addSimpleItemDecoration(
left = l1,
top = l_50,
right = l1,
bottom = l_50,
)
binding.settingsList.fixEdgeEffect()
} }
override fun onResume() { override fun onResume() {

View File

@@ -20,6 +20,7 @@ import com.topjohnwu.magisk.databinding.DialogSettingsAppNameBinding
import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding
import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
import com.topjohnwu.magisk.ktx.get import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.utils.TransitiveText
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.asTransitive import com.topjohnwu.magisk.utils.asTransitive
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
@@ -143,11 +144,12 @@ object UpdateChannel : BaseSettingsItem.Selector() {
set(value) = setV(value, field, { field = it }) { Config.updateChannel = it } set(value) = setV(value, field, { field = it }) { Config.updateChannel = it }
override val title = R.string.settings_update_channel_title.asTransitive() override val title = R.string.settings_update_channel_title.asTransitive()
override val entries override val entries: Array<String> = resources.getStringArray(R.array.update_channel).let {
get() = resources.getStringArray(R.array.update_channel).let { if (BuildConfig.DEBUG) it.toMutableList().apply { add("Canary") }.toTypedArray() else it
if (BuildConfig.DEBUG) it.toMutableList().apply { add("Canary") }.toTypedArray() else it }
} override val description
override val entryValRes = R.array.value_array get() = entries.getOrNull(value)?.asTransitive()
?: TransitiveText.String(if (value == -1) entries[0] else "Canary")
} }
object UpdateChannelUrl : BaseSettingsItem.Input() { object UpdateChannelUrl : BaseSettingsItem.Input() {
@@ -256,22 +258,20 @@ object Superuser : BaseSettingsItem.Section() {
object AccessMode : BaseSettingsItem.Selector() { object AccessMode : BaseSettingsItem.Selector() {
override val title = R.string.superuser_access.asTransitive() override val title = R.string.superuser_access.asTransitive()
override val entryRes = R.array.su_access override val entryRes = R.array.su_access
override val entryValRes = R.array.value_array
override var value = Config.rootMode override var value = Config.rootMode
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.rootMode = entryValues[it].toInt() Config.rootMode = it
} }
} }
object MultiuserMode : BaseSettingsItem.Selector() { object MultiuserMode : BaseSettingsItem.Selector() {
override val title = R.string.multiuser_mode.asTransitive() override val title = R.string.multiuser_mode.asTransitive()
override val entryRes = R.array.multiuser_mode override val entryRes = R.array.multiuser_mode
override val entryValRes = R.array.value_array
override var value = Config.suMultiuserMode override var value = Config.suMultiuserMode
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.suMultiuserMode = entryValues[it].toInt() Config.suMultiuserMode = it
} }
override val description override val description
@@ -285,11 +285,10 @@ object MultiuserMode : BaseSettingsItem.Selector() {
object MountNamespaceMode : BaseSettingsItem.Selector() { object MountNamespaceMode : BaseSettingsItem.Selector() {
override val title = R.string.mount_namespace_mode.asTransitive() override val title = R.string.mount_namespace_mode.asTransitive()
override val entryRes = R.array.namespace override val entryRes = R.array.namespace
override val entryValRes = R.array.value_array
override var value = Config.suMntNamespaceMode override var value = Config.suMntNamespaceMode
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.suMntNamespaceMode = entryValues[it].toInt() Config.suMntNamespaceMode = it
} }
override val description override val description
@@ -299,11 +298,10 @@ object MountNamespaceMode : BaseSettingsItem.Selector() {
object AutomaticResponse : BaseSettingsItem.Selector() { object AutomaticResponse : BaseSettingsItem.Selector() {
override val title = R.string.auto_response.asTransitive() override val title = R.string.auto_response.asTransitive()
override val entryRes = R.array.auto_response override val entryRes = R.array.auto_response
override val entryValRes = R.array.value_array
override var value = Config.suAutoResponse override var value = Config.suAutoResponse
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.suAutoResponse = entryValues[it].toInt() Config.suAutoResponse = it
} }
} }
@@ -314,7 +312,7 @@ object RequestTimeout : BaseSettingsItem.Selector() {
override var value = selected override var value = selected
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.suDefaultTimeout = entryValues[it].toInt() Config.suDefaultTimeout = it
} }
private val selected: Int private val selected: Int
@@ -324,10 +322,9 @@ object RequestTimeout : BaseSettingsItem.Selector() {
object SUNotification : BaseSettingsItem.Selector() { object SUNotification : BaseSettingsItem.Selector() {
override val title = R.string.superuser_notification.asTransitive() override val title = R.string.superuser_notification.asTransitive()
override val entryRes = R.array.su_notification override val entryRes = R.array.su_notification
override val entryValRes = R.array.value_array
override var value = Config.suNotification override var value = Config.suNotification
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.suNotification = entryValues[it].toInt() Config.suNotification = it
} }
} }

View File

@@ -1,8 +1,13 @@
package com.topjohnwu.magisk.ui.superuser package com.topjohnwu.magisk.ui.superuser
import android.os.Bundle
import android.view.View
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.databinding.FragmentSuperuserMd2Binding import com.topjohnwu.magisk.databinding.FragmentSuperuserMd2Binding
import com.topjohnwu.magisk.ktx.addSimpleItemDecoration
import com.topjohnwu.magisk.ktx.addVerticalPadding
import com.topjohnwu.magisk.ktx.fixEdgeEffect
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
class SuperuserFragment : BaseUIFragment<SuperuserViewModel, FragmentSuperuserMd2Binding>() { class SuperuserFragment : BaseUIFragment<SuperuserViewModel, FragmentSuperuserMd2Binding>() {
@@ -15,6 +20,25 @@ class SuperuserFragment : BaseUIFragment<SuperuserViewModel, FragmentSuperuserMd
activity.title = resources.getString(R.string.superuser) activity.title = resources.getString(R.string.superuser)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val resource = requireContext().resources
val l_50 = resource.getDimensionPixelSize(R.dimen.l_50)
val l1 = resource.getDimensionPixelSize(R.dimen.l1)
binding.superuserList.addVerticalPadding(
l_50,
l1
)
binding.superuserList.addSimpleItemDecoration(
left = l1,
top = l_50,
right = l1,
bottom = l_50,
)
binding.superuserList.fixEdgeEffect()
}
override fun onPreBind(binding: FragmentSuperuserMd2Binding) {} override fun onPreBind(binding: FragmentSuperuserMd2Binding) {}
} }

View File

@@ -2,25 +2,24 @@ package com.topjohnwu.magisk.view
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.graphics.Color import android.content.res.ColorStateList
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.graphics.drawable.InsetDrawable
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatDialog import androidx.appcompat.app.AppCompatDialog
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.ViewCompat
import androidx.core.view.updatePadding
import androidx.databinding.Bindable import androidx.databinding.Bindable
import androidx.databinding.PropertyChangeRegistry import androidx.databinding.PropertyChangeRegistry
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.color.MaterialColors
import com.google.android.material.shape.MaterialShapeDrawable
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.itemBindingOf import com.topjohnwu.magisk.arch.itemBindingOf
@@ -47,36 +46,22 @@ class MagiskDialog(
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
super.setContentView(binding.root) super.setContentView(binding.root)
val surfaceColor = MaterialColors.getColor(context, R.attr.colorSurfaceSurfaceVariant, javaClass.canonicalName)
val materialShapeDrawable = MaterialShapeDrawable(context, null, R.attr.alertDialogStyle, R.style.MaterialAlertDialog_MaterialComponents)
materialShapeDrawable.initializeElevationOverlay(context)
materialShapeDrawable.fillColor = ColorStateList.valueOf(surfaceColor)
materialShapeDrawable.elevation = context.resources.getDimension(R.dimen.margin_generic)
materialShapeDrawable.setCornerSize(context.resources.getDimension(R.dimen.l_50))
val inset = context.resources.getDimensionPixelSize(R.dimen.appcompat_dialog_background_inset)
window?.apply { window?.apply {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) setBackgroundDrawable(InsetDrawable(materialShapeDrawable, inset, inset, inset, inset))
setLayout( setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
}
val paddingTop = binding.root.paddingTop
val paddingBottom = binding.root.paddingBottom
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, insets ->
view.updatePadding(
top = paddingTop + insets.systemWindowInsetTop,
bottom = paddingBottom + insets.systemWindowInsetBottom
)
insets
} }
} }
override fun setCancelable(flag: Boolean) { inner class Data : ObservableHost {
val listener = if (!flag) {
null
} else {
setCanceledOnTouchOutside(true)
View.OnClickListener { dismiss() }
}
binding.dialogBaseOutsideContainer.setOnClickListener(listener)
}
inner class Data: ObservableHost {
override var callbacks: PropertyChangeRegistry? = null override var callbacks: PropertyChangeRegistry? = null
@get:Bindable @get:Bindable
@@ -88,7 +73,7 @@ class MagiskDialog(
set(value) = set(value, field, { field = it }, BR.title) set(value) = set(value, field, { field = it }, BR.title)
@get:Bindable @get:Bindable
var message : CharSequence = "" var message: CharSequence = ""
set(value) = set(value, field, { field = it }, BR.message) set(value) = set(value, field, { field = it }, BR.message)
val buttonPositive = Button() val buttonPositive = Button()
@@ -101,7 +86,7 @@ class MagiskDialog(
POSITIVE, NEUTRAL, NEGATIVE, IDGAF POSITIVE, NEUTRAL, NEGATIVE, IDGAF
} }
inner class Button: ObservableHost { inner class Button : ObservableHost {
override var callbacks: PropertyChangeRegistry? = null override var callbacks: PropertyChangeRegistry? = null
@get:Bindable @get:Bindable

View File

@@ -1,5 +1,8 @@
package com.topjohnwu.signing; package com.topjohnwu.signing;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1InputStream;
@@ -14,6 +17,7 @@ import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FilterInputStream; import java.io.FilterInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -84,8 +88,10 @@ public class SignBoot {
} }
} }
public static boolean doSignature(String target, InputStream imgIn, OutputStream imgOut, public static boolean doSignature(
InputStream cert, InputStream key) { @Nullable X509Certificate cert, @Nullable PrivateKey key,
@NonNull InputStream imgIn, @NonNull OutputStream imgOut, @NonNull String target
) {
try { try {
PushBackRWStream in = new PushBackRWStream(imgIn, imgOut); PushBackRWStream in = new PushBackRWStream(imgIn, imgOut);
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM]; byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
@@ -96,16 +102,16 @@ public class SignBoot {
in.unread(hdr); in.unread(hdr);
BootSignature bootsig = new BootSignature(target, signableSize); BootSignature bootsig = new BootSignature(target, signableSize);
if (cert == null) { if (cert == null) {
cert = SignBoot.class.getResourceAsStream("/keys/verity.x509.pem"); cert = CryptoUtils.readCertificate(
new ByteArrayInputStream(KeyData.verityCert()));
} }
X509Certificate certificate = CryptoUtils.readCertificate(cert); bootsig.setCertificate(cert);
bootsig.setCertificate(certificate);
if (key == null) { if (key == null) {
key = SignBoot.class.getResourceAsStream("/keys/verity.pk8"); key = CryptoUtils.readPrivateKey(
new ByteArrayInputStream(KeyData.verityKey()));
} }
PrivateKey privateKey = CryptoUtils.readPrivateKey(key); byte[] sig = bootsig.sign(key, in, signableSize);
byte[] sig = bootsig.sign(privateKey, in, signableSize); bootsig.setSignature(sig, CryptoUtils.getSignatureAlgorithmIdentifier(key));
bootsig.setSignature(sig, CryptoUtils.getSignatureAlgorithmIdentifier(privateKey));
byte[] encoded_bootsig = bootsig.getEncoded(); byte[] encoded_bootsig = bootsig.getEncoded();
imgOut.write(encoded_bootsig); imgOut.write(encoded_bootsig);
imgOut.flush(); imgOut.flush();
@@ -116,7 +122,7 @@ public class SignBoot {
} }
} }
public static boolean verifySignature(InputStream imgIn, InputStream certIn) { public static boolean verifySignature(InputStream imgIn, X509Certificate cert) {
try { try {
// Read the header for size // Read the header for size
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM]; byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
@@ -142,8 +148,8 @@ public class SignBoot {
} }
BootSignature bootsig = new BootSignature(signature); BootSignature bootsig = new BootSignature(signature);
if (certIn != null) { if (cert != null) {
bootsig.setCertificate(CryptoUtils.readCertificate(certIn)); bootsig.setCertificate(cert);
} }
if (bootsig.verify(rawImg, signableSize)) { if (bootsig.verify(rawImg, signableSize)) {
System.err.println("Signature is VALID"); System.err.println("Signature is VALID");
@@ -314,4 +320,46 @@ public class SignBoot {
} }
} }
public static void main(String[] args) throws Exception {
if (args.length > 0 && "-verify".equals(args[0])) {
X509Certificate cert = null;
if (args.length >= 2) {
// args[1] is the path to a public key certificate
cert = CryptoUtils.readCertificate(new FileInputStream(args[1]));
}
boolean signed = SignBoot.verifySignature(System.in, cert);
System.exit(signed ? 0 : 1);
} else if (args.length > 0 && "-sign".equals(args[0])) {
X509Certificate cert = null;
PrivateKey key = null;
String name = "/boot";
if (args.length >= 3) {
cert = CryptoUtils.readCertificate(new FileInputStream(args[1]));
key = CryptoUtils.readPrivateKey(new FileInputStream(args[2]));
}
if (args.length == 2) {
name = args[1];
} else if (args.length >= 4) {
name = args[3];
}
boolean result = SignBoot.doSignature(cert, key, System.in, System.out, name);
System.exit(result ? 0 : 1);
} else {
System.err.println(
"BootSigner <actions> [args]\n" +
"Input from stdin, output to stdout\n" +
"\n" +
"Actions:\n" +
" -verify [x509.pem]\n" +
" verify image. cert is optional.\n" +
" -sign [x509.pem] [pk8] [name]\n" +
" sign image. name and the cert/key pair are optional.\n" +
" name should be either /boot (default) or /recovery.\n"
);
}
}
} }

View File

@@ -17,8 +17,9 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="@{viewModel.insets.left}" app:consumeSystemWindowsInsets="start|end"
android:paddingRight="@{viewModel.insets.right}" app:edgeToEdge="true"
app:fitsSystemWindowsInsets="start|end"
tools:ignore="RtlHardcoded"> tools:ignore="RtlHardcoded">
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView
@@ -34,7 +35,7 @@
style="@style/WidgetFoundation.Appbar" style="@style/WidgetFoundation.Appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="@{viewModel.insets.top}"> app:fitsSystemWindowsInsets="top">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@+id/main_toolbar" android:id="@+id/main_toolbar"
@@ -72,7 +73,9 @@
android:layout_gravity="bottom|center_horizontal" android:layout_gravity="bottom|center_horizontal"
android:layout_marginStart="@dimen/l1" android:layout_marginStart="@dimen/l1"
android:layout_marginEnd="@dimen/l1" android:layout_marginEnd="@dimen/l1"
android:layout_marginBottom="@{(int) @dimen/l1 + viewModel.insets.bottom}" android:layout_marginBottom="@dimen/l1"
android:fitsSystemWindows="false"
app:layout_fitsSystemWindowsInsets="bottom"
tools:layout_marginBottom="64dp"> tools:layout_marginBottom="64dp">
<com.google.android.material.bottomnavigation.BottomNavigationView <com.google.android.material.bottomnavigation.BottomNavigationView
@@ -81,6 +84,9 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:textStyle="bold" android:textStyle="bold"
android:fitsSystemWindows="false"
android:paddingBottom="0dp"
app:fitsSystemWindowsInsets="start|end"
app:elevation="0dp" app:elevation="0dp"
app:itemHorizontalTranslationEnabled="false" app:itemHorizontalTranslationEnabled="false"
app:itemIconTint="@color/color_menu_tint" app:itemIconTint="@color/color_menu_tint"

View File

@@ -12,219 +12,185 @@
</data> </data>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/dialog_base_outside_container" android:layout_width="wrap_content"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="match_parent"> tools:layout_width="match_parent">
<FrameLayout <androidx.constraintlayout.widget.Guideline
android:layout_width="0dp" android:id="@+id/dialog_base_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constrainedHeight="true" android:orientation="vertical"
app:layout_constrainedWidth="true" app:layout_constraintGuide_begin="16dp" />
app:layout_constraintBottom_toBottomOf="parent"
<androidx.constraintlayout.widget.Guideline
android:id="@+id/dialog_base_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="16dp" />
<ImageView
android:id="@+id/dialog_base_icon"
style="@style/WidgetFoundation.Image.Big"
gone="@{data.icon == null}"
android:layout_gravity="center"
android:layout_marginTop="@dimen/l1"
android:src="@{data.icon}"
app:layout_constraintBottom_toTopOf="@+id/dialog_base_title"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_max="400dp"> tools:src="@drawable/ic_delete_md2" />
<com.google.android.material.card.MaterialCardView <TextView
style="@style/WidgetFoundation.Card.Elevated" android:id="@+id/dialog_base_title"
gone="@{data.title.length == 0}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/l1"
android:gravity="center"
android:text="@{data.title}"
android:textAppearance="@style/AppearanceFoundation.Title"
app:layout_constraintEnd_toEndOf="@+id/dialog_base_end"
app:layout_constraintStart_toStartOf="@+id/dialog_base_start"
app:layout_constraintTop_toBottomOf="@+id/dialog_base_icon"
tools:lines="1"
tools:text="@tools:sample/lorem/random" />
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/l_50"
android:overScrollMode="ifContentScrolls"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="@+id/dialog_base_space"
app:layout_constraintEnd_toEndOf="@+id/dialog_base_end"
app:layout_constraintStart_toStartOf="@+id/dialog_base_start"
app:layout_constraintTop_toBottomOf="@+id/dialog_base_title">
<FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content">
android:focusable="false"
app:cardElevation="@dimen/margin_generic"
app:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout <TextView
android:id="@+id/dialog_base_message"
gone="@{data.message.length == 0}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="match_parent"
android:text="@{data.message}"
android:textAppearance="@style/AppearanceFoundation.Body"
tools:lines="3"
tools:text="@tools:sample/lorem/random" />
<androidx.constraintlayout.widget.Guideline <FrameLayout
android:id="@+id/dialog_base_start" android:id="@+id/dialog_base_container"
android:layout_width="wrap_content" gone="@{data.message.length != 0}"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:orientation="vertical" android:layout_height="wrap_content" />
app:layout_constraintGuide_begin="16dp" />
<androidx.constraintlayout.widget.Guideline </FrameLayout>
android:id="@+id/dialog_base_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="16dp" />
<ImageView </androidx.core.widget.NestedScrollView>
android:id="@+id/dialog_base_icon"
style="@style/WidgetFoundation.Image.Big"
gone="@{data.icon == null}"
android:layout_gravity="center"
android:layout_marginTop="@dimen/l1"
android:src="@{data.icon}"
app:layout_constraintBottom_toTopOf="@+id/dialog_base_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_delete_md2" />
<TextView <Space
android:id="@+id/dialog_base_title" android:id="@+id/dialog_base_space"
gone="@{data.title.length == 0}" android:layout_width="wrap_content"
android:layout_width="0dp" android:layout_height="@dimen/l_50"
android:layout_height="wrap_content" app:layout_constraintBottom_toTopOf="@+id/dialog_base_buttons"
android:layout_marginTop="@dimen/l1" app:layout_constraintEnd_toEndOf="parent"
android:gravity="center" app:layout_constraintStart_toStartOf="parent" />
android:text="@{data.title}"
android:textAppearance="@style/AppearanceFoundation.Title"
app:layout_constraintEnd_toEndOf="@+id/dialog_base_end"
app:layout_constraintStart_toStartOf="@+id/dialog_base_start"
app:layout_constraintTop_toBottomOf="@+id/dialog_base_icon"
tools:lines="1"
tools:text="@tools:sample/lorem/random" />
<androidx.core.widget.NestedScrollView <androidx.appcompat.widget.ButtonBarLayout
android:layout_width="0dp" android:id="@+id/dialog_base_buttons"
android:layout_height="wrap_content" android:layout_width="0dp"
android:layout_marginTop="@dimen/l_50" android:layout_height="wrap_content"
android:overScrollMode="ifContentScrolls" android:gravity="bottom|center_horizontal"
app:layout_constrainedHeight="true" android:layoutDirection="locale"
app:layout_constraintBottom_toTopOf="@+id/dialog_base_space" android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="@+id/dialog_base_end" android:paddingStart="12dp"
app:layout_constraintStart_toStartOf="@+id/dialog_base_start" android:paddingTop="4dp"
app:layout_constraintTop_toBottomOf="@+id/dialog_base_title"> android:paddingEnd="12dp"
android:paddingBottom="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<FrameLayout <Button
android:layout_width="match_parent" android:id="@+id/dialog_base_button_4"
android:layout_height="wrap_content"> style="@style/WidgetFoundation.Button.Text"
gone="@{data.buttonIDGAF.icon == 0 &amp;&amp; data.buttonIDGAF.title.length == 0}"
isEnabled="@{data.buttonIDGAF.isEnabled()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:clickable="@{data.buttonIDGAF.isEnabled()}"
android:focusable="@{data.buttonIDGAF.isEnabled()}"
android:onClick="@{() -> data.buttonIDGAF.clicked()}"
android:text="@{data.buttonIDGAF.title}"
app:icon="@{data.buttonIDGAF.icon}"
tools:icon="@drawable/ic_bug_md2"
tools:text="Button 1" />
<TextView <Button
android:id="@+id/dialog_base_message" android:id="@+id/dialog_base_button_2"
gone="@{data.message.length == 0}" style="@style/WidgetFoundation.Button.Text"
android:layout_width="match_parent" gone="@{data.buttonNeutral.icon == 0 &amp;&amp; data.buttonNeutral.title.length == 0}"
android:layout_height="match_parent" isEnabled="@{data.buttonNeutral.isEnabled()}"
android:text="@{data.message}" android:layout_width="wrap_content"
android:textAppearance="@style/AppearanceFoundation.Body" android:layout_height="wrap_content"
tools:lines="3" android:layout_gravity="center_horizontal"
tools:text="@tools:sample/lorem/random" /> android:clickable="@{data.buttonNeutral.isEnabled()}"
android:focusable="@{data.buttonNeutral.isEnabled()}"
android:onClick="@{() -> data.buttonNeutral.clicked()}"
android:text="@{data.buttonNeutral.title}"
app:icon="@{data.buttonNeutral.icon}"
app:iconGravity="textStart"
tools:icon="@drawable/ic_bug_md2"
tools:text="Button 1" />
<FrameLayout <Space
android:id="@+id/dialog_base_container" android:id="@+id/spacer"
gone="@{data.message.length != 0}" android:layout_width="0dp"
android:layout_width="match_parent" android:layout_height="0dp"
android:layout_height="wrap_content" /> android:layout_weight="1"
android:visibility="invisible" />
</FrameLayout> <Button
android:id="@+id/dialog_base_button_3"
style="@style/WidgetFoundation.Button.Text"
gone="@{data.buttonNegative.icon == 0 &amp;&amp; data.buttonNegative.title.length == 0}"
isEnabled="@{data.buttonNegative.isEnabled()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:clickable="@{data.buttonNegative.isEnabled()}"
android:focusable="@{data.buttonNegative.isEnabled()}"
android:onClick="@{() -> data.buttonNegative.clicked()}"
android:text="@{data.buttonNegative.title}"
app:icon="@{data.buttonNegative.icon}"
tools:icon="@drawable/ic_bug_md2"
tools:text="Button 1" />
</androidx.core.widget.NestedScrollView> <Button
android:id="@+id/dialog_base_button_1"
style="@style/WidgetFoundation.Button.Text"
gone="@{data.buttonPositive.icon == 0 &amp;&amp; data.buttonPositive.title.length == 0}"
isEnabled="@{data.buttonPositive.isEnabled()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:clickable="@{data.buttonPositive.isEnabled()}"
android:focusable="@{data.buttonPositive.isEnabled()}"
android:onClick="@{() -> data.buttonPositive.clicked()}"
android:text="@{data.buttonPositive.title}"
app:icon="@{data.buttonPositive.icon}"
app:iconGravity="textStart"
tools:icon="@drawable/ic_bug_md2"
tools:text="Button 1" />
<Space </androidx.appcompat.widget.ButtonBarLayout>
android:id="@+id/dialog_base_space"
android:layout_width="wrap_content"
android:layout_height="@dimen/l_50"
app:layout_constraintBottom_toTopOf="@+id/dialog_base_buttons"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.appcompat.widget.ButtonBarLayout
android:id="@+id/dialog_base_buttons"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="bottom|center_horizontal"
android:layoutDirection="locale"
android:orientation="horizontal"
android:paddingStart="12dp"
android:paddingTop="4dp"
android:paddingEnd="12dp"
android:paddingBottom="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="@+id/dialog_base_button_4"
style="@style/WidgetFoundation.Button.Text"
gone="@{data.buttonIDGAF.icon == 0 &amp;&amp; data.buttonIDGAF.title.length == 0}"
isEnabled="@{data.buttonIDGAF.isEnabled()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:clickable="@{data.buttonIDGAF.isEnabled()}"
android:filterTouchesWhenObscured="true"
android:focusable="@{data.buttonIDGAF.isEnabled()}"
android:onClick="@{() -> data.buttonIDGAF.clicked()}"
android:text="@{data.buttonIDGAF.title}"
app:icon="@{data.buttonIDGAF.icon}"
tools:icon="@drawable/ic_bug_md2"
tools:text="Button 1" />
<Button
android:id="@+id/dialog_base_button_2"
style="@style/WidgetFoundation.Button.Text"
gone="@{data.buttonNeutral.icon == 0 &amp;&amp; data.buttonNeutral.title.length == 0}"
isEnabled="@{data.buttonNeutral.isEnabled()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:clickable="@{data.buttonNeutral.isEnabled()}"
android:filterTouchesWhenObscured="true"
android:focusable="@{data.buttonNeutral.isEnabled()}"
android:onClick="@{() -> data.buttonNeutral.clicked()}"
android:text="@{data.buttonNeutral.title}"
app:icon="@{data.buttonNeutral.icon}"
app:iconGravity="textStart"
tools:icon="@drawable/ic_bug_md2"
tools:text="Button 1" />
<Space
android:id="@+id/spacer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
<Button
android:id="@+id/dialog_base_button_3"
style="@style/WidgetFoundation.Button.Text"
gone="@{data.buttonNegative.icon == 0 &amp;&amp; data.buttonNegative.title.length == 0}"
isEnabled="@{data.buttonNegative.isEnabled()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:clickable="@{data.buttonNegative.isEnabled()}"
android:filterTouchesWhenObscured="true"
android:focusable="@{data.buttonNegative.isEnabled()}"
android:onClick="@{() -> data.buttonNegative.clicked()}"
android:text="@{data.buttonNegative.title}"
app:icon="@{data.buttonNegative.icon}"
tools:icon="@drawable/ic_bug_md2"
tools:text="Button 1" />
<Button
android:id="@+id/dialog_base_button_1"
style="@style/WidgetFoundation.Button.Text"
gone="@{data.buttonPositive.icon == 0 &amp;&amp; data.buttonPositive.title.length == 0}"
isEnabled="@{data.buttonPositive.isEnabled()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:clickable="@{data.buttonPositive.isEnabled()}"
android:filterTouchesWhenObscured="true"
android:focusable="@{data.buttonPositive.isEnabled()}"
android:onClick="@{() -> data.buttonPositive.clicked()}"
android:text="@{data.buttonPositive.title}"
app:icon="@{data.buttonPositive.icon}"
app:iconGravity="textStart"
tools:icon="@drawable/ic_bug_md2"
tools:text="Button 1" />
</androidx.appcompat.widget.ButtonBarLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</layout> </layout>

View File

@@ -18,7 +18,8 @@
<HorizontalScrollView <HorizontalScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}" android:layout_marginTop="@dimen/internal_action_bar_size"
app:layout_fitsSystemWindowsInsets="top"
tools:layout_marginTop="@dimen/internal_action_bar_size"> tools:layout_marginTop="@dimen/internal_action_bar_size">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
@@ -31,9 +32,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="@{viewModel.insets.left}" app:fitsSystemWindowsInsets="start|end|bottom"
android:paddingRight="@{viewModel.insets.right}"
android:paddingBottom="@{viewModel.insets.bottom}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/item_console_md2" /> tools:listitem="@layout/item_console_md2" />
@@ -46,12 +45,13 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_margin="@dimen/l1" android:layout_margin="@dimen/l1"
android:layout_marginBottom="@{(int) @dimen/l1 + viewModel.insets.bottom}" android:layout_marginBottom="@dimen/l1"
android:onClick="@{() -> viewModel.restartPressed()}" android:onClick="@{() -> viewModel.restartPressed()}"
android:text="@string/reboot" android:text="@string/reboot"
android:textAllCaps="false" android:textAllCaps="false"
android:textColor="?colorOnPrimary" android:textColor="?colorOnPrimary"
android:textStyle="bold" android:textStyle="bold"
app:layout_fitsSystemWindowsInsets="bottom"
app:backgroundTint="?colorPrimary" app:backgroundTint="?colorPrimary"
app:icon="@drawable/ic_restart" app:icon="@drawable/ic_restart"
app:iconTint="?colorOnPrimary" /> app:iconTint="?colorOnPrimary" />

View File

@@ -17,7 +17,6 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/hide_content" android:id="@+id/hide_content"
dividerVertical="@{@drawable/divider_l_50}"
invisibleUnless="@{viewModel.loaded || !viewModel.items.empty}" invisibleUnless="@{viewModel.loaded || !viewModel.items.empty}"
itemBinding="@{viewModel.itemBinding}" itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}" items="@{viewModel.items}"
@@ -25,10 +24,8 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="@dimen/l1" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}" app:fitsSystemWindowsInsets="top|bottom"
android:paddingEnd="@dimen/l1"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_hide_md2" tools:listitem="@layout/item_hide_md2"
tools:paddingTop="40dp" /> tools:paddingTop="40dp" />
@@ -41,8 +38,9 @@
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_marginStart="@dimen/l1" android:layout_marginStart="@dimen/l1"
android:layout_marginEnd="@dimen/l1" android:layout_marginEnd="@dimen/l1"
android:layout_marginBottom="@{viewModel.insets.bottom + (int) @dimen/l1}" android:layout_marginBottom="@dimen/l1"
app:backgroundTint="?colorSurfaceSurfaceVariant" app:backgroundTint="?colorSurfaceSurfaceVariant"
app:layout_fitsSystemWindowsInsets="bottom"
app:srcCompat="@drawable/ic_search_md2" app:srcCompat="@drawable/ic_search_md2"
app:tint="?colorPrimary" app:tint="?colorPrimary"
tools:layout_marginBottom="64dp" /> tools:layout_marginBottom="64dp" />

View File

@@ -22,8 +22,9 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:fillViewport="true" android:fillViewport="true"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l3}" android:paddingBottom="@dimen/l3"
app:fitsSystemWindowsInsets="top|bottom"
tools:layout_marginTop="24dp"> tools:layout_marginTop="24dp">
<LinearLayout <LinearLayout

View File

@@ -20,8 +20,9 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:fillViewport="true" android:fillViewport="true"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l2}" android:paddingBottom="@dimen/l2"
app:fitsSystemWindowsInsets="top|bottom"
tools:paddingTop="24dp"> tools:paddingTop="24dp">
<FrameLayout <FrameLayout
@@ -34,7 +35,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:paddingTop="@dimen/l1"> android:paddingTop="@dimen/l_50">
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
style="@style/WidgetFoundation.Card" style="@style/WidgetFoundation.Card"

View File

@@ -29,7 +29,8 @@
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_marginStart="@dimen/l1" android:layout_marginStart="@dimen/l1"
android:layout_marginEnd="@dimen/l1" android:layout_marginEnd="@dimen/l1"
android:layout_marginBottom="@{viewModel.insets.bottom + (int) @dimen/l1}" android:layout_marginBottom="@dimen/l1"
app:layout_fitsSystemWindowsInsets="bottom"
app:backgroundTint="?colorSurfaceSurfaceVariant" app:backgroundTint="?colorSurfaceSurfaceVariant"
app:srcCompat="@drawable/ic_folder_list" app:srcCompat="@drawable/ic_folder_list"
app:tint="?colorPrimary" app:tint="?colorPrimary"

View File

@@ -31,8 +31,6 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/module_list" android:id="@+id/module_list"
adapter="@{viewModel.adapter}" adapter="@{viewModel.adapter}"
dividerHorizontal="@{@drawable/divider_l1}"
dividerVertical="@{@drawable/divider_l_50}"
gone="@{viewModel.loading &amp;&amp; viewModel.items.empty}" gone="@{viewModel.loading &amp;&amp; viewModel.items.empty}"
itemBinding="@{viewModel.itemBinding}" itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}" items="@{viewModel.items}"
@@ -40,10 +38,8 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="@dimen/l1" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}" app:fitsSystemWindowsInsets="top|bottom"
android:paddingEnd="0dp"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_module_md2" /> tools:listitem="@layout/item_module_md2" />
@@ -54,7 +50,8 @@
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_marginStart="@dimen/l1" android:layout_marginStart="@dimen/l1"
android:layout_marginEnd="@dimen/l1" android:layout_marginEnd="@dimen/l1"
android:layout_marginBottom="@{viewModel.insets.bottom + (int) @dimen/l1}" android:layout_marginBottom="@dimen/l1"
app:layout_fitsSystemWindowsInsets="bottom"
app:backgroundTint="?colorSurfaceSurfaceVariant" app:backgroundTint="?colorSurfaceSurfaceVariant"
app:srcCompat="@drawable/ic_search_md2" app:srcCompat="@drawable/ic_search_md2"
app:tint="?colorPrimary" app:tint="?colorPrimary"

View File

@@ -22,8 +22,8 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:fillViewport="true" android:fillViewport="true"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingBottom="@{viewModel.insets.bottom}" app:fitsSystemWindowsInsets="top|bottom"
tools:paddingBottom="48dp" tools:paddingBottom="48dp"
tools:paddingTop="24dp"> tools:paddingTop="24dp">

View File

@@ -15,8 +15,6 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
adapter="@{viewModel.adapter}" adapter="@{viewModel.adapter}"
dividerHorizontal="@{@drawable/divider_l_50}"
dividerVertical="@{@drawable/divider_l_50}"
itemBinding="@{viewModel.itemBinding}" itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}" items="@{viewModel.items}"
android:id="@+id/settings_list" android:id="@+id/settings_list"
@@ -25,10 +23,8 @@
android:focusableInTouchMode="false" android:focusableInTouchMode="false"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="@dimen/l1" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}" app:fitsSystemWindowsInsets="top|bottom"
android:paddingEnd="@dimen/l_50"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l1}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:layout_marginTop="24dp" tools:layout_marginTop="24dp"
tools:listitem="@layout/item_settings" tools:listitem="@layout/item_settings"

View File

@@ -20,8 +20,6 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/superuser_list" android:id="@+id/superuser_list"
adapter="@{viewModel.adapter}" adapter="@{viewModel.adapter}"
dividerHorizontal="@{@drawable/divider_l1}"
dividerVertical="@{@drawable/divider_l_50}"
goneUnless="@{viewModel.loaded || !viewModel.items.empty}" goneUnless="@{viewModel.loaded || !viewModel.items.empty}"
itemBinding="@{viewModel.itemBinding}" itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}" items="@{viewModel.items}"
@@ -29,9 +27,8 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="@dimen/l1" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}" app:fitsSystemWindowsInsets="top|bottom"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l2}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_policy_md2" /> tools:listitem="@layout/item_policy_md2" />

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data> <data>
@@ -17,15 +18,17 @@
android:clipToPadding="false" android:clipToPadding="false"
android:fillViewport="true" android:fillViewport="true"
android:paddingStart="@dimen/l1" android:paddingStart="@dimen/l1"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingEnd="@dimen/l1" android:paddingEnd="@dimen/l1"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l1}"> android:paddingBottom="@dimen/l1"
app:fitsSystemWindowsInsets="top|bottom">
<LinearLayout <LinearLayout
android:id="@+id/theme_container" android:id="@+id/theme_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:paddingTop="@dimen/l1"
android:useDefaultMargins="true"> android:useDefaultMargins="true">
<include <include

View File

@@ -21,7 +21,8 @@
android:paddingStart="@dimen/l1" android:paddingStart="@dimen/l1"
android:paddingTop="@dimen/l1" android:paddingTop="@dimen/l1"
android:paddingEnd="@dimen/l1" android:paddingEnd="@dimen/l1"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l1}" android:paddingBottom="@dimen/l1"
app:fitsSystemWindowsInsets="bottom"
tools:layout_gravity="bottom" tools:layout_gravity="bottom"
tools:paddingBottom="64dp"> tools:paddingBottom="64dp">

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" <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"> xmlns:tools="http://schemas.android.com/tools">
<data> <data>
@@ -32,8 +33,8 @@
precomputedText="@{viewModel.consoleText}" precomputedText="@{viewModel.consoleText}"
android:textAppearance="@style/AppearanceFoundation.Caption" android:textAppearance="@style/AppearanceFoundation.Caption"
android:textSize="10sp" android:textSize="10sp"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingBottom="@{viewModel.insets.bottom}" app:layout_fitsSystemWindowsInsets="top|bottom"
tools:text="@tools:sample/lorem/random" /> tools:text="@tools:sample/lorem/random" />
</HorizontalScrollView> </HorizontalScrollView>

View File

@@ -16,16 +16,15 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/log_superuser"
itemBinding="@{viewModel.itemBinding}" itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}" items="@{viewModel.items}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="@dimen/l1" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}" app:fitsSystemWindowsInsets="top|bottom"
android:paddingEnd="@dimen/l1"
android:paddingBottom="@{viewModel.insets.bottom}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_log_access_md2" tools:listitem="@layout/item_log_access_md2"
tools:paddingTop="24dp" /> tools:paddingTop="24dp" />

View File

@@ -18,14 +18,13 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l1}" android:paddingBottom="@dimen/l1"
app:fitsSystemWindowsInsets="bottom"
tools:layout_gravity="bottom" tools:layout_gravity="bottom"
tools:paddingBottom="64dp"> tools:paddingBottom="64dp">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/module_filter_list" android:id="@+id/module_filter_list"
dividerHorizontal="@{@drawable/divider_l1}"
dividerVertical="@{@drawable/divider_l_50}"
itemBinding="@{viewModel.itemSearchBinding}" itemBinding="@{viewModel.itemSearchBinding}"
items="@{viewModel.itemsSearch}" items="@{viewModel.itemsSearch}"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -33,8 +32,8 @@
android:layout_marginBottom="@dimen/l1" android:layout_marginBottom="@dimen/l1"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="@dimen/l1" android:paddingTop="@dimen/internal_action_bar_size"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}" app:fitsSystemWindowsInsets="top"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constrainedHeight="true" app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="@+id/module_filter_title_search" app:layout_constraintBottom_toTopOf="@+id/module_filter_title_search"

View File

@@ -9,7 +9,7 @@
<variable <variable
name="item" name="item"
type="com.topjohnwu.magisk.ui.hide.HideItem" /> type="com.topjohnwu.magisk.ui.hide.HideRvItem" />
<variable <variable
name="viewModel" name="viewModel"

View File

@@ -7,7 +7,7 @@
<variable <variable
name="item" name="item"
type="com.topjohnwu.magisk.ui.hide.HideProcessItem" /> type="com.topjohnwu.magisk.ui.hide.HideProcessRvItem" />
<variable <variable
name="viewModel" name="viewModel"

View File

@@ -1,3 +1,12 @@
## v8.0.5
- Fix sepolicy rule copying
## v8.0.4
- A lot of stability changes and minor bug fixes
- Collect device properties, app logcat, and Magisk logs when saving logs in the logs menu
## v8.0.3 ## v8.0.3
- Switch to the new Magisk Module Repo setup in preparation to allow 3rd party repos - Switch to the new Magisk Module Repo setup in preparation to allow 3rd party repos

View File

@@ -30,10 +30,16 @@ direct_install() {
rm -f $MAGISKBIN/new-boot.img rm -f $MAGISKBIN/new-boot.img
echo "- Flashing new boot image" echo "- Flashing new boot image"
flash_image $1/new-boot.img $2 flash_image $1/new-boot.img $2
if [ $? -ne 0 ]; then case $? in
echo "! Insufficient partition size" 1)
return 1 echo "! Insufficient partition size"
fi return 1
;;
2)
echo "! $2 is read only"
return 2
;;
esac
rm -rf $1 rm -rf $1
return 0 return 0
} }

View File

@@ -6,8 +6,8 @@
<string name="logs">Журналы</string> <string name="logs">Журналы</string>
<string name="settings">Налады</string> <string name="settings">Налады</string>
<string name="refresh">Абнавіць даныя</string> <string name="refresh">Абнавіць даныя</string>
<string name="install">Усталяваць</string> <string name="install">Усталёўка</string>
<string name="section_home">На хатнюю старонку</string> <string name="section_home">Хатняя старонка</string>
<string name="section_theme">Тэмы</string> <string name="section_theme">Тэмы</string>
<string name="safetynet">SafetyNet</string> <string name="safetynet">SafetyNet</string>
<!--Home--> <!--Home-->
@@ -16,7 +16,7 @@
<string name="manager">Кіраўнік</string> <string name="manager">Кіраўнік</string>
<string name="loading">Загрузка…</string> <string name="loading">Загрузка…</string>
<string name="update">Абнавіць</string> <string name="update">Абнавіць</string>
<string name="not_available">Н</string> <string name="not_available">Не</string>
<string name="hide">Схаваць</string> <string name="hide">Схаваць</string>
<string name="status">Статус</string> <string name="status">Статус</string>
<string name="home_package">Пакунак</string> <string name="home_package">Пакунак</string>
@@ -26,7 +26,7 @@
<string name="home_support_content">Magisk ёсць і заўсёды будзе бясплатным праектам з адкрытым зыходным кодам. Але вы заўсёды можаце ахвяраваць нам на распрацоўку.</string> <string name="home_support_content">Magisk ёсць і заўсёды будзе бясплатным праектам з адкрытым зыходным кодам. Але вы заўсёды можаце ахвяраваць нам на распрацоўку.</string>
<string name="home_status_normal">Звычайны</string> <string name="home_status_normal">Звычайны</string>
<string name="home_status_stub">Хаванне</string> <string name="home_status_stub">Хаванне</string>
<string name="home_installed_version">Усталяваны</string> <string name="home_installed_version">Усталявана</string>
<string name="home_latest_version">Апошні</string> <string name="home_latest_version">Апошні</string>
<string name="invalid_update_channel">Хібны канал абнаўлення</string> <string name="invalid_update_channel">Хібны канал абнаўлення</string>
<string name="uninstall_magisk_title">Выдаліць Magisk</string> <string name="uninstall_magisk_title">Выдаліць Magisk</string>

View File

@@ -15,7 +15,7 @@
<string name="no_connection">Keine Verbindung verfügbar</string> <string name="no_connection">Keine Verbindung verfügbar</string>
<string name="app_changelog">Änderungen</string> <string name="app_changelog">Änderungen</string>
<string name="manager">Manager</string> <string name="manager">Manager</string>
<string name="loading">Lädt</string> <string name="loading">Laden</string>
<string name="update">Update</string> <string name="update">Update</string>
<string name="not_available">N/A</string> <string name="not_available">N/A</string>
<string name="hide">Verstecken</string> <string name="hide">Verstecken</string>
@@ -40,7 +40,7 @@
<string name="recovery_mode">Recovery Modus</string> <string name="recovery_mode">Recovery Modus</string>
<string name="install_options_title">Optionen</string> <string name="install_options_title">Optionen</string>
<string name="install_method_title">Methode</string> <string name="install_method_title">Methode</string>
<string name="install_next">Nächste</string> <string name="install_next">Nächster Schritt</string>
<string name="install_start">Los geht\'s</string> <string name="install_start">Los geht\'s</string>
<string name="manager_download_install">Tippen zum Herunterladen und Installieren</string> <string name="manager_download_install">Tippen zum Herunterladen und Installieren</string>
<string name="download_zip_only">Nur Zip herunterladen</string> <string name="download_zip_only">Nur Zip herunterladen</string>

View File

@@ -170,6 +170,8 @@
<string name="superuser_notification">Notificación de superusuario</string> <string name="superuser_notification">Notificación de superusuario</string>
<string name="settings_su_reauth_title">Re-autenticación</string> <string name="settings_su_reauth_title">Re-autenticación</string>
<string name="settings_su_reauth_summary">Pedir permisos de superusuario nuevamente si una aplicación es actualizada o reinstalada</string> <string name="settings_su_reauth_summary">Pedir permisos de superusuario nuevamente si una aplicación es actualizada o reinstalada</string>
<string name="settings_su_tapjack_title">Habilitar Protección contra Tapjacking</string>
<string name="settings_su_tapjack_summary">El cuadro de solicitud de superusuario no responderá mientras esté oculto por cualquier otra ventana o superposición</string>
<string name="settings_su_biometric_title">Habilitar autenticación biométrica</string> <string name="settings_su_biometric_title">Habilitar autenticación biométrica</string>
<string name="settings_su_biometric_summary">Usar autenticación biométrica para permitir solicitudes de superusuario</string> <string name="settings_su_biometric_summary">Usar autenticación biométrica para permitir solicitudes de superusuario</string>
<string name="no_biometric">Dispositivo no compatible o las configuraciones biométricas no están habilitadas</string> <string name="no_biometric">Dispositivo no compatible o las configuraciones biométricas no están habilitadas</string>

View File

@@ -22,7 +22,7 @@
<string name="status">Status</string> <string name="status">Status</string>
<string name="home_package">Paket</string> <string name="home_package">Paket</string>
<string name="home_notice_content">Pastikan selalu menggunakan Magisk Manager dari sumber terbuka. Manager dari sumber yang tidak dikenal dapat melakukan tindakan jahat.</string> <string name="home_notice_content">Pastikan selalu menggunakan Magisk Manager dari sumber terbuka. Manager dari sumber yang tidak dikenal dapat melakukan tindakan jahat!</string>
<string name="home_support_title">Dukung kami</string> <string name="home_support_title">Dukung kami</string>
<string name="home_item_source">Sumber</string> <string name="home_item_source">Sumber</string>
<string name="home_support_content">Magisk gratis dan bersumber terbuka, dan akan selalu seperti itu. Bagaimanapun juga Anda dapat menunjukan kepedulian Anda kepada kami dengan mengirimkan sedikit donasi.</string> <string name="home_support_content">Magisk gratis dan bersumber terbuka, dan akan selalu seperti itu. Bagaimanapun juga Anda dapat menunjukan kepedulian Anda kepada kami dengan mengirimkan sedikit donasi.</string>
@@ -85,11 +85,11 @@
<string name="superuser_policy_none">Belum ada aplikasi yang meminta izin superuser.</string> <string name="superuser_policy_none">Belum ada aplikasi yang meminta izin superuser.</string>
<!--Logs--> <!--Logs-->
<string name="log_data_none">Log Anda masih kosong, coba gunakan lebih banyak aplikasi yang membutuhkan SU Anda.</string> <string name="log_data_none">Log Anda masih kosong, coba gunakan lebih banyak aplikasi yang membutuhkan SU Anda</string>
<string name="log_data_magisk_none">Log Magisk kosong, ini aneh.</string> <string name="log_data_magisk_none">Log Magisk kosong, ini aneh</string>
<string name="menuSaveLog">Simpan log</string> <string name="menuSaveLog">Simpan log</string>
<string name="menuClearLog">Hapus log sekarang</string> <string name="menuClearLog">Hapus log sekarang</string>
<string name="logs_cleared">Log berhasil dihapus.</string> <string name="logs_cleared">Log berhasil dihapus</string>
<string name="pid">PID: %1$d</string> <string name="pid">PID: %1$d</string>
<string name="target_uid">Target UID: %1$d</string> <string name="target_uid">Target UID: %1$d</string>
@@ -101,7 +101,7 @@
<string name="safetynet_attest_loading">Tunggu sebentar…</string> <string name="safetynet_attest_loading">Tunggu sebentar…</string>
<string name="safetynet_attest_restart">Coba lagi</string> <string name="safetynet_attest_restart">Coba lagi</string>
<!-- MagiskHide --> <!--MagiskHide-->
<string name="show_system_app">Tampilkan aplikasi sistem</string> <string name="show_system_app">Tampilkan aplikasi sistem</string>
<string name="show_os_app">Tampilkan aplikasi OS</string> <string name="show_os_app">Tampilkan aplikasi OS</string>
<string name="hide_filter_hint">Filter menurut nama</string> <string name="hide_filter_hint">Filter menurut nama</string>
@@ -109,7 +109,7 @@
<string name="hide_filters">Filter</string> <string name="hide_filters">Filter</string>
<string name="hide_search">Telusuri</string> <string name="hide_search">Telusuri</string>
<!--Module --> <!--Module-->
<string name="no_info_provided">(Info tidak tersedia)</string> <string name="no_info_provided">(Info tidak tersedia)</string>
<string name="reboot_userspace">Nyalakan ulang secara halus</string> <string name="reboot_userspace">Nyalakan ulang secara halus</string>
<string name="reboot_recovery">Nyalakan ke mode Recovery</string> <string name="reboot_recovery">Nyalakan ke mode Recovery</string>
@@ -127,7 +127,7 @@
<string name="module_section_online">Online</string> <string name="module_section_online">Online</string>
<string name="sorting_order">Urutan sortir</string> <string name="sorting_order">Urutan sortir</string>
<!--Settings --> <!--Settings-->
<string name="settings_dark_mode_title">Mode tema</string> <string name="settings_dark_mode_title">Mode tema</string>
<string name="settings_dark_mode_message">Pilih mode yang paling cocok dengan gaya Anda!</string> <string name="settings_dark_mode_message">Pilih mode yang paling cocok dengan gaya Anda!</string>
<string name="settings_dark_mode_light">Selalu terang</string> <string name="settings_dark_mode_light">Selalu terang</string>
@@ -220,7 +220,7 @@
<string name="repo_cache_cleared">Cache repo dihapus</string> <string name="repo_cache_cleared">Cache repo dihapus</string>
<string name="flashing">Memasang…</string> <string name="flashing">Memasang…</string>
<string name="done">Selesai!</string> <string name="done">Selesai!</string>
<string name="failure">Gagal</string> <string name="failure">Gagal!</string>
<string name="hide_manager_title">Menyembunyikan Magisk Manager…</string> <string name="hide_manager_title">Menyembunyikan Magisk Manager…</string>
<string name="hide_manager_fail_toast">Gagal menyembunyikan Magisk Manager.</string> <string name="hide_manager_fail_toast">Gagal menyembunyikan Magisk Manager.</string>
<string name="restore_manager_fail_toast">Gagal memulihkan Magisk Manager</string> <string name="restore_manager_fail_toast">Gagal memulihkan Magisk Manager</string>

View File

@@ -55,6 +55,7 @@
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">Richiesta di accesso root</string> <string name="su_request_title">Richiesta di accesso root</string>
<string name="touch_filtered_warning">Magisk non può verificare la tua risposta perché un\'app sta oscurando una richiesta di accesso root</string>
<string name="deny">Nega</string> <string name="deny">Nega</string>
<string name="prompt">Chiedi</string> <string name="prompt">Chiedi</string>
<string name="grant">Consenti</string> <string name="grant">Consenti</string>
@@ -101,6 +102,7 @@
<!-- MagiskHide --> <!-- MagiskHide -->
<string name="show_system_app">Mostra app di sistema</string> <string name="show_system_app">Mostra app di sistema</string>
<string name="show_os_app">Mostra app del sistema operativo</string>
<string name="hide_filter_hint">Filtra per nome</string> <string name="hide_filter_hint">Filtra per nome</string>
<string name="hide_scroll_up">Scorri verso l\'alto</string> <string name="hide_scroll_up">Scorri verso l\'alto</string>
<string name="hide_filters">Filtri</string> <string name="hide_filters">Filtri</string>
@@ -108,6 +110,7 @@
<!--Module Fragment--> <!--Module Fragment-->
<string name="no_info_provided">(Nessuna informazione)</string> <string name="no_info_provided">(Nessuna informazione)</string>
<string name="reboot_userspace">Riavvio veloce</string>
<string name="reboot_recovery">Riavvia in recovery</string> <string name="reboot_recovery">Riavvia in recovery</string>
<string name="reboot_bootloader">Riavvia in bootloader</string> <string name="reboot_bootloader">Riavvia in bootloader</string>
<string name="reboot_download">Riavvia in modalità download</string> <string name="reboot_download">Riavvia in modalità download</string>
@@ -169,6 +172,8 @@
<string name="superuser_notification">Notifica di accesso root</string> <string name="superuser_notification">Notifica di accesso root</string>
<string name="settings_su_reauth_title">Riautentica dopo aggiornamento</string> <string name="settings_su_reauth_title">Riautentica dopo aggiornamento</string>
<string name="settings_su_reauth_summary">Richiedi nuovamente i permessi di root dopo l\'aggiornamento di un\'app</string> <string name="settings_su_reauth_summary">Richiedi nuovamente i permessi di root dopo l\'aggiornamento di un\'app</string>
<string name="settings_su_tapjack_title">Abilita protezione anti-tapjacking</string>
<string name="settings_su_tapjack_summary">La schermata di richiesta dei permessi di root non risponderà al tocco mentre è oscurata da altre finestre o elementi in sovraimpressione</string>
<string name="settings_su_biometric_title">Abilita autenticazione biometrica</string> <string name="settings_su_biometric_title">Abilita autenticazione biometrica</string>
<string name="settings_su_biometric_summary">Utilizza l\'autenticazione biometrica per accettare le richieste di accesso root</string> <string name="settings_su_biometric_summary">Utilizza l\'autenticazione biometrica per accettare le richieste di accesso root</string>
<string name="no_biometric">Il dispositivo non è supportato o le impostazioni biometriche sono disattivate</string> <string name="no_biometric">Il dispositivo non è supportato o le impostazioni biometriche sono disattivate</string>
@@ -217,6 +222,7 @@
<string name="failure">Fallito</string> <string name="failure">Fallito</string>
<string name="hide_manager_title">Nascondendo Magisk Manager…</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="hide_manager_fail_toast">Non è stato possibile nascondere Magisk Manager.</string>
<string name="restore_manager_fail_toast">Non è stato possibile ripristinare Magisk Manager.</string>
<string name="open_link_failed_toast">Nessuna app disponibile per aprire il link</string> <string name="open_link_failed_toast">Nessuna app disponibile per aprire il link</string>
<string name="complete_uninstall">Disinstalla completamente</string> <string name="complete_uninstall">Disinstalla completamente</string>
<string name="restore_img">Ripristina immagini</string> <string name="restore_img">Ripristina immagini</string>

View File

@@ -15,7 +15,7 @@
<string name="no_connection">אין חיבור זמין</string> <string name="no_connection">אין חיבור זמין</string>
<string name="app_changelog">רשימת שינויים</string> <string name="app_changelog">רשימת שינויים</string>
<string name="manager">מנהל</string> <string name="manager">מנהל</string>
<string name="loading">טוען</string> <string name="loading">טוען</string>
<string name="update">עדכון</string> <string name="update">עדכון</string>
<string name="not_available">ל/ז</string> <string name="not_available">ל/ז</string>
<string name="hide">הסתרה</string> <string name="hide">הסתרה</string>
@@ -33,6 +33,7 @@
<string name="invalid_update_channel">ערוץ עדכון לא חוקי</string> <string name="invalid_update_channel">ערוץ עדכון לא חוקי</string>
<string name="uninstall_magisk_title">הסרת Magisk</string> <string name="uninstall_magisk_title">הסרת Magisk</string>
<string name="uninstall_magisk_msg">כל המודולים יושבתו/יוסרו!\nגישת שורש תושבת!\nהנתונים שלך עשויים להיות מוצפנים אם לא הוצפנו כבר!</string> <string name="uninstall_magisk_msg">כל המודולים יושבתו/יוסרו!\nגישת שורש תושבת!\nהנתונים שלך עשויים להיות מוצפנים אם לא הוצפנו כבר!</string>
<string name="home_check_safetynet">בדיקת SafetyNet</string>
<!--Install--> <!--Install-->
<string name="keep_force_encryption">שמירה על הצפנה בכח</string> <string name="keep_force_encryption">שמירה על הצפנה בכח</string>
@@ -41,7 +42,7 @@
<string name="install_options_title">אפשרויות</string> <string name="install_options_title">אפשרויות</string>
<string name="install_method_title">שיטה</string> <string name="install_method_title">שיטה</string>
<string name="install_next">הבא</string> <string name="install_next">הבא</string>
<string name="install_start">מצא לדרך</string> <string name="install_start">צא לדרך</string>
<string name="manager_download_install">לחץ להורדה והתקנה</string> <string name="manager_download_install">לחץ להורדה והתקנה</string>
<string name="download_zip_only">הורד ZIP בלבד</string> <string name="download_zip_only">הורד ZIP בלבד</string>
<string name="direct_install">התקנה ישירה (מומלץ)</string> <string name="direct_install">התקנה ישירה (מומלץ)</string>
@@ -55,7 +56,8 @@
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">בקשות משתמש על</string> <string name="su_request_title">בקשות משתמש על</string>
<string name="deny">דחה</string> <string name="touch_filtered_warning">מכיוון שאפליקציה מסתירה בקשה של משתמש על, Magisk לא יכולה לאמת את תגובתך</string>
<string name="deny">דחה</string>
<string name="prompt">מיידי</string> <string name="prompt">מיידי</string>
<string name="grant">הענק</string> <string name="grant">הענק</string>
<string name="su_warning">מעניק גישה מלאה להתקן שלך.\nדחה באם אינך בטוח!</string> <string name="su_warning">מעניק גישה מלאה להתקן שלך.\nדחה באם אינך בטוח!</string>
@@ -93,7 +95,7 @@
<!--SafetyNet--> <!--SafetyNet-->
<string name="safetynet_api_error">SafetyNet שגיאת API</string> <string name="safetynet_api_error">SafetyNet שגיאת API</string>
<string name="safetynet_res_invalid">התגובה אינה חוקים</string> <string name="safetynet_res_invalid">תגובה אינה חוקית</string>
<string name="safetynet_attest_success">הצליח!</string> <string name="safetynet_attest_success">הצליח!</string>
<string name="safetynet_attest_failure">האישור נכשל!</string> <string name="safetynet_attest_failure">האישור נכשל!</string>
<string name="safetynet_attest_loading">רק רגע…</string> <string name="safetynet_attest_loading">רק רגע…</string>
@@ -101,6 +103,7 @@
<!-- MagiskHide --> <!-- MagiskHide -->
<string name="show_system_app">הצגת יישומי מערכת</string> <string name="show_system_app">הצגת יישומי מערכת</string>
<string name="show_os_app">הצגת יישומי מערכת הפעלה</string>
<string name="hide_filter_hint">סינון לפי שם</string> <string name="hide_filter_hint">סינון לפי שם</string>
<string name="hide_scroll_up">גלול למעלה</string> <string name="hide_scroll_up">גלול למעלה</string>
<string name="hide_filters">מסננים</string> <string name="hide_filters">מסננים</string>
@@ -108,6 +111,7 @@
<!--Module Fragment--> <!--Module Fragment-->
<string name="no_info_provided">(לא סופק מידע)</string> <string name="no_info_provided">(לא סופק מידע)</string>
<string name="reboot_userspace">אתחול מהיר</string>
<string name="reboot_recovery">אתחול למצב שחזור</string> <string name="reboot_recovery">אתחול למצב שחזור</string>
<string name="reboot_bootloader">אתחול מצב מנהל האתחול</string> <string name="reboot_bootloader">אתחול מצב מנהל האתחול</string>
<string name="reboot_download">אתחול מצב הורדה</string> <string name="reboot_download">אתחול מצב הורדה</string>
@@ -120,8 +124,8 @@
<string name="module_action_install_external">התקן מהאחסון</string> <string name="module_action_install_external">התקן מהאחסון</string>
<string name="update_available">עדכונים זמינים</string> <string name="update_available">עדכונים זמינים</string>
<string name="module_installed">@string/home_installed_version</string> <string name="module_installed">@string/home_installed_version</string>
<string name="module_section_online">מקוון</string>
<string name="sorting_order">סדר מיון</string> <string name="sorting_order">סדר מיון</string>
<string name="external_rw_permission_denied">הענק הרשאה לאחסון כדי לאפשר פונקציונליות זו</string>
<!--Settings --> <!--Settings -->
<string name="settings_dark_mode_title">מצב עיצוב</string> <string name="settings_dark_mode_title">מצב עיצוב</string>
@@ -168,12 +172,15 @@
<string name="request_timeout">בקש פסק זמן</string> <string name="request_timeout">בקש פסק זמן</string>
<string name="superuser_notification">התראות משתמש על</string> <string name="superuser_notification">התראות משתמש על</string>
<string name="settings_su_reauth_title">אמת מחדש לאחר שדרוג</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_biometric_title">אפשר אימות ביומטרי</string> <string name="settings_su_tapjack_title">הפעלת הגנת Tapjacking</string>
<string name="settings_su_tapjack_summary">תיבת הדו שיח של משתמש העל לא תגיב לקלט כשהיא מוסתרת על ידי חלון או כיסוי אחר</string> <string name="settings_su_biometric_title">אפשר אימות ביומטרי</string>
<string name="settings_su_biometric_summary">השתמש באימות ביומטרי כדי לאפשר בקשות לשימוש במשתמש על</string> <string name="settings_su_biometric_summary">השתמש באימות ביומטרי כדי לאפשר בקשות לשימוש במשתמש על</string>
<string name="no_biometric">התקן לא נתמך או הגדרות ביומטריות אינן מאופשרות</string> <string name="no_biometric">התקן לא נתמך או הגדרות ביומטריות אינן מאופשרות</string>
<string name="settings_customization">התאמה אישית</string> <string name="settings_customization">התאמה אישית</string>
<string name="setting_add_shortcut_summary">הוסף קיצור דרך יפה במסך הבית למקרה שקשה לזהות את השם ואת הסמל לאחר הסתרת האפליקציה</string>
<string name="settings_doh_title">DNS על HTTPS</string>
<string name="settings_doh_description">עקיפת DNS מורעל במדינות מסוימות</string>
<string name="multiuser_mode">מצב מרובה משתמשים</string> <string name="multiuser_mode">מצב מרובה משתמשים</string>
<string name="settings_owner_only">בעל ההתקן בלבד</string> <string name="settings_owner_only">בעל ההתקן בלבד</string>
<string name="settings_owner_manage">אחראי ניהול ההתקן</string> <string name="settings_owner_manage">אחראי ניהול ההתקן</string>
@@ -214,8 +221,9 @@
<string name="failure">נכשל</string> <string name="failure">נכשל</string>
<string name="hide_manager_title">מסתיר את מנהל Magisk…</string> <string name="hide_manager_title">מסתיר את מנהל Magisk…</string>
<string name="hide_manager_fail_toast">הסתרת מנהל Magisk כשלה.</string> <string name="hide_manager_fail_toast">הסתרת מנהל Magisk כשלה.</string>
<string name="open_link_failed_toast">לא נמצאו יישומים לפתיחת קישור זה</string> <string name="restore_manager_fail_toast">שחזור מנהל Magisk נכשל</string>
<string name="complete_uninstall">הוסר סהצלחה</string> <string name="open_link_failed_toast">לא נמצאו יישומים לפתיחת קישור זה</string>
<string name="complete_uninstall">הסרה מלאה</string>
<string name="restore_img">שיחזור תמונות</string> <string name="restore_img">שיחזור תמונות</string>
<string name="restore_img_msg">משחזר…</string> <string name="restore_img_msg">משחזר…</string>
<string name="restore_done">השיחזור בוצע!</string> <string name="restore_done">השיחזור בוצע!</string>
@@ -229,5 +237,8 @@
<string name="authenticate">אימות</string> <string name="authenticate">אימות</string>
<string name="unsupport_magisk_title">גרסת Magisk אינה נתמכת</string> <string name="unsupport_magisk_title">גרסת Magisk אינה נתמכת</string>
<string name="unsupport_magisk_msg">גרסה זו של מנהל Magisk אינה תומכת בגרסת Magisk הנמוכה מ-%1$s.\n\nהיישום יתנהג כאילו לא הותקן Magisk, אנא שדרג את Magisk בהקדם האפשרי.</string> <string name="unsupport_magisk_msg">גרסה זו של מנהל Magisk אינה תומכת בגרסת Magisk הנמוכה מ-%1$s.\n\nהיישום יתנהג כאילו לא הותקן Magisk, אנא שדרג את Magisk בהקדם האפשרי.</string>
<string name="external_rw_permission_denied">הענק הרשאת אחסון להפעלת פונקציונליות זו</string>
<string name="add_shortcut_title">הוסף קיצור דרך למסך הבית</string>
<string name="add_shortcut_msg">לאחר שהסתיר את Magisk Manager, השם והסמל שלו עשויים להיות קשים לזיהוי. האם אתה רוצה להוסיף קיצור דרך יפה למסך הבית?</string>
<string name="app_not_found">לא נמצא יישום לטיפול בפעולה זו</string>
</resources> </resources>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="SplashTheme" parent="Theme.Splash" />
<style name="Foundation" parent="Theme.Foundation" />
</resources>

View File

@@ -0,0 +1,244 @@
<resources>
<!--Sections-->
<string name="modules">ਮੋਡੀਊਲ</string>
<string name="superuser">ਸੁਪਰਯੂਜ਼ਰ</string>
<string name="logs">ਲੋਗਜ਼</string>
<string name="settings">ਸੈਟਿੰਗਜ਼</string>
<string name="refresh">ਸਥਾਨਕ ਡੇਟਾ ਨੂੰ ਤਾਜ਼ਾ ਕਰੋ</string>
<string name="install">ਇੰਸਟਾਲ</string>
<string name="section_home">ਹੋਮ</string>
<string name="section_theme">ਥੀਮ</string>
<string name="safetynet">ਸੇਫਟੀਨੇਟ</string>
<!--Home-->
<string name="no_connection">ਕੋਈ ਸੰਪਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ</string>
<string name="app_changelog">ਬਦਲਾਓ</string>
<string name="manager">ਮੈਨੇਜਰ</string>
<string name="loading">ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ</string>
<string name="update">ਅੱਪਡੇਟ</string>
<string name="not_available">N/A</string>
<string name="hide">ਓਹਲੇ</string>
<string name="status">ਸਥਿਤੀ</string>
<string name="home_package">ਪੈਕੇਜ</string>
<string name="home_notice_content">ਹਮੇਸ਼ਾਂ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਓਪਨ-ਸੋਰਸ ਮੈਜਿਸਕ ਮੈਨੀਜ਼ਰ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੇ ਹੋ। ਅਗਿਆਤ ਸਰੋਤ ਪ੍ਰਬੰਧਕ ਦੁਰਭਾਵਨਾਤਮਕ ਕਾਰਜ ਕਰ ਸਕਦੇ ਹਨ।</string>
<string name="home_support_title">ਸਾਡਾ ਸਮਰਥਨ ਕਰੋ</string>
<string name="home_item_source">ਸਰੋਤ</string>
<string name="home_support_content">ਮੈਜਿਸਕ ਮੁਫਤ ਅਤੇ ਖੁੱਲਾ ਸਰੋਤ ਹੈ, ਅਤੇ ਹਮੇਸ਼ਾਂ ਰਹੇਗਾ। ਹਾਲਾਂਕਿ, ਤੁਸੀਂ ਦਿਖਾ ਸਕਦੇ ਹੋ ਕਿ ਤੁਸੀਂ ਇੱਕ ਛੋਟਾ ਜਿਹਾ ਦਾਨ ਭੇਜ ਕੇ ਦੇਖਭਾਲ ਕਰਦੇ ਹੋ।</string>
<string name="home_status_normal">ਸਧਾਰਨ</string>
<string name="home_status_stub">ਸਟੱਬ</string>
<string name="home_installed_version">ਇੰਸਟਾਲਡ</string>
<string name="home_latest_version">ਨਵੀਨਤਮ</string>
<string name="invalid_update_channel">ਅਵੈਧ ਅਪਡੇਟ ਚੈਨਲ</string>
<string name="uninstall_magisk_title">ਮੈਜਿਸਕ ਨੂੰ ਅਣਇੰਸਟੌਲ ਕਰੋ</string>
<string name="uninstall_magisk_msg">ਸਾਰੇ ਮੋਡੀਊਲ ਅਯੋਗ/ਮਿਟਾ ਦਿੱਤੇ ਜਾਣਗੇ!\n ਰੂਟ ਨੂੰ ਹਟਾਇਆ ਜਾਏਗਾ!\n ਤੁਹਾਡਾ ਡਾਟਾ ਸੰਭਾਵਤ ਤੌਰ ਤੇ ਐਨਕ੍ਰਿਪਟ ਕੀਤਾ ਗਿਆ ਹੈ ਜੇ ਪਹਿਲਾਂ ਹੀ ਨਹੀਂ!</string>
<string name="home_check_safetynet">ਸੇਫਟੀਨੇਟ ਦੀ ਜਾਂਚ ਕਰੋ</string>
<!--Install-->
<string name="keep_force_encryption">ਫੋਰਸ ਇਨਕ੍ਰਿਪਸ਼ਨ ਨੂੰ ਸੁਰੱਖਿਅਤ ਰੱਖੋ</string>
<string name="keep_dm_verity">AVB 2.0/dm-verity ਨੂੰ ਸੁਰੱਖਿਅਤ ਰੱਖੋ</string>
<string name="recovery_mode">ਰਿਕਵਰੀ ਮੋਡ</string>
<string name="install_options_title">ਚੋਣ</string>
<string name="install_method_title">ਤਰੀਕਾ</string>
<string name="install_next">ਅੱਗੇ</string>
<string name="install_start">ਤਾਂ ਆਓ ਸ਼ੁਰੂ ਕਰੀਏ!</string>
<string name="manager_download_install">ਡਾਊਨਲੋਡ ਅਤੇ ਇੰਸਟੌਲ ਕਰਨ ਲਈ ਦਬਾਓ</string>
<string name="download_zip_only">ਸਿਰਫ ਜ਼ਿਪ ਡਾਊਨਲੋਡ ਕਰੋ</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="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>
<string name="flash_screen_title">ਇੰਸਟਾਲੇਸ਼ਨ</string>
<!--Superuser-->
<string name="su_request_title">ਸੁਪਰਯੂਜ਼ਰ ਮੰਗ</string>
<string name="deny">ਇਨਕਾਰ ਕਰੋ</string>
<string name="prompt">ਸੰਕੇਤ ਦਿਖਾਓ</string>
<string name="grant">ਆਗਿਆ ਦਿਓ</string>
<string name="su_warning">ਇਹ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਤੇ ਪੂਰੀ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦੇਵੇਗਾ,\n ਜੇ ਤੁਹਾਨੂੰ ਯਕੀਨ ਨਹੀਂ ਹੈ ਤਾਂ ਇਨਕਾਰ ਕਰੋ!</string>
<string name="forever">ਹਮੇਸ਼ਾ</string>
<string name="once">ਇਕ ਵਾਰ</string>
<string name="tenmin">10 ਮਿੰਟ</string>
<string name="twentymin">20 ਮਿੰਟ</string>
<string name="thirtymin">30 ਮਿੰਟ</string>
<string name="sixtymin">60 ਮਿੰਟ</string>
<string name="su_allow_toast"> %1$s ਨੂੰ ਸੁਪਰਯੂਜ਼ਰ ਅਧਿਕਾਰ ਦਿੱਤੇ ਗਏ ਸਨ</string>
<string name="su_deny_toast"> %1$s ਸੁਪਰਯੂਜ਼ਰ ਅਧਿਕਾਰਾਂ ਤੋਂ ਇਨਕਾਰ ਕੀਤਾ ਗਿਆ ਸੀ</string>
<string name="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="superuser_toggle_notification">ਸੂਚਨਾ</string>
<string name="superuser_toggle_revoke">ਅਧਿਕਾਰ ਵਾਪਸ ਲਓ</string>
<string name="superuser_policy_none">ਅਜੇ ਤੱਕ ਕਿਸੇ ਵੀ ਐਪ ਨੇ ਸੁਪਰਯੂਜ਼ਰ ਲਈ ਆਗਿਆ ਨਹੀਂ ਮੰਗੀ ਹੈ।</string>
<!--Logs-->
<string name="log_data_none">ਕੋਈ ਲੌਗਸ ਨਹੀਂ, ਆਪਣੀ ਸੁਪਰਯੂਜ਼ਰ ਸਮਰਥਿਤ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਹੋਰ ਵਰਤਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</string>
<string name="log_data_magisk_none">ਮੈਜਿਸਕ ਲੌਗਸ ਖਾਲੀ ਹਨ, ਇਹ ਅਜੀਬ ਹੈ।</string>
<string name="menuSaveLog">ਲੌਗ ਸੇਵ ਕਰੋ</string>
<string name="menuClearLog">ਲੌਗ ਸਾਫ ਕਰੋ</string>
<string name="logs_cleared">ਲੌਗ ਸਫਲਤਾਪੂਰਕ ਸਾਫ ਹੋ ਗਏ ਹਨ।</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">ਟੀਚਾ UID: %1$d</string>
<!--SafetyNet-->
<string name="safetynet_api_error">ਸੇਫਟੀਨੇਟ ਏਪੀਆਈ ਗਲਤੀ</string>
<string name="safetynet_res_invalid">ਜਵਾਬ ਅਵੈਧ ਹੈ</string>
<string name="safetynet_attest_success">ਸਫਲਤਾ!</string>
<string name="safetynet_attest_failure">ਤਸਦੀਕ ਅਸਫਲ!</string>
<string name="safetynet_attest_loading">ਸਿਰਫ ਇਕ ਸਕਿੰਟ…</string>
<string name="safetynet_attest_restart">ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ</string>
<!-- MagiskHide -->
<string name="show_system_app">ਸਿਸਟਮ ਐਪਸ ਦਿਖਾਓ</string>
<string name="show_os_app">OS ਐਪਲੀਕੇਸ਼ਨ ਦਿਖਾਓ</string>
<string name="hide_filter_hint">ਨਾਮ ਦੁਆਰਾ ਫਿਲਟਰ ਕਰੋ</string>
<string name="hide_scroll_up">ਉੱਪਰ ਸਕ੍ਰੌਲ ਕਰੋ</string>
<string name="hide_filters">ਫਿਲਟਰ</string>
<string name="hide_search">ਖੋਜੋ</string>
<!--Module -->
<string name="no_info_provided">(ਕੋਈ ਜਾਣਕਾਰੀ ਨਹੀਂ ਦਿੱਤੀ ਗਈ)</string>
<string name="reboot_userspace">ਸਾਫਟ ਰੀਬੂਟ</string>
<string name="reboot_recovery">ਰਿਕਵਰੀ ਰੀਬੂਟ</string>
<string name="reboot_bootloader">ਬੂਟਲੋਡਰ ਰੀਬੂਟ</string>
<string name="reboot_download">ਡਾਊਨਲੋਡ ਮੋਡ ਰੀਬੂਟ</string>
<string name="reboot_edl">EDL ਰੀਬੂਟ</string>
<string name="module_version_author"> %2$s ਦੇ ਦੁਆਰਾ %1$s</string>
<string name="module_section_pending">ਅਪਡੇਟਸ</string>
<string name="module_section_pending_action">ਸਾਰੇ ਅਪਡੇਟ ਕਰੋ</string>
<string name="module_state_remove">ਹਟਾਓ</string>
<string name="module_state_restore">ਰੀਸਟੋਰ ਕਰੋ</string>
<string name="module_action_install_external">ਸਟੋਰੇਜ ਤੋਂ ਇੰਸਟਾਲ ਕਰੋ</string>
<string name="update_available">ਅਪਡੇਟ ਉਪਲੱਬਧ ਹੈ</string>
<string name="module_installed">ਇੰਸਟਾਲਡ</string>
<string name="module_section_online">ਆਨਲਾਈਨ</string>
<string name="sorting_order">ਲੜੀਬੱਧ ਵਿਧੀ</string>
<!--Settings -->
<string name="settings_dark_mode_title">ਥੀਮ ਮੋਡ</string>
<string name="settings_dark_mode_message">ਕੋਈ ਥੀਮ ਚੁਣੋ ਜੋ ਤੁਹਾਡੀ ਸ਼ੈਲੀ ਦੇ ਅਨੁਕੂਲ ਹੋਵੇ!</string>
<string name="settings_dark_mode_light">ਹਮੇਸ਼ਾਂ ਚਿੱਟੇ ਰੰਗ ਦੀ</string>
<string name="settings_dark_mode_system">ਸਿਸਟਮ ਦੇ ਅਨੁਸਾਰ</string>
<string name="settings_dark_mode_dark">ਹਮੇਸ਼ਾ ਗਹਿਰੇ ਰੰਗ ਦੀ</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">ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਓਹਲੇ ਕਰੋ</string>
<string name="settings_hide_manager_summary">ਬੇਤਰਤੀਬੇ ਪੈਕੇਜ ਅਤੇ ਐਪ ਦੇ ਨਾਮਾਂ ਨਾਲ ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਨੂੰ ਰਿ੫ੇਕੇਜ ਕਰੋ</string>
<string name="settings_restore_manager_title">ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਨੂੰ ਰੀਸਟੋਰ ਕਰੋ</string>
<string name="settings_restore_manager_summary">ਅਸਲੀ ਪੈਕੇਜ ਅਤੇ ਐਪਲੀਕੇਸ਼ ਦੇ ਨਾਮ ਨਾਲ ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਨੂੰ ਰੀਸਟੋਰ ਕਰੋ</string>
<string name="language">ਭਾਸ਼ਾ</string>
<string name="system_default">(ਸਿਸਟਮ ਡਿਫੌਲਟ)</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_magiskhide_summary">ਵੱਖ ਵੱਖ ਕਿਸਮਾਂ ਦੀਆਂ ਖੋਜਾਂ ਤੋਂ ਬਚਣ ਲਈ ਮੈਜਿਸਕ ਨੂੰ ਓਹਲੇ ਕਰੋ</string>
<string name="settings_hosts_title">Systemless ਹੋਸਟ</string>
<string name="settings_hosts_summary">Adblock ਐਪਸ ਲਈ Systemless ਹੋਸਟ ਦੀ ਸਹਿਯੋਗ</string>
<string name="settings_hosts_toast">Systemless ਹੋਸਟ ਮੋਡੀਊਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ</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">ਐਪਸ ਅਤੇ ਐਡਬੀ</string>
<string name="settings_su_app">ਸਿਰਫ ਐਪਸ</string>
<string name="settings_su_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="settings_su_reauth_title">ਅਪਗ੍ਰੇਡ ਹੋਣ ਤੋਂ ਬਾਅਦ ਪ੍ਰਮਾਣਿਕਤਾ</string>
<string name="settings_su_reauth_summary">ਇੱਕ ਐਪ ਦੇ ਅਪਡੇਟ ਹੋਣ ਤੋਂ ਬਾਅਦ ਸੁਪਰਯੂਜ਼ਰ ਆਗਿਆ ਪ੍ਰਮਾਣਿਤ ਕਰੋ</string>
<string name="settings_su_biometric_title">ਬਾਇਓਮੈਟ੍ਰਿਕ ਪ੍ਰਮਾਣਿਕਤਾ ਦਾ ਯੋਗ ਕਰੋ</string>
<string name="settings_su_biometric_summary">ਸੁਪਰਯੂਜ਼ਰ ਦੀ ਆਗਿਆ ਦੇਣ ਲਈ ਬਾਇਓਮੈਟ੍ਰਿਕ ਪ੍ਰਮਾਣੀਕਰਣ ਦੀ ਵਰਤੋਂ ਕਰੋ</string>
<string name="no_biometric">ਅਸਮਰਥਿਤ ਡਿਵਾਈਸ ਜਾਂ ਕੋਈ ਬਾਇਓਮੈਟ੍ਰਿਕ ਸੈਟਿੰਗ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ</string>
<string name="settings_customization">ਕਸਟਮਾਈਜੇਸ਼ਨ</string>
<string name="setting_add_shortcut_summary">ਐਪ ਨੂੰ ਲੁਕਾਉਣ ਤੋਂ ਬਾਅਦ ਨਾਮ ਅਤੇ ਆਈਕਾਨ ਨੂੰ ਪਛਾਣਨਾ ਮੁਸ਼ਕਲ ਹੈ, ਤਾਂ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿਚ ਇਕ ਸੁੰਦਰ ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰੋ</string>
<string name="settings_doh_title">DNS ਉੱਤੇ HTTPS</string>
<string name="settings_doh_description">ਕੁਝ ਦੇਸ਼ਾਂ ਵਿੱਚ ਚੱਲ ਰਹੇ DNS ਵਿਸ਼ਾਕਤਤਾ ਦਾ ਹੱਲ</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>
<!--Notifications-->
<string name="update_channel">ਮੈਜਿਸਕ ਅਪਡੇਟ</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">ਮੈਜਿਸਕ ਅਪਡੇਟ ਉਪਲੱਬਧ!</string>
<string name="manager_update_title">ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਲਈ ਅਪਡੇਟ ਉਪਲੱਬਧ ਹੈ!</string>
<!--Toasts, Dialogs-->
<string name="yes">ਹਾਂ</string>
<string name="no">ਨਹੀਂ</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="release_notes">ਰੀਲਿਜ਼ ਨੋਟਿਸ</string>
<string name="repo_cache_cleared">ਰਿਪੋ ਕੈਚੇ ਸਾਫ਼ ਕੀਤਾ</string>
<string name="flashing">ਫਲੈਸ਼ਿੰਗ …</string>
<string name="done">ਸਫਲ ਹੋਇਆ!</string>
<string name="failure">ਅਸਫਲ ਹੋਇਆ</string>
<string name="hide_manager_title">ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਨੂੰ ਲੁਕਾਇਆ ਜਾ ਰਿਹਾ ਹੈ …</string>
<string name="hide_manager_fail_toast">ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਓਹਲੇ ਕਰਨ ਵਿੱਚ ਅਸਫਲ</string>
<string name="restore_manager_fail_toast">ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਨੂੰ ਰਿਸਟੋਰ ਕਰਨਾ ਵਿਫਲ ਹੋਇਆ</string>
<string name="open_link_failed_toast">ਲਿੰਕ ਖੋਲ੍ਹਣ ਲਈ ਕੋਈ ਐਪਲੀਕੇਸ਼ਨ ਨਹੀਂ ਮਿਲੀ</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">ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਇੱਕ ਮੁਫਤ ਅਤੇ ਓਪਨ ਸੋਰਸ ਐਪ ਹੈ ਜੋ ਗੂਗਲ ਦੇ ਮਲਕੀਅਤ ਸੁਰੱਖਿਆ ਕੋਡ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰਦਾ। ਕੀ ਤੁਸੀਂ ਸੁਰੱਖਿਆ ਨੂੰ ਵੇਖਣ ਲਈ ਮੈਸਿਕ ਮੈਨੇਜਰ ਨੂੰ ਇੱਕ ਐਕਸਟੈਂਸ਼ਨ ਡਾ ਡਾਊਨਲੋਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣਾ ਚਾਹੁੰਦੇ ਹੋ?</string>
<string name="setup_fail">ਸੈਟਅਪ ਅਸਫਲ ਹੋਇਆ</string>
<string name="env_fix_title">ਵਾਧੂ ਸੈਟਅਪ ਚਾਹੀਦਾ ਹੈ</string>
<string name="env_fix_msg">ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਤੇ ਮੈਜਿਸਕ ਨੂੰ ਸਹੀ ਤਰ੍ਹਾਂ ਕੰਮ ਕਰਨ ਲਈ ਵਾਧੂ ਸੈਟਅਪ ਦੀ ਲੋੜ ਹੈ। ਇਹ ਇੱਕ ਮੈਜਿਸਕ ਸੈਟਅਪ ਜ਼ਿਪ ਡਾਉਨਲੋਡ ਕਰੇਗਾ, ਕੀ ਤੁਸੀਂ ਅੱਗੇ ਵਧਣਾ ਚਾਹੋਗੇ?</string>
<string name="setup_msg">ਵਾਤਾਵਰਣ ਸੈਟਅਪ ਚੱਲ ਰਿਹਾ ਹੈ …</string>
<string name="authenticate">ਪ੍ਰਮਾਣਿਤ ਕਰੋ</string>
<string name="unsupport_magisk_title">ਗ਼ੈਰ ਮੈਜਿਸਕ ਵਰਜਨ</string>
<string name="unsupport_magisk_msg">ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਦਾ ਇਹ ਵਰਜਨ ਮੈਜਿਸਕ ਵਰਜਨ %1$s ਤੋਂ ਘੱਟ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦਾ।\n\n ਐਪ ਇਸ ਤਰ੍ਹਾਂ ਦਾ ਵਿਵਹਾਰ ਕਰੇਗੀ ਜਿਵੇਂ ਮੈਜਿਸਕ ਇੰਸਟਾਲ ਨਹੀਂ ਹੈ, ਕਿਰਪਾ ਕਰਕੇ ਜਲਦੀ ਹੀ ਮੈਜਿਸਕ ਨੂੰ ਅਪਗ੍ਰੇਡ ਕਰੋ।</string>
<string name="external_rw_permission_denied">ਇਸ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਸਟੋਰੇਜ ਦੀ ਆਗਿਆ ਦਿਓ</string>
<string name="add_shortcut_title">ਹੋਮਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰੋ</string>
<string name="add_shortcut_msg">ਮੈਜਿਸਕ ਮੈਨੇਜਰ ਨੂੰ ਲੁਕਾਉਣ ਤੋਂ ਬਾਅਦ ਇਸਦੇ ਨਾਮ ਅਤੇ ਆਈਕਾਨ ਦੀ ਪਛਾਣ ਕਰਨਾ ਮੁਸ਼ਕਲ ਹੋ ਸਕਦਾ ਹੈ, ਕੀ ਤੁਸੀਂ ਹੋਮਸਕ੍ਰੀਨ ਤੇ ਇੱਕ ਵਧੀਆ ਲੁੱਕ ਸ਼ੌਰਟਕਟ ਸ਼ਾਮਲ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?</string>
<string name="app_not_found">ਇਸ ਐਕਸ਼ਨ ਨੂੰ ਸੰਭਾਲਣ ਲਈ ਕੋਈ ਐਪਲੀਕੇਸ਼ਨ ਨਹੀਂ ਮਿਲੀ</string>
</resources>

View File

@@ -22,7 +22,7 @@
<string name="status">Stare</string> <string name="status">Stare</string>
<string name="home_package">Pachet</string> <string name="home_package">Pachet</string>
<string name="home_notice_content">Asigură-te întotdeauna că folosești aplicația open-source Magisk Manager. Managerul din surse necunoscute poate efectua acțiuni rău-intenționate.</string> <string name="home_notice_content">Asigură-te întotdeauna că folosești aplicația open-source Magisk Manager. Managerul din surse necunoscute poate efectua acțiuni rău-intenționate!</string>
<string name="home_support_title">Sprijină-ne</string> <string name="home_support_title">Sprijină-ne</string>
<string name="home_item_source">Sursă</string> <string name="home_item_source">Sursă</string>
<string name="home_support_content">Magisk este și va fi întotdeauna gratuit și open-source. Cu toate acestea, ne poți arăta că îți pasă trimițând o mică donație.</string> <string name="home_support_content">Magisk este și va fi întotdeauna gratuit și open-source. Cu toate acestea, ne poți arăta că îți pasă trimițând o mică donație.</string>
@@ -55,7 +55,8 @@
<string name="flash_screen_title">Instalare</string> <string name="flash_screen_title">Instalare</string>
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">Solicitare de superutilizator</string> <string name="su_request_title">Cerere de superutilizator</string>
<string name="touch_filtered_warning">Deoarece o aplicație ascunde o cerere de superutilizator, Magisk nu îți poate verifica răspunsul</string>
<string name="deny">Refuză</string> <string name="deny">Refuză</string>
<string name="prompt">Solicită</string> <string name="prompt">Solicită</string>
<string name="grant">Acordă</string> <string name="grant">Acordă</string>
@@ -81,14 +82,14 @@
<string name="superuser_toggle_notification">Notificări</string> <string name="superuser_toggle_notification">Notificări</string>
<string name="superuser_toggle_revoke">Revocă</string> <string name="superuser_toggle_revoke">Revocă</string>
<string name="superuser_policy_none">Nicio aplicație nu a solicitat încă permisiuni de superutilizator.</string> <string name="superuser_policy_none">Nicio aplicație nu a cerut încă permisiuni de superutilizator.</string>
<!--Logs--> <!--Logs-->
<string name="log_data_none">Nu există jurnale, încearcă să folosești ceva mai mult aplicațiile cu acces de superutilizator.</string> <string name="log_data_none">Nu există jurnale, încearcă să folosești ceva mai mult aplicațiile cu acces de superutilizator</string>
<string name="log_data_magisk_none">Jurnalele Magisk sunt goale, asta-i ciudat.</string> <string name="log_data_magisk_none">Jurnalele Magisk sunt goale, asta-i ciudat</string>
<string name="menuSaveLog">Salvează jurnalul</string> <string name="menuSaveLog">Salvează jurnalul</string>
<string name="menuClearLog">Golește jurnalul acum</string> <string name="menuClearLog">Golește jurnalul acum</string>
<string name="logs_cleared">Jurnal golit cu succes.</string> <string name="logs_cleared">Jurnal golit cu succes</string>
<string name="pid">PID: %1$d</string> <string name="pid">PID: %1$d</string>
<string name="target_uid">UID țintă: %1$d</string> <string name="target_uid">UID țintă: %1$d</string>
@@ -100,15 +101,17 @@
<string name="safetynet_attest_loading">Așteaptă o clipă…</string> <string name="safetynet_attest_loading">Așteaptă o clipă…</string>
<string name="safetynet_attest_restart">Încearcă din nou</string> <string name="safetynet_attest_restart">Încearcă din nou</string>
<!-- MagiskHide --> <!--MagiskHide-->
<string name="show_system_app">Afișează aplicațiile de sistem</string> <string name="show_system_app">Afișează aplicațiile de sistem</string>
<string name="show_os_app">Afișează aplicațiile SO-ului</string>
<string name="hide_filter_hint">Filtrează după nume</string> <string name="hide_filter_hint">Filtrează după nume</string>
<string name="hide_scroll_up">Derulează în sus</string> <string name="hide_scroll_up">Derulează în sus</string>
<string name="hide_filters">Filtre</string> <string name="hide_filters">Filtre</string>
<string name="hide_search">Căutare</string> <string name="hide_search">Căutare</string>
<!--Module --> <!--Module-->
<string name="no_info_provided">(Nu sunt furnizate informații)</string> <string name="no_info_provided">(Nu sunt furnizate informații)</string>
<string name="reboot_userspace">Repornire software</string>
<string name="reboot_recovery">Repornește în modul recovery</string> <string name="reboot_recovery">Repornește în modul recovery</string>
<string name="reboot_bootloader">Repornește în modul bootloader</string> <string name="reboot_bootloader">Repornește în modul bootloader</string>
<string name="reboot_download">Repornește în modul download</string> <string name="reboot_download">Repornește în modul download</string>
@@ -124,7 +127,7 @@
<string name="module_section_online">Online</string> <string name="module_section_online">Online</string>
<string name="sorting_order">Ordine de sortare</string> <string name="sorting_order">Ordine de sortare</string>
<!--Settings --> <!--Settings-->
<string name="settings_dark_mode_title">Mod pentru temă</string> <string name="settings_dark_mode_title">Mod pentru temă</string>
<string name="settings_dark_mode_message">Selectează modul care ți se pliază cel mai bine stilului!</string> <string name="settings_dark_mode_message">Selectează modul care ți se pliază cel mai bine stilului!</string>
<string name="settings_dark_mode_light">Mereu deschis</string> <string name="settings_dark_mode_light">Mereu deschis</string>
@@ -133,7 +136,7 @@
<string name="settings_download_path_title">Cale de descărcare</string> <string name="settings_download_path_title">Cale de descărcare</string>
<string name="settings_download_path_message">Fișierele vor fi salvate în %1$s</string> <string name="settings_download_path_message">Fișierele vor fi salvate în %1$s</string>
<string name="settings_clear_cache_title">Golește cache-ul depozitelor</string> <string name="settings_clear_cache_title">Golește cache-ul depozitelor</string>
<string name="settings_clear_cache_summary">Golește informațiile memorate în cache pentru depozitele online. Acest lucru forțează actualizarea aplicației online.</string> <string name="settings_clear_cache_summary">Golește informațiile memorate în cache pentru depozitele online. Acest lucru forțează actualizarea aplicației online</string>
<string name="settings_hide_manager_title">Ascunde Magisk Manager</string> <string name="settings_hide_manager_title">Ascunde Magisk Manager</string>
<string name="settings_hide_manager_summary">Reîmpachetează Magisk Manager cu numele aleatorii pentru pachet și aplicație</string> <string name="settings_hide_manager_summary">Reîmpachetează Magisk Manager cu numele aleatorii pentru pachet și aplicație</string>
<string name="settings_restore_manager_title">Restaurează Magisk Manager</string> <string name="settings_restore_manager_title">Restaurează Magisk Manager</string>
@@ -166,10 +169,12 @@
<string name="settings_su_request_60">60 de secunde</string> <string name="settings_su_request_60">60 de secunde</string>
<string name="superuser_access">Acces pentru superutilizator</string> <string name="superuser_access">Acces pentru superutilizator</string>
<string name="auto_response">Răspuns automat</string> <string name="auto_response">Răspuns automat</string>
<string name="request_timeout">Expirare pentru solicitare</string> <string name="request_timeout">Expirare pentru cerere</string>
<string name="superuser_notification">Notificare de superutilizator</string> <string name="superuser_notification">Notificare de superutilizator</string>
<string name="settings_su_reauth_title">Reautentificare după actualizare</string> <string name="settings_su_reauth_title">Reautentificare după actualizare</string>
<string name="settings_su_reauth_summary">Reautentifică permisiunile pentru superutilizator după o actualizare a aplicației</string> <string name="settings_su_reauth_summary">Reautentifică permisiunile pentru superutilizator după o actualizare a aplicației</string>
<string name="settings_su_tapjack_title">Activează protecția față de tapjacking</string>
<string name="settings_su_tapjack_summary">Caseta de dialog pentru solicitarea drepturilor de superutilizator nu va răspunde la input cât timp este ascunsă de orice altă fereastră sau suprapunere</string>
<string name="settings_su_biometric_title">Activează autentificarea biometrică</string> <string name="settings_su_biometric_title">Activează autentificarea biometrică</string>
<string name="settings_su_biometric_summary">Folosește autentificarea biometrică pentru a permite cereri de superutilizator</string> <string name="settings_su_biometric_summary">Folosește autentificarea biometrică pentru a permite cereri de superutilizator</string>
<string name="no_biometric">Dispozitiv nesuportat sau nu sunt activate setări biometrice</string> <string name="no_biometric">Dispozitiv nesuportat sau nu sunt activate setări biometrice</string>
@@ -183,7 +188,7 @@
<string name="settings_owner_manage">Gestionat de proprietarul dispozitivului</string> <string name="settings_owner_manage">Gestionat de proprietarul dispozitivului</string>
<string name="settings_user_independent">Utilizator independent</string> <string name="settings_user_independent">Utilizator independent</string>
<string name="owner_only_summary">Numai proprietarul are acces la root</string> <string name="owner_only_summary">Numai proprietarul are acces la root</string>
<string name="owner_manage_summary">Numai proprietarul poate să gestioneze accesul la root și să primească solicitări</string> <string name="owner_manage_summary">Numai proprietarul poate să gestioneze accesul la root și să primească cereri</string>
<string name="user_indepenent_summary">Fiecare utilizator are propriile sale reguli separate pentru root</string> <string name="user_indepenent_summary">Fiecare utilizator are propriile sale reguli separate pentru root</string>
<string name="mount_namespace_mode">Modul spațiului de nume pentru montare</string> <string name="mount_namespace_mode">Modul spațiului de nume pentru montare</string>
@@ -215,9 +220,10 @@
<string name="repo_cache_cleared">Cache-ul depozitelor golit</string> <string name="repo_cache_cleared">Cache-ul depozitelor golit</string>
<string name="flashing">Se scrie în memoria flash…</string> <string name="flashing">Se scrie în memoria flash…</string>
<string name="done">Terminat!</string> <string name="done">Terminat!</string>
<string name="failure">Eșec</string> <string name="failure">Eșec!</string>
<string name="hide_manager_title">Se ascunde Magisk Manager…</string> <string name="hide_manager_title">Se ascunde Magisk Manager…</string>
<string name="hide_manager_fail_toast">Ascunderea Magisk Manager a eșuat.</string> <string name="hide_manager_fail_toast">Ascunderea Magisk Manager a eșuat</string>
<string name="restore_manager_fail_toast">Restaurarea Magisk Manager a eșuat</string>
<string name="open_link_failed_toast">Nu a fost găsită nicio aplicație pentru a deschide linkul</string> <string name="open_link_failed_toast">Nu a fost găsită nicio aplicație pentru a deschide linkul</string>
<string name="complete_uninstall">Finalizează dezinstalarea</string> <string name="complete_uninstall">Finalizează dezinstalarea</string>
<string name="restore_img">Restaurează imagini</string> <string name="restore_img">Restaurează imagini</string>

View File

@@ -22,7 +22,7 @@
<string name="status">Stav</string> <string name="status">Stav</string>
<string name="home_package">Balíček</string> <string name="home_package">Balíček</string>
<string name="home_notice_content">Vždy sa uistite, že používate Magisk Manager s otvoreným kódom. Správca z neznámeho zdroja môže vykonávať škodlivé akcie.</string> <string name="home_notice_content">Vždy sa uistite, že používate Magisk Manager s otvoreným kódom. Správca z neznámeho zdroja môže vykonávať škodlivé akcie!</string>
<string name="home_support_title">Podporte nás</string> <string name="home_support_title">Podporte nás</string>
<string name="home_item_source">Zdroj</string> <string name="home_item_source">Zdroj</string>
<string name="home_support_content">Magisk je a vždy bude slobodný a s otvoreným kódom. Môžete nám však ukázať, že vám na tom záleží zaslaním malého daru.</string> <string name="home_support_content">Magisk je a vždy bude slobodný a s otvoreným kódom. Môžete nám však ukázať, že vám na tom záleží zaslaním malého daru.</string>
@@ -44,7 +44,7 @@
<string name="install_next">Ďalej</string> <string name="install_next">Ďalej</string>
<string name="install_start">Poďme na to</string> <string name="install_start">Poďme na to</string>
<string name="manager_download_install">Stlačte pre stiahnutie a inštaláciu</string> <string name="manager_download_install">Stlačte pre stiahnutie a inštaláciu</string>
<string name="download_zip_only">Len tiahnuť zip</string> <string name="download_zip_only">Len stiahnuť zip</string>
<string name="direct_install">Priama inštalácia (Odporúča sa)</string> <string name="direct_install">Priama inštalácia (Odporúča sa)</string>
<string name="install_inactive_slot">Inštalovať na neaktívny slot (Po OTA)</string> <string name="install_inactive_slot">Inštalovať na neaktívny slot (Po OTA)</string>
<string name="install_inactive_slot_msg">Vaše zariadenie bude po reštarte PRINÚTENÉ nabootovať do aktuálne neaktívneho slotu!\nTúto voľbu použite iba po skončení OTA.\nPokračovať?</string> <string name="install_inactive_slot_msg">Vaše zariadenie bude po reštarte PRINÚTENÉ nabootovať do aktuálne neaktívneho slotu!\nTúto voľbu použite iba po skončení OTA.\nPokračovať?</string>
@@ -85,11 +85,11 @@
<string name="superuser_policy_none">Žiadna aplikácia zatiaľ nepožiadala o povolenie Superužívateľa.</string> <string name="superuser_policy_none">Žiadna aplikácia zatiaľ nepožiadala o povolenie Superužívateľa.</string>
<!--Logs--> <!--Logs-->
<string name="log_data_none">Nie sú žiadne záznamy, skúste nejakú appku vyžadujúcu práva Superužívateľa.</string> <string name="log_data_none">Nie sú žiadne záznamy, skúste nejakú appku vyžadujúcu práva Superužívateľa</string>
<string name="log_data_magisk_none">Záznamy Magisku sú prázdne, to je divné.</string> <string name="log_data_magisk_none">Záznamy Magisku sú prázdne, to je divné</string>
<string name="menuSaveLog">Uložiť záznam</string> <string name="menuSaveLog">Uložiť záznam</string>
<string name="menuClearLog">Odstrániť záznam</string> <string name="menuClearLog">Odstrániť záznam</string>
<string name="logs_cleared">Záznam úspešne odstránený.</string> <string name="logs_cleared">Záznam úspešne odstránený</string>
<string name="pid">PID:%1$d</string> <string name="pid">PID:%1$d</string>
<string name="target_uid">Cieľový UID: %1$d</string> <string name="target_uid">Cieľový UID: %1$d</string>
@@ -101,7 +101,7 @@
<string name="safetynet_attest_loading">Momentík ...</string> <string name="safetynet_attest_loading">Momentík ...</string>
<string name="safetynet_attest_restart">Skúste to znova</string> <string name="safetynet_attest_restart">Skúste to znova</string>
<!-- MagiskHide --> <!--MagiskHide-->
<string name="show_system_app">Zobraziť systémové aplikácie</string> <string name="show_system_app">Zobraziť systémové aplikácie</string>
<string name="show_os_app">Zobraziť aplikácie OS</string> <string name="show_os_app">Zobraziť aplikácie OS</string>
<string name="hide_filter_hint">Filtrovať podľa názvu</string> <string name="hide_filter_hint">Filtrovať podľa názvu</string>
@@ -109,7 +109,7 @@
<string name="hide_filters">Filtre</string> <string name="hide_filters">Filtre</string>
<string name="hide_search">Vyhľadávanie</string> <string name="hide_search">Vyhľadávanie</string>
<!--Module Fragment--> <!--Module-->
<string name="no_info_provided">(Nie sú k dispozícii žiadne informácie)</string> <string name="no_info_provided">(Nie sú k dispozícii žiadne informácie)</string>
<string name="reboot_userspace">Softvérový reštart</string> <string name="reboot_userspace">Softvérový reštart</string>
<string name="reboot_recovery">Reštartovať do Recovery</string> <string name="reboot_recovery">Reštartovať do Recovery</string>
@@ -129,7 +129,7 @@
<!--Settings --> <!--Settings-->
<string name="settings_dark_mode_title">Režim motívu</string> <string name="settings_dark_mode_title">Režim motívu</string>
<string name="settings_dark_mode_message">Vyberte režim, ktorý najlepšie vyhovuje vášmu štýlu!</string> <string name="settings_dark_mode_message">Vyberte režim, ktorý najlepšie vyhovuje vášmu štýlu!</string>
<string name="settings_dark_mode_light">Vždy svetlý</string> <string name="settings_dark_mode_light">Vždy svetlý</string>
@@ -222,7 +222,7 @@
<string name="repo_cache_cleared">Cache repo odstránená</string> <string name="repo_cache_cleared">Cache repo odstránená</string>
<string name="flashing">Flashovanie...</string> <string name="flashing">Flashovanie...</string>
<string name="done">Hotovo!</string> <string name="done">Hotovo!</string>
<string name="failure">Zlyhalo</string> <string name="failure">Zlyhalo!</string>
<string name="hide_manager_title">Skrývanie Magisk Managera…</string> <string name="hide_manager_title">Skrývanie Magisk Managera…</string>
<string name="hide_manager_fail_toast">Skrytie Magisk Managera zlyhalo</string> <string name="hide_manager_fail_toast">Skrytie Magisk Managera zlyhalo</string>
<string name="restore_manager_fail_toast">Obnovenie Magisk Managera zlyhalo</string> <string name="restore_manager_fail_toast">Obnovenie Magisk Managera zlyhalo</string>

View File

@@ -0,0 +1,231 @@
<resources>
<!--Sections-->
<string name="modules">Modulet</string>
<string name="superuser">Superpërdoruesi</string>
<string name="logs">Regjistrat</string>
<string name="settings">Cilësimet</string>
<string name="refresh">Rifresko të Dhënat Lokale</string>
<string name="install">Instalo</string>
<string name="section_home">Shtëpia</string>
<string name="section_theme">Temat</string>
<string name="safetynet">Rrjeti i Sigurisë</string>
<!--Home-->
<string name="no_connection">Nuk ka lidhje interneti</string>
<string name="app_changelog">Ndryshimet</string>
<string name="manager">Menaxheri</string>
<string name="loading">Po ngarkon…</string>
<string name="update">Përditëso</string>
<string name="not_available">N/A</string>
<string name="hide">Fshih</string>
<string name="status">Statusi</string>
<string name="home_package">Paketa</string>
<string name="home_notice_content">Gjithmonë sigurohuni që jeni duke përdorur Magisk Manager me burim të hapur. Magisk Manager i një burimi të panjohur mund të kryejë veprime të dëmshme!</string>
<string name="home_support_title">Na ndihmoni</string>
<string name="home_item_source">Burimi</string>
<string name="home_support_content">Magisk është, dhe gjithmonë do të jetë, falas dhe me burim të hapur. Megjithatë mund të na tregoni se ju interesoni duke dërguar një donacion të vogël.</string>
<string name="home_status_normal">Normale</string>
<string name="home_status_stub">Stub</string>
<string name="home_installed_version">E instaluar</string>
<string name="home_latest_version">Më e fundit</string>
<string name="invalid_update_channel">Kanal i pavlefshëm i azhurnimit</string>
<string name="uninstall_magisk_title">Çinstalo Magisk</string>
<string name="uninstall_magisk_msg">Të gjitha modulet do të çaktivizohen/hiqen! \n Rrënja do të hiqet! \n\n Të dhënat tuaja potencialisht të koduara nëse jo tashmë!</string>
<string name="home_check_safetynet">Kontrolloni Rrjetin e Sigurisë</string>
<!--Install-->
<string name="keep_force_encryption">Ruaj kriptimin me forcë</string>
<string name="keep_dm_verity">Ruaj AVB 2.0 /dm-vërtetësi</string>
<string name="recovery_mode">Modaliteti i rikuperimit</string>
<string name="install_options_title">Opsionet</string>
<string name="install_method_title">Metoda</string>
<string name="install_next">Tjetra</string>
<string name="install_start">Le të shkojmë</string>
<string name="manager_download_install">Shtypni për të shkarkuar dhe instaluar</string>
<string name="download_zip_only">Shkarkoni vetëm Zip</string>
<string name="direct_install">Instalimi i drejtpërdrejtë (rekomandohet)</string>
<string name="install_inactive_slot">Instalo në Slot Inaktive (Pas OTA)</string>
<string name="install_inactive_slot_msg">Pajisja juaj do të detyrohet të nisë në vendndodhjen aktuale joaktive pas një rindezjeje! \n Të përdorni vetëm këtë mundësi pasi të keni mbaruar OTA. \n Vazhdoni? </string>
<string name="setup_title">Konfigurimi shtesë</string>
<string name="select_patch_file">Zgjidhni dhe Patch një Skedar</string>
<string name="patch_file_msg">Zgjidhni një imazh të papërpunuar (* .img) ose një tarifë ODIN (* .tar)</string>
<string name="reboot_delay_toast">Rinisje pas 5 sekonda…</string>
<string name="flash_screen_title">Instalimi</string>
<!--Superuser-->
<string name="touch_filtered_warning">Meqenëse një aplikacion po errëson një kërkesë të superpërdoruesit, Magisk nuk mund të verifikojë përgjigjen tuaj</string>
<string name="deny">Moho</string>
<string name="prompt">Pyet</string>
<string name="grant">Lejo</string>
<string name="su_warning">Jep akses të plotë në pajisjen tuaj. \n Moho nëse nuk je i sigurt!</string>
<string name="forever">Përgjithmonë</string>
<string name="once">Një herë</string>
<string name="tenmin">10 minuta</string>
<string name="twentymin">20 minuta</string>
<string name="thirtymin">30 minuta</string>
<string name="sixtymin">60 minuta</string>
<string name="su_allow_toast">%1$s iu dha e drejta e superpërdoruesit</string>
<string name="su_deny_toast">%1$s iu refuzuan të drejtat e Superpërdoruesit</string>
<string name="su_snack_grant">Jep të drejtën e superpërdoruesit prej %1$s</string>
<string name="su_snack_deny">Të drejtat e superpërdoruesit prej %1$s mohohen</string>
<string name="su_snack_notif_on">Njoftimet e %1$s janë aktivizuar</string>
<string name="su_snack_notif_off">Njoftimet e %1$s janë çaktivizuar</string>
<string name="su_snack_log_on">Regjistrimi i %1$s është aktivizuar</string>
<string name="su_snack_log_off">Regjistrimi i %1$s është çaktivizuar</string>
<string name="su_revoke_title">Anulohet?</string>
<string name="su_revoke_msg">Konfirmo të heqësh të drejtat e %1$s?</string>
<string name="toast">dolli</string>
<string name="superuser_toggle_notification">Njoftimet</string>
<string name="superuser_toggle_revoke">Anulo</string>
<string name="superuser_policy_none">Asnjë aplikacion nuk ka kërkuar ende leje për superpërdoruesin.</string>
<!--Logs-->
<string name="log_data_none">Ju jeni pa regjistrime, provoni të përdorni më shumë aplikacionet tuaja të aktivizuara SU</string>
<string name="log_data_magisk_none">Regjistrat e Magisk janë bosh, kjo është e çuditshme</string>
<string name="menuSaveLog">Ruaj regjistrin</string>
<string name="menuClearLog">Pastro regjistrin tani</string>
<string name="logs_cleared">Regjistri u pastrua me sukses</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">UID i synuar: %1$d</string>
<!--SafetyNet-->
<string name="safetynet_api_error">Gabim API i SafetyNet</string>
<string name="safetynet_res_invalid">Përgjigjja është e pavlefshme </string>
<string name="safetynet_attest_success">Suksese!</string>
<string name="safetynet_attest_failure">Vërtetimi dështoi!</string>
<string name="safetynet_attest_loading">Prit një sekondë…</string>
<string name="safetynet_attest_restart">Provo përsëri</string>
<!--MagiskHide-->
<string name="show_system_app">Shfaq aplikacionet e sistemit</string>
<string name="show_os_app">Shfaq aplikacionet e sistemit operativ</string>
<string name="hide_filter_hint">Filtro me emër</string>
<string name="hide_scroll_up">Lëviz lart</string>
<string name="hide_filters">Filtrat</string>
<string name="hide_search">Kërko</string>
<!--Module-->
<string name="no_info_provided">(Nuk ofrohet informacion)</string>
<string name="reboot_userspace">Ristartim normal</string>
<string name="reboot_recovery">Ristartoni në recovery</string>
<string name="reboot_bootloader">Ristartoni në bootloader</string>
<string name="reboot_download">Ristartoni në download</string>
<string name="reboot_edl">Ristartoni në EDL</string>
<string name="module_version_author">%1$s nga %2$s</string>
<string name="module_state_remove">Hiq</string>
<string name="module_state_restore">Rivendos</string>
<string name="module_action_install_external">Instaloni nga hapësira ruajtëse</string>
<string name="update_available">Përditësimi i disponueshëm</string>
<string name="module_installed">@string/home_installed_version</string>
<string name="module_section_online">Në internet</string>
<string name="sorting_order">Renditja e Renditjes</string>
<!--Settings-->
<string name="settings_dark_mode_title">Modaliteti i temës</string>
<string name="settings_dark_mode_message">Zgjidhni mënyrën e cila i përshtatet më mirë stilit tuaj!</string>
<string name="settings_dark_mode_light">Gjithmonë e lehtë</string>
<string name="settings_dark_mode_system">Ndiqni sistemin</string>
<string name="settings_dark_mode_dark">Gjithmonë e errët</string>
<string name="settings_download_path_title">Shtegu i shkarkimit</string>
<string name="settings_download_path_message">Skedarët do të ruhen në %1$s</string>
<string name="settings_clear_cache_title">Pastro Cache të Repos</string>
<string name="settings_clear_cache_summary">Pastroni informacionin e memorizuar për repot në internet. Kjo e detyron aplikacionin të rifreskohet në internet</string>
<string name="settings_hide_manager_title">Fshih menaxherin e Magisk</string>
<string name="settings_hide_manager_summary">Ripaketimi Magisk Manager me paketa të rastësishme dhe emra të aplikacioneve</string>
<string name="settings_restore_manager_title">Rivendos menaxherin e Magisk</string>
<string name="settings_restore_manager_summary">Rivendos Magisk Manager me paketën origjinale dhe emrat e aplikacioneve</string>
<string name="language">Gjuha</string>
<string name="system_default">(Parazgjedhja e Sistemit)</string>
<string name="settings_check_update_title">Kontrolloni azhurnimet</string>
<string name="settings_check_update_summary">Kontrolloni periodikisht për azhurnime në sfond</string>
<string name="settings_update_channel_title">Azhurnoni Kanalin</string>
<string name="settings_update_stable">Qëndrueshëm</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Kanali i personalizuar</string>
<string name="settings_update_custom_msg">Vendos një URL të personalizuar</string>
<string name="settings_magiskhide_summary">Fshih Magisk nga forma të ndryshme të zbulimit</string>
<string name="settings_hosts_title">Pritës pa sistem</string>
<string name="settings_hosts_summary">Mbështetja e hostëve pa sistem për aplikacionet Adblock</string>
<string name="settings_hosts_toast">Moduli i pritur i sistemit pa sistem</string>
<string name="settings_app_name_hint">Emër i ri</string>
<string name="settings_app_name_helper">Aplikacioni do të ripaketohet në këtë emër</string>
<string name="settings_app_name_error">Formati i pavlefshëm</string>
<string name="settings_su_app_adb">Aplikacionet dhe ADB</string>
<string name="settings_su_app">Vetëm aplikacionet</string>
<string name="settings_su_adb">Vetëm ADB</string>
<string name="settings_su_disable">Çaktivizuar</string>
<string name="superuser_access">Hyrja në superpërdorues</string>
<string name="auto_response">Përgjigje Automatike</string>
<string name="request_timeout">Koha e kërkesës</string>
<string name="superuser_notification">Njoftimi i superpërdoruesit</string>
<string name="settings_su_reauth_title">Ridentifikoni pas azhurnimit</string>
<string name="settings_su_reauth_summary">Ridentifikoni lejet e superpërdoruesit pas azhurnimeve të një aplikacioni</string>
<string name="settings_su_tapjack_title">Aktivizo Mbrojtjen nga Tapjacking</string>
<string name="settings_su_tapjack_summary">Dialogu i menjëhershëm i superpërdoruesit nuk do ti përgjigjet hyrjes ndërsa errësohet nga ndonjë dritare tjetër ose mbivendosja</string>
<string name="settings_su_biometric_title">Aktivizo vërtetimin biometrik</string>
<string name="settings_su_biometric_summary">Përdorni vërtetimin biometrik për të lejuar kërkesat e superpërdoruesit</string>
<string name="no_biometric">Pajisja e pambështetur ose nuk janë aktivizuar cilësime biometrike</string>
<string name="settings_customization">Përshtatje</string>
<string name="setting_add_shortcut_summary">"Shtoni një shkurtore të bukur në ekranin kryesor në rast se emri dhe ikona janë të vështira për t'u njohur pasi të keni fshehur aplikacionin"</string>
<string name="settings_doh_title">DNS mbi HTTPS</string>
<string name="settings_doh_description">Helmimi i paqartë nga DNS në disa kombe</string>
<string name="multiuser_mode">Modaliteti i shumë përdoruesit</string>
<string name="settings_owner_only">Vetëm zotëruesi i pajisjes</string>
<string name="settings_owner_manage">Pronari i Pajisjes i Menaxhuar</string>
<string name="settings_user_independent">Përdorues i Pavarur</string>
<string name="user_indepenent_summary">Çdo përdorues ka rregullat e tij/saj të veçanta rrënjësore</string>
<string name="mount_namespace_mode">Modaliteti i hapësirës së emrave të malit</string>
<string name="settings_ns_global">Hapësira Globale e Emrave</string>
<string name="settings_ns_requester">Trashëgoni Hapësirën e Emrave</string>
<string name="settings_ns_isolate">Hapësira e izoluar e emrave</string>
<string name="global_summary">Të gjitha sesionet rrënjësore përdorin hapësirën globale të emrave të montimit</string>
<string name="requester_summary">Seancat rrënjësore do të trashëgojnë hapësirën e emrave të kërkuesit të tyre</string>
<string name="isolate_summary">Çdo sesion rrënjë do të ketë hapësirën e vet të izoluar të tij</string>
<!--Notifications-->
<string name="update_channel">Përditësimet e Magisk</string>
<string name="progress_channel">Njoftimet e Progresit</string>
<string name="download_complete">Shkarkimi përfundoi</string>
<string name="download_file_error">Gabim në shkarkimin e skedarit</string>
<string name="download_open_parent">Shfaq në dosjen mëmë</string>
<string name="magisk_update_title">Mundësohet azhurnimi i Magisk!</string>
<string name="manager_update_title">Ka perditësime të ri të Magisk Manager!</string>
<!--Toasts, Dialogs-->
<string name="yes">Po</string>
<string name="no">Jo</string>
<string name="repo_install_title">Instalo %1$s</string>
<string name="repo_install_msg">Dëshiron të instalosh %1$s tani?</string>
<string name="download">Shkarkim</string>
<string name="reboot">Rinis</string>
<string name="release_notes">Lëshoni shënime</string>
<string name="repo_cache_cleared">Depoja e repos u pastrua</string>
<string name="flashing">Ndezje…</string>
<string name="done">U krye!</string>
<string name="failure">Dështoi!</string>
<string name="hide_manager_title">Fshehja e Magisk manager…</string>
<string name="hide_manager_fail_toast">Fsheh Menaxherin e Magisk dështoi</string>
<string name="restore_manager_fail_toast">Rikthe menaxherin e Magisk dështoi</string>
<string name="open_link_failed_toast">Asnjë aplikacion nuk u gjet për të hapur lidhjen</string>
<string name="complete_uninstall">Çinstalimi i plotë</string>
<string name="restore_img">Rikthe Imazhet</string>
<string name="restore_img_msg">Rivendosja…</string>
<string name="restore_done">Restaurimi u krye!</string>
<string name="restore_fail">Rezervimi i aksioneve nuk ekziston!</string>
<string name="proprietary_title">Shkarkoni Kodin e Pronarit</string>
<string name="proprietary_notice">Magisk Manager është FOSS dhe nuk përmban kodin e pronarit të Google SecurityNet API. \n\n A do të lejoni që Magisk Manager të shkarkojë një shtesë (përmban GoogleApiClient) për kontrollet e SafetyNet?</string>
<string name="setup_fail">Konfigurimi dështoi</string>
<string name="env_fix_title">Kërkon Konfigurim Shtesë</string>
<string name="env_fix_msg">Pajisja juaj ka nevojë për konfigurim shtesë që Magisk të funksionojë siç duhet. Do të shkarkojë zip-in e konfigurimit të Magisk, doni të vazhdoni tani?</string>
<string name="setup_msg">Konfigurimi i mjedisit drejtues…</string>
<string name="authenticate">Vërteto</string>
<string name="unsupport_magisk_title">Versioni i pambështetur i Magisk</string>
<string name="unsupport_magisk_msg">Ky version i Magisk Manager nuk e mbështet versionin Magisk më të ulët se %1$s. \n\n Aplikimi do të sillet sikur nuk është instaluar asnjë Magisk, ju lutemi azhurnoni Magisk sa më shpejt të jetë e mundur.</string>
<string name="external_rw_permission_denied">Jep leje për ruajtje për të mundësuar këtë funksionalitet</string>
<string name="add_shortcut_title">Shto shkurtore në ekranin kryesor</string>
<string name="add_shortcut_msg">Pasi të keni fshehur Magisk Manager, emri dhe ikona e tij mund të bëhen të vështira për t\'u njohur. \n\n Dëshironi të shtoni një shkurtore të bukur në ekranin kryesor?</string>
<string name="app_not_found">Asnjë aplikacion nuk u gjet për të trajtuar këtë veprim</string>
</resources>

View File

@@ -1,11 +1,11 @@
<resources> <resources>
<!--Welcome Activity--> <!--Sections-->
<string name="modules">Modüller</string> <string name="modules">Modüller</string>
<string name="superuser">Yetkili Kullanıcı</string> <string name="superuser">Yetkili Kullanıcı</string>
<string name="logs">Günlük</string> <string name="logs">Günlük</string>
<string name="settings">Ayarlar</string> <string name="settings">Ayarlar</string>
<string name="refresh">Yerel Verileri Yenile</string> <string name="refresh">Yerel verileri yenile</string>
<string name="install">Yükle</string> <string name="install">Yükle</string>
<string name="section_home">Ana Ekran</string> <string name="section_home">Ana Ekran</string>
<string name="section_theme">Temalar</string> <string name="section_theme">Temalar</string>
@@ -14,7 +14,7 @@
<!--Home--> <!--Home-->
<string name="no_connection">Bağlantı yok</string> <string name="no_connection">Bağlantı yok</string>
<string name="app_changelog">Değişiklikler</string> <string name="app_changelog">Değişiklikler</string>
<string name="manager">Yönetici</string> <string name="manager">Manager</string>
<string name="loading">Yükleniyor…</string> <string name="loading">Yükleniyor…</string>
<string name="update">Güncelle</string> <string name="update">Güncelle</string>
<string name="not_available">N/A</string> <string name="not_available">N/A</string>
@@ -22,13 +22,13 @@
<string name="status">Durum</string> <string name="status">Durum</string>
<string name="home_package">Paket</string> <string name="home_package">Paket</string>
<string name="home_notice_content">Her zaman açık kaynaklı Magisk Manager kullandığınızdan emin olun. Kaynağı bilinmeyen yönetici uygulamaları kötü amaçlı eylemler gerçekleştirebilir.</string> <string name="home_notice_content">Her zaman açık kaynaklı Magisk Manager kullandığınızdan emin olun. Kaynağı bilinmeyen Manager(yönetici) uygulamaları kötü amaçlı eylemler gerçekleştirebilirler!</string>
<string name="home_support_title">Bizi Destekleyin</string> <string name="home_support_title">Bizi Destekleyin</string>
<string name="home_item_source">Kaynak</string> <string name="home_item_source">Kaynak</string>
<string name="home_support_content">Magisk özgür ve açık kaynaklıdır ve her zaman da öyle kalacak. Ancak küçük bir bağış göndererek bize önem verdiğinizi gösterebilirsiniz.</string> <string name="home_support_content">Magisk özgür ve açık kaynaklıdır ve her zaman da öyle kalacaktır. Ancak küçük bir bağış göndererek bize önem verdiğinizi gösterebilirsiniz.</string>
<string name="home_status_normal">Normal</string> <string name="home_status_normal">Normal</string>
<string name="home_status_stub">Stub</string> <string name="home_status_stub">Stub</string>
<string name="home_installed_version">Yüklendi</string> <string name="home_installed_version">Yüklü</string>
<string name="home_latest_version">Güncel</string> <string name="home_latest_version">Güncel</string>
<string name="invalid_update_channel">Geçersiz Güncelleme Kanalı</string> <string name="invalid_update_channel">Geçersiz Güncelleme Kanalı</string>
<string name="uninstall_magisk_title">Magisk\'i kaldır</string> <string name="uninstall_magisk_title">Magisk\'i kaldır</string>
@@ -36,7 +36,7 @@
<string name="home_check_safetynet">SafetyNet\'i kontrol et</string> <string name="home_check_safetynet">SafetyNet\'i kontrol et</string>
<!--Install--> <!--Install-->
<string name="keep_force_encryption">Şifrelemeyi zorlamayı sürdür</string> <string name="keep_force_encryption">Şifrelemeye zorlamayı sürdür</string>
<string name="keep_dm_verity">AVB 2.0/dm-verity\'i koru</string> <string name="keep_dm_verity">AVB 2.0/dm-verity\'i koru</string>
<string name="recovery_mode">Kurtarma Modu</string> <string name="recovery_mode">Kurtarma Modu</string>
<string name="install_options_title">Seçenekler</string> <string name="install_options_title">Seçenekler</string>
@@ -47,7 +47,7 @@
<string name="download_zip_only">Sadece Zip\'i indir</string> <string name="download_zip_only">Sadece Zip\'i indir</string>
<string name="direct_install">Doğrudan kurulum (Önerilen)</string> <string name="direct_install">Doğrudan kurulum (Önerilen)</string>
<string name="install_inactive_slot">Aktif olmayan yuvaya yükle (OTA\'dan sonra)</string> <string name="install_inactive_slot">Aktif olmayan yuvaya yükle (OTA\'dan sonra)</string>
<string name="install_inactive_slot_msg">Cihazınız, yeniden başlatmanın ardından geçerli etkin olmayan yuvaya önyüklemeye ZORLANACAK!\nBu seçeneği yalnızca OTA bittikten sonra kullanın.\nDevam edilsin mi?</string> <string name="install_inactive_slot_msg">Cihazınız, yeniden başlatmanın ardından geçerli etkin olmayan yuvaya ön yüklemeye ZORLANACAK!\nBu seçeneği yalnızca OTA bittikten sonra kullanın.\nDevam edilsin mi?</string>
<string name="setup_title">Ek kurulum</string> <string name="setup_title">Ek kurulum</string>
<string name="select_patch_file">Dosya seçin ve yamalayın</string> <string name="select_patch_file">Dosya seçin ve yamalayın</string>
<string name="patch_file_msg">Bir raw imaj (*.img) veya ODIN tar dosyası (*.tar) seçin</string> <string name="patch_file_msg">Bir raw imaj (*.img) veya ODIN tar dosyası (*.tar) seçin</string>
@@ -56,12 +56,13 @@
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">Yetkili Kullanıcı İsteği</string> <string name="su_request_title">Yetkili Kullanıcı İsteği</string>
<string name="touch_filtered_warning">Çünkü bir uygulama yetkili kullanıcı isteğini engelliyor, Magisk senin yanıtını doğrulayamaz</string>
<string name="deny">Reddet</string> <string name="deny">Reddet</string>
<string name="prompt">Sor</string> <string name="prompt">Sor</string>
<string name="grant">İzin ver</string> <string name="grant">İzin ver</string>
<string name="su_warning">Cihazınıza tam erişim izni verir.\nEmin değilseniz reddedin!</string> <string name="su_warning">Cihazınıza tam erişim izni verir.\nEmin değilseniz reddedin!</string>
<string name="forever">Daima</string> <string name="forever">Daima</string>
<string name="once">Bir kere</string> <string name="once">Bir kereliğine</string>
<string name="tenmin">10 dakika</string> <string name="tenmin">10 dakika</string>
<string name="twentymin">20 dakika</string> <string name="twentymin">20 dakika</string>
<string name="thirtymin">30 dakika</string> <string name="thirtymin">30 dakika</string>
@@ -81,14 +82,14 @@
<string name="superuser_toggle_notification">Bildirimler</string> <string name="superuser_toggle_notification">Bildirimler</string>
<string name="superuser_toggle_revoke">İptal et</string> <string name="superuser_toggle_revoke">İptal et</string>
<string name="superuser_policy_none">Henüz hiçbir uygulama süper kullanıcı izni istemedi.</string> <string name="superuser_policy_none">Henüz hiçbir uygulama yetkili kullanıcı izni istemedi.</string>
<!--Logs--> <!--Logs-->
<string name="log_data_none">Günlük boş, daha fazla uygulama için SU etkinleştirmeyi deneyin.</string> <string name="log_data_none">Günlüksüzsün, daha fazla Yetkili Kullanıcı İzni isteyen uygulama kullanmayı dene</string>
<string name="log_data_magisk_none">Magisk günlükleri boş, bu garip.</string> <string name="log_data_magisk_none">Magisk günlükleri boş, bu garip</string>
<string name="menuSaveLog">Günlüğü kaydet</string> <string name="menuSaveLog">Günlüğü kaydet</string>
<string name="menuClearLog">Günlüğü temizle</string> <string name="menuClearLog">Günlüğü temizle</string>
<string name="logs_cleared">Günlük başarıyla temizlendi.</string> <string name="logs_cleared">Günlük başarıyla temizlendi</string>
<string name="pid">PID: %1$d</string> <string name="pid">PID: %1$d</string>
<string name="target_uid">Hedef UID: %1$d</string> <string name="target_uid">Hedef UID: %1$d</string>
@@ -96,41 +97,43 @@
<string name="safetynet_api_error">SafetyNet API Hatası</string> <string name="safetynet_api_error">SafetyNet API Hatası</string>
<string name="safetynet_res_invalid">Yanıt geçersiz</string> <string name="safetynet_res_invalid">Yanıt geçersiz</string>
<string name="safetynet_attest_success">Başarılı!</string> <string name="safetynet_attest_success">Başarılı!</string>
<string name="safetynet_attest_failure">Onaylama başarısız oldu!</string> <string name="safetynet_attest_failure">Onaylama başarısız!</string>
<string name="safetynet_attest_loading">Sadece bir saniye…</string> <string name="safetynet_attest_loading">Sadece bir saniye…</string>
<string name="safetynet_attest_restart">Tekrar deneyiniz</string> <string name="safetynet_attest_restart">Tekrar dene</string>
<!-- MagiskHide --> <!--MagiskHide-->
<string name="show_system_app">Sistem uygulamalarını göster</string> <string name="show_system_app">Sistem uyg. göster</string>
<string name="show_os_app">İşletim Sistemi uyg. göster</string>
<string name="hide_filter_hint">İsme göre filtrele</string> <string name="hide_filter_hint">İsme göre filtrele</string>
<string name="hide_scroll_up">Yukarı kaydır</string> <string name="hide_scroll_up">Yukarı kaydır</string>
<string name="hide_filters">Filtreler</string> <string name="hide_filters">Filtreler</string>
<string name="hide_search">Ara</string> <string name="hide_search">Ara</string>
<!--Module Fragment--> <!--Module-->
<string name="no_info_provided">(Hiçbir ıklama sağlanmadı)</string> <string name="no_info_provided">(Hiçbir bilgi sağlanmadı)</string>
<string name="reboot_userspace">Hızlı yeniden başlat</string>
<string name="reboot_recovery">Kurtarma moduna yeniden başlat</string> <string name="reboot_recovery">Kurtarma moduna yeniden başlat</string>
<string name="reboot_bootloader">Ön yükleyici moduna yeniden başlat</string> <string name="reboot_bootloader">Ön yükleyici moduna yeniden başlat</string>
<string name="reboot_download">Yükleme moduna yeniden başlat</string> <string name="reboot_download">İndirme moduna yeniden başlat</string>
<string name="reboot_edl">EDL moduna yeniden başlat</string> <string name="reboot_edl">EDL moduna yeniden başlat</string>
<string name="module_version_author">%1$s - %2$s</string> <string name="module_version_author">%1$s - %2$s</string>
<string name="module_section_pending">Güncellemeler</string> <string name="module_section_pending">Güncellemeler</string>
<string name="module_section_pending_action">Tümünü güncelle</string> <string name="module_section_pending_action">Tümünü güncelle</string>
<string name="module_state_remove">Kaldır</string> <string name="module_state_remove">Kaldır</string>
<string name="module_state_restore">Geri yükle</string> <string name="module_state_restore">Geri yükle</string>
<string name="module_action_install_external">Depolama alanından yükle</string> <string name="module_action_install_external">Dahili depolamadan yükle</string>
<string name="update_available">Güncelleme mevcut</string> <string name="update_available">Güncelleme mevcut</string>
<string name="module_installed">@string/home_installed_version</string> <string name="module_installed">@string/home_installed_version</string>
<string name="module_section_online">Çevrim içi</string> <string name="module_section_online">Çevrim İçi</string>
<string name="sorting_order">Sıralama Düzeni</string> <string name="sorting_order">Sıralama Düzeni</string>
<!--Settings --> <!--Settings -->
<string name="settings_dark_mode_title">Tema Modu</string> <string name="settings_dark_mode_title">Tema Modu</string>
<string name="settings_dark_mode_message">Stilinize en uygun modu seçin!</string> <string name="settings_dark_mode_message">Stilinize en iyi uyan modu seçin!</string>
<string name="settings_dark_mode_light">Her zaman aydınlık</string> <string name="settings_dark_mode_light">Her Zaman Aydınlık</string>
<string name="settings_dark_mode_system">Sistemi takip et</string> <string name="settings_dark_mode_system">Sistemi Takip Et</string>
<string name="settings_dark_mode_dark">Her zaman karanlık</string> <string name="settings_dark_mode_dark">Her Zmana Karanlık</string>
<string name="settings_download_path_title">İndirme Yolu</string> <string name="settings_download_path_title">İndirme dizini</string>
<string name="settings_download_path_message">Dosyalar %1$s konumuna kaydedilecek</string> <string name="settings_download_path_message">Dosyalar %1$s konumuna kaydedilecek</string>
<string name="settings_clear_cache_title">Depo Önbelleğini Temizle</string> <string name="settings_clear_cache_title">Depo Önbelleğini Temizle</string>
<string name="settings_clear_cache_summary">Çevrim içi depolar için önbellek bilgilerini temizle, uygulamayı çevrim içi yenilemeye zorla</string> <string name="settings_clear_cache_summary">Çevrim içi depolar için önbellek bilgilerini temizle, uygulamayı çevrim içi yenilemeye zorla</string>
@@ -143,9 +146,9 @@
<string name="settings_check_update_title">Güncellemeleri Denetle</string> <string name="settings_check_update_title">Güncellemeleri Denetle</string>
<string name="settings_check_update_summary">Düzenli aralıklarla arka planda güncellemeleri denetle</string> <string name="settings_check_update_summary">Düzenli aralıklarla arka planda güncellemeleri denetle</string>
<string name="settings_update_channel_title">Güncelleme Kanalı</string> <string name="settings_update_channel_title">Güncelleme Kanalı</string>
<string name="settings_update_stable">Stabil(kararlı)</string> <string name="settings_update_stable">Stabil</string>
<string name="settings_update_beta">Beta</string> <string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Özel</string> <string name="settings_update_custom">Özel Kanal</string>
<string name="settings_update_custom_msg">Özel bir URL ekleyin</string> <string name="settings_update_custom_msg">Özel bir URL ekleyin</string>
<string name="settings_magiskhide_summary">Magisk\'i çeşitli algılamalardan gizle</string> <string name="settings_magiskhide_summary">Magisk\'i çeşitli algılamalardan gizle</string>
<string name="settings_hosts_title">Sistemsiz host</string> <string name="settings_hosts_title">Sistemsiz host</string>
@@ -157,7 +160,7 @@
<string name="settings_su_app_adb">Uygulamalar ve ADB</string> <string name="settings_su_app_adb">Uygulamalar ve ADB</string>
<string name="settings_su_app">Sadece uygulamalar</string> <string name="settings_su_app">Sadece uygulamalar</string>
<string name="settings_su_adb">Sadece ADB</string> <string name="settings_su_adb">Sadece ADB</string>
<string name="settings_su_disable">Devre dışı</string> <string name="settings_su_disable">Devre Dışı</string>
<string name="settings_su_request_10">10 saniye</string> <string name="settings_su_request_10">10 saniye</string>
<string name="settings_su_request_15">15 saniye</string> <string name="settings_su_request_15">15 saniye</string>
<string name="settings_su_request_20">20 saniye</string> <string name="settings_su_request_20">20 saniye</string>
@@ -170,13 +173,15 @@
<string name="superuser_notification">Yetkili Kullanıcı Bildirimi</string> <string name="superuser_notification">Yetkili Kullanıcı Bildirimi</string>
<string name="settings_su_reauth_title">Yükseltmeden sonra yeniden kimlik doğrula</string> <string name="settings_su_reauth_title">Yükseltmeden sonra yeniden kimlik doğrula</string>
<string name="settings_su_reauth_summary">Uygulama yükseltmeleri sonrasında yetkili kullanıcı izinlerini yeniden doğrula</string> <string name="settings_su_reauth_summary">Uygulama yükseltmeleri sonrasında yetkili kullanıcı izinlerini yeniden doğrula</string>
<string name="settings_su_tapjack_title">Tapjacking Korumasını Aktifleştir</string>
<string name="settings_su_tapjack_summary">Yetkili Kullanıcı izin penceresi başka bir pencere veya arayüz tarafından engellenirken verilen yanıtlara tepki vermeyecektir</string>
<string name="settings_su_biometric_title">Biyometrik Kimlik Doğrulamayı Etkinleştir</string> <string name="settings_su_biometric_title">Biyometrik Kimlik Doğrulamayı Etkinleştir</string>
<string name="settings_su_biometric_summary">Superuser isteklerine izin vermek için biyometrik kimlik doğrulamayı kullanın</string> <string name="settings_su_biometric_summary">Superuser isteklerine izin vermek için biyometrik kimlik doğrulamayı kullanın</string>
<string name="no_biometric">Desteklenmeyen cihaz veya biyometrik ayar etkinleştirilmemiş</string> <string name="no_biometric">Desteklenmeyen cihaz veya biyometrik ayar etkinleştirilmemiş</string>
<string name="settings_customization">Özelleştirme</string> <string name="settings_customization">Özelleştirme</string>
<string name="setting_add_shortcut_summary">Uygulamayı gizledikten sonra ismini ve simgesini tanımakta zorlanırsan ana ekrana güzel bir kısayol ekleyebilirsin</string> <string name="setting_add_shortcut_summary">Uygulamayı gizledikten sonra ismini ve simgesini tanımakta zorlanırsan ana ekrana güzel bir kısayol ekleyebilirsin</string>
<string name="settings_doh_title">HTTPS üzerinden DNS</string> <string name="settings_doh_title">HTTPS üzerinden DNS</string>
<string name="settings_doh_description">Bazı ülkelerdeki DNS zehirlenmesini çözmeye çalışır</string> <string name="settings_doh_description">Bazı ülkelerdeki DNS zehirlenmesini çözmeye çalış</string>
<string name="multiuser_mode">Çoklu Kullanıcı Modu</string> <string name="multiuser_mode">Çoklu Kullanıcı Modu</string>
<string name="settings_owner_only">Yalnızca Cihaz Sahibi</string> <string name="settings_owner_only">Yalnızca Cihaz Sahibi</string>
@@ -186,8 +191,8 @@
<string name="owner_manage_summary">Yalnızca cihaz sahibi kök erişimini yönetebilir ve izin isteklerini alabilir</string> <string name="owner_manage_summary">Yalnızca cihaz sahibi kök erişimini yönetebilir ve izin isteklerini alabilir</string>
<string name="user_indepenent_summary">Her kullanıcının kendi ayrı kök erişimi kuralları vardır</string> <string name="user_indepenent_summary">Her kullanıcının kendi ayrı kök erişimi kuralları vardır</string>
<string name="mount_namespace_mode">Ad Alanı Modunu Doldur</string> <string name="mount_namespace_mode">Ad Alanı Modunu Bağla</string>
<string name="settings_ns_global">Evrensel Ad Alanı</string> <string name="settings_ns_global">Global Ad Alanı</string>
<string name="settings_ns_requester">Devralınan Ad Alanı</string> <string name="settings_ns_requester">Devralınan Ad Alanı</string>
<string name="settings_ns_isolate">Ayrılmış Ad Alanı</string> <string name="settings_ns_isolate">Ayrılmış Ad Alanı</string>
<string name="global_summary">Tüm kök oturumları genel bağlama ad alanını kullanır</string> <string name="global_summary">Tüm kök oturumları genel bağlama ad alanını kullanır</string>
@@ -201,8 +206,8 @@
<string name="download_file_error">Dosya indirme hatası</string> <string name="download_file_error">Dosya indirme hatası</string>
<string name="download_open_parent">Üst klasörde göster</string> <string name="download_open_parent">Üst klasörde göster</string>
<string name="download_open_self">Dosyayı göster</string> <string name="download_open_self">Dosyayı göster</string>
<string name="magisk_update_title">Yeni Magisk Güncellemesi Mevcut!</string> <string name="magisk_update_title">Magisk Güncellemesi Mevcut!</string>
<string name="manager_update_title">Yeni Magisk Manager Güncellemesi Mevcut!</string> <string name="manager_update_title">Magisk Manager Güncellemesi Mevcut!</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="yes">Evet</string> <string name="yes">Evet</string>
@@ -217,25 +222,26 @@
<string name="done">Tamamlandı!</string> <string name="done">Tamamlandı!</string>
<string name="failure">Başarısız</string> <string name="failure">Başarısız</string>
<string name="hide_manager_title">Magisk Manager Gizleniyor…</string> <string name="hide_manager_title">Magisk Manager Gizleniyor…</string>
<string name="hide_manager_fail_toast">Magisk Manager\'ı Gizleme başarısız oldu.</string> <string name="hide_manager_fail_toast">Magisk Manager\'ı gizleme başarısız</string>
<string name="open_link_failed_toast">Bağlantıyı açabilecek uygulama bulunamadı.</string> <string name="restore_manager_fail_toast">Magisk Manager\'ı geri yükleme başarısız</string>
<string name="open_link_failed_toast">Bağlantıyı açabilecek bir uygulama bulunamadı</string>
<string name="complete_uninstall">Tamamen Kaldır</string> <string name="complete_uninstall">Tamamen Kaldır</string>
<string name="restore_img">Önyükleme İmajını Geri Yükle</string> <string name="restore_img">İmajları Geri Yükle</string>
<string name="restore_img_msg">Geri Yükleniyor…</string> <string name="restore_img_msg">Geri Yükleniyor…</string>
<string name="restore_done">Yenileme tamamlandı!</string> <string name="restore_done">Geri yükleme tamamlandı!</string>
<string name="restore_fail">Stok önyükleme yedeği yok!</string> <string name="restore_fail">Stock ön yükleme yedeği yok!</string>
<string name="proprietary_title">Sahipli Kodu İndirin</string> <string name="proprietary_title">Sahipli Kodu İndirin</string>
<string name="proprietary_notice">Magisk Yöneticisi, FOSS(açık kaynaklı) olduğundan gerekli olan Google\'ın sahipli(kapalı kaynaklı) SafetyNet API kodunu içermez.\n\nMagisk Manager\'ın SafetyNet kontrolü için (GoogleApiClient içeren) bir uzantıyı indirmesine izin veriyor musunuz?</string> <string name="proprietary_notice">Magisk Manager, FOSS(açık kaynaklı) olduğundan gerekli olan Google\'ın sahipli(kapalı kaynaklı) SafetyNet API kodunu içermez.\n\nMagisk Manager\'ın SafetyNet kontrolü için (GoogleApiClient içeren) bir uzantıyı indirmesine izin veriyor musunuz?</string>
<string name="setup_fail">Kurulum başarısız</string> <string name="setup_fail">Kurulum başarısız</string>
<string name="env_fix_title">Ek Kurulum Gerekli</string> <string name="env_fix_title">Ek Kurulum Gerekli</string>
<string name="env_fix_msg">Cihazınızın Magisk\'in düzgün çalışması için ek kuruluma ihtiyacı var. Bu Magisk kurulum zip dosyasını indirecektir, şimdi devam etmek istiyor musunuz?</string> <string name="env_fix_msg">Cihazınızın Magisk\'in düzgün çalışması için ek kuruluma ihtiyacı var. Bu Magisk kurulum zip dosyasını indirecektir, şimdi devam etmek istiyor musunuz?</string>
<string name="setup_msg">Ortam kurulumu çalışıyor…</string> <string name="setup_msg">Ortam kurulumu çalıştırılıyor…</string>
<string name="authenticate">Kimlik doğrulaması</string> <string name="authenticate">Kimlik Doğrulaması</string>
<string name="unsupport_magisk_title">Desteklenmeyen Magisk Sürümü</string> <string name="unsupport_magisk_title">Desteklenmeyen Magisk Sürümü</string>
<string name="unsupport_magisk_msg">Magisk Manager\'ın bu sürümü, %1$s daha düşük Magisk versiyonlarını desteklememektedir.\n\nUygulama hiçbir Magisk kurulu değil gibi davranacak, lütfen en kısa zamanda Magisk\'i yükseltin.</string> <string name="unsupport_magisk_msg">Magisk Manager\'ın bu sürümü, %1$s daha düşük Magisk versiyonlarını desteklememektedir.\n\nUygulama hiçbir Magisk kurulu değil gibi davranacak, lütfen en kısa zamanda Magisk\'i yükseltin.</string>
<string name="external_rw_permission_denied">Bu işlevi etkinleştirmek için depolama izni verin</string> <string name="external_rw_permission_denied">Bu işlevi etkinleştirmek için depolama izni verin</string>
<string name="add_shortcut_title">Ana ekrana kısayol ekle</string> <string name="add_shortcut_title">Ana ekrana kısayol ekle</string>
<string name="add_shortcut_msg">Magisk Manager\'ı gizledikten sonra, ismini ve simgesini tanıması güç olabilir. Ana ekrana güzel bir kısayol eklemek ister misin??</string> <string name="add_shortcut_msg">Magisk Manager\'ı gizledikten sonra, ismini ve simgesini tanıması zor olabilir. Ana ekrana güzel bir kısayol eklemek ister misin?</string>
<string name="app_not_found">Bu işlemi yapabilecek bir uygulama bulunamadı</string> <string name="app_not_found">Bu işlemi yapabilecek bir uygulama bulunamadı</string>
</resources> </resources>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="SplashTheme" parent="SplashThemeBase">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
</resources>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Base.V19.Theme.Splash.Light" parent="Base.V17.Theme.Splash.Light">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
<style name="Base.V19.Theme.Splash" parent="Base.V17.Theme.Splash">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
<style name="Theme.Splash.Light" parent="Base.V19.Theme.Splash.Light" />
<style name="Theme.Splash" parent="Base.V19.Theme.Splash" />
</resources>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Foundation.Compat">
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Base.V21.Theme.Foundation.Light" parent="Base.V17.Theme.Foundation.Light">
<item name="android:statusBarColor">#38000000</item>
<item name="android:navigationBarColor">#38000000</item>
</style>
<style name="Base.V21.Theme.Foundation" parent="Base.V17.Theme.Foundation">
<item name="android:statusBarColor">#60000000</item>
<item name="android:navigationBarColor">#60000000</item>
</style>
<style name="Theme.Foundation.Light" parent="Base.V21.Theme.Foundation.Light" />
<style name="Theme.Foundation" parent="Base.V21.Theme.Foundation" />
<style name="Base.V21.Theme.Splash.Light" parent="Base.V19.Theme.Splash.Light">
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
<style name="Base.V21.Theme.Splash" parent="Base.V19.Theme.Splash">
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
<style name="Theme.Splash.Light" parent="Base.V21.Theme.Splash.Light" />
<style name="Theme.Splash" parent="Base.V21.Theme.Splash" />
</resources>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Base.V23.Theme.Foundation.Light" parent="Base.V21.Theme.Foundation.Light">
<item name="android:statusBarColor">#40bdbdbd</item>
<item name="android:windowLightStatusBar">true</item>
</style>
<style name="Theme.Foundation.Light" parent="Base.V23.Theme.Foundation.Light" />
<style name="Base.V23.Theme.Splash.Light" parent="Base.V21.Theme.Splash.Light">
<item name="android:windowLightStatusBar">false</item>
</style>
<style name="Theme.Splash.Light" parent="Base.V23.Theme.Splash.Light" />
</resources>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Base.V27.Theme.Foundation.Light" parent="Base.V23.Theme.Foundation.Light">
<item name="android:navigationBarColor">#e0fafafa</item>
<item name="android:navigationBarDividerColor">#1f000000</item>
<item name="android:windowLightNavigationBar">true</item>
</style>
<style name="Base.V27.Theme.Foundation" parent="Base.V21.Theme.Foundation">
<item name="android:navigationBarDividerColor">@android:color/transparent</item>
</style>
<style name="Theme.Foundation.Light" parent="Base.V27.Theme.Foundation.Light" />
<style name="Theme.Foundation" parent="Base.V27.Theme.Foundation" />
<style name="Base.V27.Theme.Splash.Light" parent="Base.V23.Theme.Splash.Light">
<item name="android:windowLightNavigationBar">false</item>
</style>
<style name="Theme.Splash.Light" parent="Base.V27.Theme.Splash.Light" />
</resources>

View File

@@ -16,14 +16,6 @@
<item>@string/settings_su_app_adb</item> <item>@string/settings_su_app_adb</item>
</string-array> </string-array>
<string-array name="value_array">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</string-array>
<string-array name="request_timeout"> <string-array name="request_timeout">
<item>@string/settings_su_request_10</item> <item>@string/settings_su_request_10</item>
<item>@string/settings_su_request_15</item> <item>@string/settings_su_request_15</item>

View File

@@ -19,4 +19,32 @@
<!--endregion--> <!--endregion-->
<declare-styleable name="WindowInsetsHelper">
<attr name="edgeToEdge" format="boolean"/>
<attr name="fitsSystemWindowsInsets" format="flags">
<flag name="top" value="0x30" />
<flag name="bottom" value="0x50" />
<flag name="left" value="0x03" />
<flag name="right" value="0x05" />
<flag name="start" value="0x00800003" />
<flag name="end" value="0x00800005" />
</attr>
<attr name="consumeSystemWindowsInsets" format="flags">
<flag name="top" value="0x30" />
<flag name="bottom" value="0x50" />
<flag name="left" value="0x03" />
<flag name="right" value="0x05" />
<flag name="start" value="0x00800003" />
<flag name="end" value="0x00800005" />
</attr>
<attr name="layout_fitsSystemWindowsInsets" format="flags">
<flag name="top" value="0x30" />
<flag name="bottom" value="0x50" />
<flag name="left" value="0x03" />
<flag name="right" value="0x05" />
<flag name="start" value="0x00800003" />
<flag name="end" value="0x00800005" />
</attr>
</declare-styleable>
</resources> </resources>

View File

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<item name="recyclerScrollListener" type="id" /> <item name="recyclerScrollListener" type="id" />
<item name="coroutineScope" type="id"/> <item name="coroutineScope" type="id" />
<item name="tag_rikka_material_WindowInsetsHelper" type="id"/>
<item name="tag_rikka_recyclerView_OverScrollIfContentScrollsListener" type="id"/>
</resources> </resources>

View File

@@ -1,20 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="SplashThemeBase" parent="android:Theme.DeviceDefault.NoActionBar"> <style name="SplashTheme" parent="Theme.Splash.Light" />
<item name="android:windowBackground">@drawable/ic_splash_activity</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="SplashTheme" parent="SplashThemeBase" /> <style name="Foundation" parent="Theme.Foundation.Light" />
<style name="Foundation" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="android:windowBackground">?colorSurface</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<!--This should be overridden in v21 for transparency, etc-->
<style name="Foundation.Compat" />
<!--region Do not remove--> <!--region Do not remove-->
<style name="Empty" /> <style name="Empty" />
@@ -28,7 +17,7 @@
<item name="android:textStyle">bold</item> <item name="android:textStyle">bold</item>
</style> </style>
<style name="Foundation.Default" parent="Foundation.Compat"> <style name="Foundation.Default">
<item name="android:includeFontPadding">false</item> <item name="android:includeFontPadding">false</item>
<item name="actionBarSize">@dimen/internal_action_bar_size</item> <item name="actionBarSize">@dimen/internal_action_bar_size</item>
<item name="popupMenuStyle">@style/Foundation.PopupMenu</item> <item name="popupMenuStyle">@style/Foundation.PopupMenu</item>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Base.V17.Theme.Foundation.Light" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="android:windowBackground">?colorSurface</item>
<item name="android:windowContentOverlay">@null</item>
<item name="dialogTheme">@style/ThemeOverlay.Foundation.Dialog</item>
</style>
<style name="Base.V17.Theme.Foundation" parent="Theme.MaterialComponents.NoActionBar">
<item name="android:windowBackground">?colorSurface</item>
<item name="android:windowContentOverlay">@null</item>
<item name="dialogTheme">@style/ThemeOverlay.Foundation.Dialog</item>
</style>
<style name="Theme.Foundation.Light" parent="Base.V17.Theme.Foundation.Light" />
<style name="Theme.Foundation" parent="Base.V17.Theme.Foundation" />
<style name="Base.V17.Theme.Splash.Light" parent="android:Theme.DeviceDefault.Light.NoActionBar">
<item name="android:windowBackground">@drawable/ic_splash_activity</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="Base.V17.Theme.Splash" parent="android:Theme.DeviceDefault.NoActionBar">
<item name="android:windowBackground">@drawable/ic_splash_activity</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="Theme.Splash.Light" parent="Base.V17.Theme.Splash.Light" />
<style name="Theme.Splash" parent="Base.V17.Theme.Splash" />
<style name="Base.V17.ThemeOverlay.Foundation.Dialog" parent="ThemeOverlay.MaterialComponents.Dialog">
<item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>
</style>
<style name="ThemeOverlay.Foundation.Dialog" parent="Base.V17.ThemeOverlay.Foundation.Dialog" />
</resources>

View File

@@ -14,12 +14,12 @@ buildscript {
maven { url = uri("https://kotlin.bintray.com/kotlinx") } maven { url = uri("https://kotlin.bintray.com/kotlinx") }
} }
val vNav = "2.3.1" val vNav = "2.3.2"
extra["vNav"] = vNav extra["vNav"] = vNav
dependencies { dependencies {
classpath("com.android.tools.build:gradle:4.1.1") classpath("com.android.tools.build:gradle:4.1.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.21")
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:${vNav}") classpath("androidx.navigation:navigation-safe-args-gradle-plugin:${vNav}")
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
@@ -27,7 +27,7 @@ buildscript {
} }
} }
tasks.register("clean",Delete::class){ tasks.register("clean", Delete::class) {
delete(rootProject.buildDir) delete(rootProject.buildDir)
} }
@@ -110,12 +110,12 @@ subprojects {
buildTypes { buildTypes {
signingConfigs.getByName("config").also { signingConfigs.getByName("config").also {
getByName("debug") { getByName("debug") {
// If keystore exists, sign the APK with custom signature signingConfig = if (it.storeFile?.exists() == true) it
if (it.storeFile?.exists() == true) else signingConfigs.getByName("debug")
signingConfig = it
} }
getByName("release") { getByName("release") {
signingConfig = it signingConfig = if (it.storeFile?.exists() == true) it
else signingConfigs.getByName("debug")
} }
} }
} }

222
build.py
View File

@@ -2,20 +2,32 @@
import sys import sys
import os import os
import subprocess import subprocess
import argparse
is_windows = os.name == 'nt' import multiprocessing
if is_windows: import zipfile
import colorama import datetime
colorama.init() import errno
import shutil
import lzma
import platform
import urllib.request
import os.path as op
from distutils.dir_util import copy_tree
def error(str): def error(str):
print('\n' + '\033[41m' + str + '\033[0m' + '\n') if is_ci:
print(f'\n ! {str}\n')
else:
print(f'\n\033[41m{str}\033[0m\n')
sys.exit(1) sys.exit(1)
def header(str): def header(str):
print('\n' + '\033[44m' + str + '\033[0m' + '\n') if is_ci:
print(f'\n{str}\n')
else:
print(f'\n\033[44m{str}\033[0m\n')
def vprint(str): def vprint(str):
@@ -23,6 +35,13 @@ def vprint(str):
print(str) print(str)
is_windows = os.name == 'nt'
is_ci = 'CI' in os.environ and os.environ['CI'] == 'true'
if not is_ci and is_windows:
import colorama
colorama.init()
# Environment checks # Environment checks
if not sys.version_info >= (3, 6): if not sys.version_info >= (3, 6):
error('Requires Python 3.6+') error('Requires Python 3.6+')
@@ -36,28 +55,12 @@ try:
except FileNotFoundError: except FileNotFoundError:
error('Please install JDK and make sure \'javac\' is available in PATH') error('Please install JDK and make sure \'javac\' is available in PATH')
import argparse
import multiprocessing
import zipfile
import datetime
import errno
import shutil
import lzma
import tempfile
import platform
import urllib.request
import os.path as op
from distutils.dir_util import copy_tree
cpu_count = multiprocessing.cpu_count() cpu_count = multiprocessing.cpu_count()
archs = ['armeabi-v7a', 'x86'] archs = ['armeabi-v7a', 'x86']
arch64 = ['arm64-v8a', 'x86_64'] arch64 = ['arm64-v8a', 'x86_64']
support_targets = ['magisk', 'magiskinit', 'magiskboot', 'magiskpolicy', 'resetprop', 'busybox', 'test'] support_targets = ['magisk', 'magiskinit', 'magiskboot', 'magiskpolicy', 'resetprop', 'busybox', 'test']
default_targets = ['magisk', 'magiskinit', 'magiskboot', 'busybox'] default_targets = ['magisk', 'magiskinit', 'magiskboot', 'busybox']
ndk_ver = '21d'
ndk_ver_full = '21.3.6528147'
ndk_root = op.join(os.environ['ANDROID_SDK_ROOT'], 'ndk') ndk_root = op.join(os.environ['ANDROID_SDK_ROOT'], 'ndk')
ndk_path = op.join(ndk_root, 'magisk') ndk_path = op.join(ndk_root, 'magisk')
ndk_build = op.join(ndk_path, 'ndk-build') ndk_build = op.join(ndk_path, 'ndk-build')
@@ -66,6 +69,8 @@ gradlew = op.join('.', 'gradlew' + ('.bat' if is_windows else ''))
# Global vars # Global vars
config = {} config = {}
STDOUT = None STDOUT = None
build_tools = None
def mv(source, target): def mv(source, target):
try: try:
@@ -116,6 +121,10 @@ def system(cmd):
return subprocess.run(cmd, shell=True, stdout=STDOUT) return subprocess.run(cmd, shell=True, stdout=STDOUT)
def cmd_out(cmd):
return subprocess.check_output(cmd).strip().decode('utf-8')
def xz(data): def xz(data):
return lzma.compress(data, preset=9, check=lzma.CHECK_NONE) return lzma.compress(data, preset=9, check=lzma.CHECK_NONE)
@@ -129,37 +138,36 @@ def parse_props(file):
prop = line.split('=') prop = line.split('=')
if len(prop) != 2: if len(prop) != 2:
continue continue
props[prop[0].strip(' \t\r\n')] = prop[1].strip(' \t\r\n') value = prop[1].strip(' \t\r\n')
if len(value) == 0:
continue
props[prop[0].strip(' \t\r\n')] = value
return props return props
def load_config(args): def load_config(args):
# Load prop file commit_hash = cmd_out(['git', 'rev-parse', '--short=8', 'HEAD'])
if not op.exists(args.config):
error(f'Please make sure {args.config} exists')
# Some default values # Default values
config['version'] = commit_hash
config['outdir'] = 'out' config['outdir'] = 'out'
config['prettyName'] = 'false' config['prettyName'] = 'false'
config['keyStore'] = 'release-key.jks'
config.update(parse_props(args.config)) # Load prop files
if op.exists(args.config):
config.update(parse_props(args.config))
# Sanitize configs for key, value in parse_props('gradle.properties').items():
if key.startswith('magisk.'):
config[key[7:]] = value
config['prettyName'] = config['prettyName'].lower() == 'true' config['prettyName'] = config['prettyName'].lower() == 'true'
if 'version' not in config or 'versionCode' not in config:
error('Config error: "version" and "versionCode" is required')
try: try:
config['versionCode'] = int(config['versionCode']) config['versionCode'] = int(config['versionCode'])
except ValueError: except ValueError:
error('Config error: "versionCode" is required to be an integer') error('Config error: "versionCode" is required to be an integer')
if args.release and not op.exists(config['keyStore']):
error(f'Config error: assign "keyStore" to a java keystore')
mkdir_p(config['outdir']) mkdir_p(config['outdir'])
global STDOUT global STDOUT
STDOUT = None if args.verbose else subprocess.DEVNULL STDOUT = None if args.verbose else subprocess.DEVNULL
@@ -188,33 +196,52 @@ def clean_elf():
elf_cleaner = op.join('native', 'out', 'elf-cleaner') elf_cleaner = op.join('native', 'out', 'elf-cleaner')
if not op.exists(elf_cleaner): if not op.exists(elf_cleaner):
execv(['g++', '-std=c++11', 'tools/termux-elf-cleaner/termux-elf-cleaner.cpp', execv(['g++', '-std=c++11', 'tools/termux-elf-cleaner/termux-elf-cleaner.cpp',
'-o', elf_cleaner]) '-o', elf_cleaner])
args = [elf_cleaner] args = [elf_cleaner]
args.extend(op.join('native', 'out', arch, 'magisk') for arch in archs + arch64) args.extend(op.join('native', 'out', arch, 'magisk')
for arch in archs + arch64)
execv(args) execv(args)
def sign_zip(unsigned, output, release): def find_build_tools():
if not release: global build_tools
mv(unsigned, output) if build_tools:
return build_tools
build_tools_root = op.join(os.environ['ANDROID_SDK_ROOT'], 'build-tools')
ls = os.listdir(build_tools_root)
# Use the latest build tools available
ls.sort()
build_tools = op.join(build_tools_root, ls[-1])
return build_tools
def sign_zip(unsigned):
if 'keyStore' not in config:
return return
signer_name = 'zipsigner-4.0.jar' msg = '* Signing APK'
zipsigner = op.join('app', 'signing', 'build', 'libs', signer_name) apksigner = op.join(find_build_tools(), 'apksigner')
if not op.exists(zipsigner): execArgs = [apksigner, 'sign',
header('* Building ' + signer_name) '--ks', config['keyStore'],
proc = execv([gradlew, 'app:signing:shadowJar']) '--ks-pass', f'pass:{config["keyStorePass"]}',
if proc.returncode != 0: '--ks-key-alias', config['keyAlias'],
error(f'Build {signer_name} failed!') '--key-pass', f'pass:{config["keyPass"]}',
'--v1-signer-name', 'CERT',
'--v4-signing-enabled', 'false']
header('* Signing Zip') if unsigned.endswith('.zip'):
msg = '* Signing zip'
execArgs.extend(['--min-sdk-version', '17',
'--v2-signing-enabled', 'false',
'--v3-signing-enabled', 'false'])
proc = execv(['java', '-jar', zipsigner, config['keyStore'], config['keyStorePass'], execArgs.append(unsigned)
config['keyAlias'], config['keyPass'], unsigned, output])
header(msg)
proc = execv(execArgs)
if proc.returncode != 0: if proc.returncode != 0:
error('Signing zip failed!') error('Signing failed!')
def binary_dump(src, out, var_name): def binary_dump(src, out, var_name):
@@ -274,9 +301,7 @@ def dump_bin_headers():
binary_dump(src, out, 'magisk_xz') binary_dump(src, out, 'magisk_xz')
stub = op.join(config['outdir'], 'stub-release.apk') stub = op.join(config['outdir'], 'stub-release.apk')
if not op.exists(stub): if not op.exists(stub):
stub = op.join(config['outdir'], 'stub-debug.apk') error('Build stub APK before building "magiskinit"')
if not op.exists(stub):
error('Build stub APK before building "magiskinit"')
with open(op.join('native', 'out', 'binaries.h'), 'w') as out: with open(op.join('native', 'out', 'binaries.h'), 'w') as out:
with open(stub, 'rb') as src: with open(stub, 'rb') as src:
binary_dump(src, out, 'manager_xz') binary_dump(src, out, 'manager_xz')
@@ -285,7 +310,7 @@ def dump_bin_headers():
def build_binary(args): def build_binary(args):
# Verify NDK install # Verify NDK install
props = parse_props(op.join(ndk_path, 'source.properties')) props = parse_props(op.join(ndk_path, 'source.properties'))
if props['Pkg.Revision'] != ndk_ver_full: if props['Pkg.Revision'] != config['fullNdkVersion']:
error('Incorrect NDK. Please install/upgrade NDK with "build.py ndk"') error('Incorrect NDK. Please install/upgrade NDK with "build.py ndk"')
if args.target: if args.target:
@@ -297,7 +322,20 @@ def build_binary(args):
header('* Building binaries: ' + ' '.join(args.target)) header('* Building binaries: ' + ' '.join(args.target))
os.utime(op.join('native', 'jni', 'include', 'flags.hpp')) update_flags = False
flags = op.join('native', 'jni', 'include', 'flags.hpp')
flags_stat = os.stat(flags)
if op.exists(args.config):
if os.stat(args.config).st_mtime_ns > flags_stat.st_mtime_ns:
update_flags = True
last_commit = int(cmd_out(['git', 'log', '-1', r'--format=%at', 'HEAD']))
if last_commit > flags_stat.st_mtime:
update_flags = True
if update_flags:
os.utime(flags)
# Basic flags # Basic flags
global base_flags global base_flags
@@ -331,10 +369,10 @@ def build_binary(args):
def build_apk(args, module): def build_apk(args, module):
build_type = 'Release' if args.release else 'Debug' build_type = 'Release' if args.release or module == 'stub' else 'Debug'
proc = execv([gradlew, f'{module}:assemble{build_type}', proc = execv([gradlew, f'{module}:assemble{build_type}',
'-PconfigPath=' + op.abspath(args.config)]) '-PconfigPath=' + op.abspath(args.config)])
if proc.returncode != 0: if proc.returncode != 0:
error(f'Build {module} failed!') error(f'Build {module} failed!')
@@ -379,10 +417,16 @@ def build_snet(args):
def zip_main(args): def zip_main(args):
header('* Packing Flashable Zip') header('* Packing Flashable Zip')
with tempfile.NamedTemporaryFile(delete=False) as f: if config['prettyName']:
unsigned = f.name name = f'Magisk-v{config["version"]}.zip'
elif args.release:
name = 'magisk-release.zip'
else:
name = 'magisk-debug.zip'
with zipfile.ZipFile(unsigned, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf: output = op.join(config['outdir'], name)
with zipfile.ZipFile(output, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
# update-binary # update-binary
target = op.join('META-INF', 'com', 'google', target = op.join('META-INF', 'com', 'google',
'android', 'update-binary') 'android', 'update-binary')
@@ -429,26 +473,27 @@ def zip_main(args):
# chromeos # chromeos
for tool in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']: for tool in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
source = op.join('tools', tool) if tool == 'futility':
source = op.join('tools', tool)
else:
source = op.join('tools', 'keys', tool)
target = op.join('chromeos', tool) target = op.join('chromeos', tool)
zip_with_msg(zipf, source, target) zip_with_msg(zipf, source, target)
# End of zipping # End of zipping
output = op.join(config['outdir'], f'Magisk-v{config["version"]}.zip' if config['prettyName'] else sign_zip(output)
'magisk-release.zip' if args.release else 'magisk-debug.zip')
sign_zip(unsigned, output, args.release)
rm(unsigned)
header('Output: ' + output) header('Output: ' + output)
def zip_uninstaller(args): def zip_uninstaller(args):
header('* Packing Uninstaller Zip') header('* Packing Uninstaller Zip')
with tempfile.NamedTemporaryFile(delete=False) as f: datestr = datetime.datetime.now().strftime("%Y%m%d")
unsigned = f.name name = f'Magisk-uninstaller-{datestr}.zip' if config['prettyName'] else 'magisk-uninstaller.zip'
output = op.join(config['outdir'], name)
with zipfile.ZipFile(unsigned, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf: with zipfile.ZipFile(output, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
# update-binary # update-binary
target = op.join('META-INF', 'com', 'google', target = op.join('META-INF', 'com', 'google',
'android', 'update-binary') 'android', 'update-binary')
@@ -475,17 +520,16 @@ def zip_uninstaller(args):
# chromeos # chromeos
for tool in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']: for tool in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
source = op.join('tools', tool) if tool == 'futility':
source = op.join('tools', tool)
else:
source = op.join('tools', 'keys', tool)
target = op.join('chromeos', tool) target = op.join('chromeos', tool)
zip_with_msg(zipf, source, target) zip_with_msg(zipf, source, target)
# End of zipping # End of zipping
datestr = datetime.datetime.now().strftime("%Y%m%d") sign_zip(output)
output = op.join(config['outdir'], f'Magisk-uninstaller-{datestr}.zip'
if config['prettyName'] else 'magisk-uninstaller.zip')
sign_zip(unsigned, output, args.release)
rm(unsigned)
header('Output: ' + output) header('Output: ' + output)
@@ -510,6 +554,7 @@ def cleanup(args):
def setup_ndk(args): def setup_ndk(args):
os_name = platform.system().lower() os_name = platform.system().lower()
ndk_ver = config['ndkVersion']
url = f'https://dl.google.com/android/repository/android-ndk-r{ndk_ver}-{os_name}-x86_64.zip' url = f'https://dl.google.com/android/repository/android-ndk-r{ndk_ver}-{os_name}-x86_64.zip'
ndk_zip = url.split('/')[-1] ndk_zip = url.split('/')[-1]
@@ -523,7 +568,7 @@ def setup_ndk(args):
for info in zf.infolist(): for info in zf.infolist():
extracted_path = zf.extract(info, ndk_root) extracted_path = zf.extract(info, ndk_root)
vprint(f'Extracting {info.filename}') vprint(f'Extracting {info.filename}')
if info.create_system == 3: # ZIP_UNIX_SYSTEM = 3 if info.create_system == 3: # ZIP_UNIX_SYSTEM = 3
unix_attributes = info.external_attr >> 16 unix_attributes = info.external_attr >> 16
if unix_attributes: if unix_attributes:
os.chmod(extracted_path, unix_attributes) os.chmod(extracted_path, unix_attributes)
@@ -540,15 +585,15 @@ def setup_ndk(args):
header('* Replacing API-16 static libs') header('* Replacing API-16 static libs')
for target in ['arm-linux-androideabi', 'i686-linux-android']: for target in ['arm-linux-androideabi', 'i686-linux-android']:
arch = target.split('-')[0] arch = target.split('-')[0]
lib_dir = op.join( lib_dir = op.join(
ndk_path, 'toolchains', 'llvm', 'prebuilt', f'{os_name}-x86_64', ndk_path, 'toolchains', 'llvm', 'prebuilt', f'{os_name}-x86_64',
'sysroot', 'usr', 'lib', f'{target}', '16') 'sysroot', 'usr', 'lib', f'{target}', '16')
src_dir = op.join('tools', 'ndk-bins', arch) src_dir = op.join('tools', 'ndk-bins', arch)
# Remove stupid macOS crap # Remove stupid macOS crap
rm(op.join(src_dir, '.DS_Store')) rm(op.join(src_dir, '.DS_Store'))
for path in copy_tree(src_dir, lib_dir): for path in copy_tree(src_dir, lib_dir):
vprint(f'Replaced {path}') vprint(f'Replaced {path}')
def build_all(args): def build_all(args):
@@ -561,12 +606,13 @@ def build_all(args):
parser = argparse.ArgumentParser(description='Magisk build script') parser = argparse.ArgumentParser(description='Magisk build script')
parser.set_defaults(func=lambda x: None)
parser.add_argument('-r', '--release', action='store_true', parser.add_argument('-r', '--release', action='store_true',
help='compile in release mode') help='compile in release mode')
parser.add_argument('-v', '--verbose', action='store_true', parser.add_argument('-v', '--verbose', action='store_true',
help='verbose output') help='verbose output')
parser.add_argument('-c', '--config', default='config.prop', parser.add_argument('-c', '--config', default='config.prop',
help='override config file (default: config.prop)') help='custom config file (default: config.prop)')
subparsers = parser.add_subparsers(title='actions') subparsers = parser.add_subparsers(title='actions')
all_parser = subparsers.add_parser( all_parser = subparsers.add_parser(

View File

@@ -13,3 +13,7 @@ gradlePlugin {
} }
} }
} }
dependencies {
implementation("org.eclipse.jgit:org.eclipse.jgit:5.10.0.202012080955-r")
}

View File

@@ -1,5 +1,6 @@
import org.gradle.api.GradleException import org.eclipse.jgit.api.Git
import org.eclipse.jgit.internal.storage.file.FileRepository
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.provideDelegate
@@ -7,19 +8,30 @@ import java.io.File
import java.util.* import java.util.*
private val props = Properties() private val props = Properties()
private lateinit var commitHash: String
private var commitCount = 0
object Config { object Config {
operator fun get(key: String) = props[key] as? String operator fun get(key: String) : String? {
fun contains(key: String) = props.containsKey(key) val v = props[key] as? String ?: return null
return if (v.isBlank()) null else v
}
fun contains(key: String) = get(key) != null
val appVersion: String get() = get("appVersion") ?: commitHash
val appVersionCode: Int get() = commitCount
} }
class MagiskPlugin : Plugin<Project> { class MagiskPlugin : Plugin<Project> {
override fun apply(project: Project) { override fun apply(project: Project) {
val configPath: String? by project val configPath: String? by project
val file = configPath?.let { File(it) } ?: project.file("config.prop") val config = configPath?.let { File(it) } ?: project.rootProject.file("config.prop")
if (!file.exists()) if (config.exists())
throw GradleException("Please setup config.prop") config.inputStream().use { props.load(it) }
file.inputStream().use { props.load(it) } val repo = FileRepository(project.rootProject.file(".git"))
val refId = repo.refDatabase.exactRef("HEAD").objectId
commitHash = repo.newObjectReader().abbreviate(refId, 8).name()
commitCount = Git(repo).log().add(refId).call().count()
} }
} }

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