mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 08:07:25 +00:00
Compare commits
144 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7f8257152f | ||
![]() |
0cd80f2556 | ||
![]() |
1717387876 | ||
![]() |
109363ebf6 | ||
![]() |
716c4fa386 | ||
![]() |
9a09b4eb20 | ||
![]() |
95a5b57265 | ||
![]() |
13fbf397d1 | ||
![]() |
20be99ec8a | ||
![]() |
04c53c3578 | ||
![]() |
51bc27a869 | ||
![]() |
71b083794c | ||
![]() |
b100d0c503 | ||
![]() |
76061296c9 | ||
![]() |
bb303d2da1 | ||
![]() |
c91c070343 | ||
![]() |
aec06a6f61 | ||
![]() |
e8ba671fc2 | ||
![]() |
1860e5d133 | ||
![]() |
f2cb3c38fe | ||
![]() |
9a28dd4f6e | ||
![]() |
d2acd59ea8 | ||
![]() |
79dfdb29e7 | ||
![]() |
eb21c8b42e | ||
![]() |
541bb53553 | ||
![]() |
fe8997efae | ||
![]() |
23455c722c | ||
![]() |
5ce29c30d2 | ||
![]() |
70d67728fd | ||
![]() |
e546884b08 | ||
![]() |
b36e6d987d | ||
![]() |
53c3dd5e8b | ||
![]() |
da723b207a | ||
![]() |
e050f77198 | ||
![]() |
540b4b7ea9 | ||
![]() |
bbef22daf7 | ||
![]() |
9ed110c91b | ||
![]() |
a30d510eb1 | ||
![]() |
ef98eaed8f | ||
![]() |
2a257f327c | ||
![]() |
4060c2107c | ||
![]() |
cd23d27048 | ||
![]() |
18b86e4fd2 | ||
![]() |
5f2e22a259 | ||
![]() |
4e97b18977 | ||
![]() |
f9bde347bc | ||
![]() |
947a7d6a2f | ||
![]() |
872ab2e99b | ||
![]() |
90b8813bb7 | ||
![]() |
88d0f63294 | ||
![]() |
79fa0d3a90 | ||
![]() |
8e61080a4a | ||
![]() |
3f9a64417b | ||
![]() |
eb959379e8 | ||
![]() |
41a644afb9 | ||
![]() |
6b42db943d | ||
![]() |
1c325459eb | ||
![]() |
6d88d8ad95 | ||
![]() |
246997f273 | ||
![]() |
b6144ae582 | ||
![]() |
afe17c73b4 | ||
![]() |
b51b884fc7 | ||
![]() |
d3e4b29e62 | ||
![]() |
24059e7403 | ||
![]() |
107a2a6682 | ||
![]() |
56b4ab6672 | ||
![]() |
4662454938 | ||
![]() |
db4f78d463 | ||
![]() |
880de21596 | ||
![]() |
622dd84c9e | ||
![]() |
f983bfc883 | ||
![]() |
45cdb3fdb0 | ||
![]() |
9a707236b8 | ||
![]() |
e9e6ad3bb0 | ||
![]() |
ab78a81d15 | ||
![]() |
18340099b7 | ||
![]() |
a013696a41 | ||
![]() |
8a2a6d9232 | ||
![]() |
12aa6d86e4 | ||
![]() |
7d08969d28 | ||
![]() |
dda4aa8488 | ||
![]() |
cdaef3d801 | ||
![]() |
9159166128 | ||
![]() |
dc0882e043 | ||
![]() |
c811f015ef | ||
![]() |
d8f0b66fe1 | ||
![]() |
dc3d57deba | ||
![]() |
d089698475 | ||
![]() |
8ed2dd6687 | ||
![]() |
50305ca1fe | ||
![]() |
3e91567636 | ||
![]() |
0b4dd63d36 | ||
![]() |
38d0f85deb | ||
![]() |
c5b452f369 | ||
![]() |
6ce9225f52 | ||
![]() |
13a8820603 | ||
![]() |
503997a09a | ||
![]() |
17efdff134 | ||
![]() |
984f32f994 | ||
![]() |
eee7f097e3 | ||
![]() |
086059ec30 | ||
![]() |
7ff22c68c7 | ||
![]() |
1232113772 | ||
![]() |
039d4936cb | ||
![]() |
784dd80965 | ||
![]() |
1ffe9bd83b | ||
![]() |
0c28b23224 | ||
![]() |
ec1af9dc1e | ||
![]() |
ff4cea229a | ||
![]() |
3f81f9371f | ||
![]() |
60e89a7d22 | ||
![]() |
c50daa5c9e | ||
![]() |
58d00ab863 | ||
![]() |
ce916459c5 | ||
![]() |
4094d560ab | ||
![]() |
4dbf7eb04b | ||
![]() |
a39577c44d | ||
![]() |
125ee46685 | ||
![]() |
ce84f1762c | ||
![]() |
a687d1347b | ||
![]() |
6d9db20614 | ||
![]() |
c62dfc1bcc | ||
![]() |
aabe2696fe | ||
![]() |
ae0d605310 | ||
![]() |
2a694596b5 | ||
![]() |
ff0a76606e | ||
![]() |
dead74801d | ||
![]() |
ab207a1bb3 | ||
![]() |
f152e8c33d | ||
![]() |
797ba4fbf4 | ||
![]() |
a848f10bba | ||
![]() |
552ec1eb35 | ||
![]() |
1385d2a4f4 | ||
![]() |
3b5c9abf7a | ||
![]() |
e0fa032bd3 | ||
![]() |
7b69650fcd | ||
![]() |
08a8df489f | ||
![]() |
9f35a8a520 | ||
![]() |
0df891b336 | ||
![]() |
385853a290 | ||
![]() |
fa3ef8a1c1 | ||
![]() |
c93ada03c7 | ||
![]() |
0064b01ae0 | ||
![]() |
1469b82aa2 |
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal 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
94
.github/workflows/build.yml
vendored
Normal 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
3
.gitmodules
vendored
@@ -25,6 +25,9 @@
|
||||
[submodule "pcre"]
|
||||
path = native/jni/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"]
|
||||
path = tools/termux-elf-cleaner
|
||||
url = https://github.com/termux/termux-elf-cleaner.git
|
||||
|
10
README.MD
10
README.MD
@@ -15,11 +15,11 @@ Here are some feature highlights:
|
||||
|
||||
## Downloads
|
||||
|
||||
[](https://github.com/topjohnwu/Magisk/releases/download/manager-v8.0.2/MagiskManager-v8.0.2.apk)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/download/manager-v8.0.5/MagiskManager-v8.0.5.apk)
|
||||
[](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-debug.apk)
|
||||
<br>
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v20.4)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v21.0)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v21.2)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v21.2)
|
||||
|
||||
## 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`
|
||||
- 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
|
||||
- Set configurations in `config.prop`. A sample `config.prop.sample` is provided.
|
||||
- To start building, run `build.py` to see your options. \
|
||||
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.
|
||||
- `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
|
||||
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import java.io.PrintStream
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
kotlin("android")
|
||||
kotlin("android.extensions")
|
||||
kotlin("plugin.parcelize")
|
||||
kotlin("kapt")
|
||||
id("androidx.navigation.safeargs.kotlin")
|
||||
}
|
||||
@@ -20,12 +22,11 @@ android {
|
||||
applicationId = "com.topjohnwu.magisk"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
multiDexEnabled = true
|
||||
versionName = Config["appVersion"]
|
||||
versionCode = Config["appVersionCode"]?.toInt()
|
||||
buildConfigField("int", "LATEST_MAGISK", Config["versionCode"] ?: "Integer.MAX_VALUE")
|
||||
versionName = Config.appVersion
|
||||
versionCode = Config.appVersionCode
|
||||
|
||||
javaCompileOptions.annotationProcessorOptions.arguments(
|
||||
mapOf("room.incremental" to "true")
|
||||
mapOf("room.incremental" to "true")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -64,28 +65,61 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
androidExtensions {
|
||||
isExperimental = true
|
||||
}
|
||||
|
||||
val copyUtils = tasks.register("copyUtils", Copy::class) {
|
||||
tasks["preBuild"]?.dependsOn(tasks.register("copyUtils", Copy::class) {
|
||||
from(rootProject.file("scripts/util_functions.sh"))
|
||||
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 {
|
||||
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
|
||||
implementation(kotlin("stdlib"))
|
||||
implementation(project(":app:shared"))
|
||||
implementation(project(":app:signing"))
|
||||
|
||||
implementation("com.github.topjohnwu:jtar:1.0.0")
|
||||
implementation("com.github.topjohnwu:indeterminate-checkbox:1.0.7")
|
||||
implementation("com.github.topjohnwu:lz4-java:1.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 bindingAdapter = "me.tatarka.bindingcollectionadapter2:bindingcollectionadapter"
|
||||
implementation("${bindingAdapter}:${vBAdapt}")
|
||||
@@ -124,7 +158,7 @@ dependencies {
|
||||
implementation("com.squareup.moshi:moshi:${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-ktx:${vRoom}")
|
||||
kapt("androidx.room:room-compiler:${vRoom}")
|
||||
@@ -136,7 +170,7 @@ dependencies {
|
||||
implementation("androidx.biometric:biometric:1.0.1")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
|
||||
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.recyclerview:recyclerview:1.1.0")
|
||||
implementation("androidx.fragment:fragment-ktx:1.2.5")
|
||||
|
1
app/signing/.gitignore
vendored
1
app/signing/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/build
|
@@ -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")
|
||||
}
|
@@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@
|
||||
<application
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:name="a.e"
|
||||
android:allowBackup="true"
|
||||
android:allowBackup="false"
|
||||
tools:ignore="UnusedAttribute,GoogleAppIndexingWarning">
|
||||
|
||||
<!-- Splash -->
|
||||
|
@@ -8,10 +8,10 @@ import com.topjohnwu.magisk.core.SplashActivity
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.ui.MainActivity
|
||||
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
|
||||
import com.topjohnwu.signing.BootSigner
|
||||
import com.topjohnwu.signing.SignBoot
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
BootSigner.main(args)
|
||||
SignBoot.main(args)
|
||||
}
|
||||
|
||||
class b : MainActivity()
|
||||
|
@@ -1,5 +1,8 @@
|
||||
package com.topjohnwu.magisk.arch
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
@@ -14,6 +17,7 @@ import androidx.navigation.fragment.NavHostFragment
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.ui.inflater.LayoutInflaterFactory
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
|
||||
abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
@@ -41,6 +45,8 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
layoutInflater.factory2 = LayoutInflaterFactory(delegate)
|
||||
|
||||
setTheme(themeRes)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@@ -59,6 +65,31 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
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() {
|
||||
@@ -66,8 +97,6 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
it.setVariable(BR.viewModel, viewModel)
|
||||
it.lifecycleOwner = this
|
||||
}
|
||||
|
||||
ensureInsets()
|
||||
}
|
||||
|
||||
fun setAccessibilityDelegate(delegate: View.AccessibilityDelegate?) {
|
||||
|
@@ -1,12 +1,9 @@
|
||||
package com.topjohnwu.magisk.arch
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
|
||||
interface BaseUIComponent<VM : BaseViewModel>: LifecycleOwner {
|
||||
interface BaseUIComponent<VM : BaseViewModel> : LifecycleOwner {
|
||||
|
||||
val viewRoot: View
|
||||
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.
|
||||
*/
|
||||
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()
|
||||
|
||||
}
|
||||
|
@@ -24,8 +24,6 @@ abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
override val viewRoot: View get() = binding.root
|
||||
private val navigation get() = activity.navigation
|
||||
|
||||
override fun consumeSystemWindowInsets(insets: Insets) = insets
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
startObserveEvents()
|
||||
@@ -43,6 +41,11 @@ abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity.supportActionBar?.subtitle = null
|
||||
}
|
||||
|
||||
override fun onEventDispatched(event: ViewEvent) = when(event) {
|
||||
is ContextExecutor -> event(requireContext())
|
||||
is ActivityExecutor -> event(activity)
|
||||
@@ -65,7 +68,6 @@ abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
return true
|
||||
}
|
||||
})
|
||||
ensureInsets()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@@ -18,7 +18,6 @@ import com.topjohnwu.magisk.ktx.inject
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
||||
object Config : PreferenceModel, DBConfig {
|
||||
@@ -159,12 +158,13 @@ object Config : PreferenceModel, DBConfig {
|
||||
|
||||
private const val SU_FINGERPRINT = "su_fingerprint"
|
||||
|
||||
fun load(pkg: String) {
|
||||
try {
|
||||
fun load(pkg: String?) {
|
||||
// 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 {
|
||||
prefs.edit { parsePrefs(it) }
|
||||
}
|
||||
} catch (e: IOException) {}
|
||||
}
|
||||
|
||||
prefs.edit {
|
||||
// Settings migration
|
||||
|
@@ -16,8 +16,6 @@ object Const {
|
||||
const val BOOTCTL_REVISION = "18ab78817087c337ae0edd1ecac38aec49217880"
|
||||
|
||||
// Misc
|
||||
const val ANDROID_MANIFEST = "AndroidManifest.xml"
|
||||
const val MAGISK_INSTALL_LOG_FILENAME = "magisk_install_log_%s.log"
|
||||
val USER_ID = Process.myUid() / 100000
|
||||
|
||||
object Version {
|
||||
@@ -27,6 +25,7 @@ object Const {
|
||||
fun atLeast_20_2() = Info.env.magiskVersionCode >= 20200 || isCanary()
|
||||
fun atLeast_20_4() = Info.env.magiskVersionCode >= 20400 || 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
|
||||
}
|
||||
|
||||
@@ -38,7 +37,6 @@ object Const {
|
||||
// notifications
|
||||
const val MAGISK_UPDATE_NOTIFICATION_ID = 4
|
||||
const val APK_UPDATE_NOTIFICATION_ID = 5
|
||||
const val HIDE_MANAGER_NOTIFICATION_ID = 8
|
||||
const val UPDATE_NOTIFICATION_CHANNEL = "update"
|
||||
const val PROGRESS_NOTIFICATION_CHANNEL = "progress"
|
||||
const val CHECK_MAGISK_UPDATE_WORKER_ID = "magisk_update"
|
||||
@@ -58,7 +56,7 @@ object Const {
|
||||
object Key {
|
||||
// intents
|
||||
const val OPEN_SECTION = "section"
|
||||
const val HIDDEN_PKG = "hidden_pkg"
|
||||
const val PREV_PKG = "prev_pkg"
|
||||
}
|
||||
|
||||
object Value {
|
||||
|
@@ -48,10 +48,10 @@ open class SplashActivity : Activity() {
|
||||
// Pre-initialize root shell
|
||||
Shell.getShell()
|
||||
|
||||
val hiddenPackage = intent.getStringExtra(Const.Key.HIDDEN_PKG)
|
||||
val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)
|
||||
|
||||
Config.load(hiddenPackage ?: APPLICATION_ID)
|
||||
handleRepackage(hiddenPackage)
|
||||
Config.load(prevPkg)
|
||||
handleRepackage(prevPkg)
|
||||
Notifications.setup(this)
|
||||
UpdateCheckService.schedule(this)
|
||||
Shortcuts.setupDynamic(this)
|
||||
|
@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.core.download
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Parcelable
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
sealed class Action : Parcelable {
|
||||
|
||||
|
@@ -12,8 +12,8 @@ import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
import com.topjohnwu.magisk.ktx.cachedFile
|
||||
import com.topjohnwu.magisk.ktx.get
|
||||
import kotlinx.android.parcel.IgnoredOnParcel
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
private fun cachedFile(name: String) = get<Context>().cachedFile(name).apply { delete() }.toUri()
|
||||
|
||||
@@ -101,7 +101,6 @@ sealed class Subject : Parcelable {
|
||||
Action.Download -> Download()
|
||||
Action.Uninstall -> Uninstall()
|
||||
Action.EnvFix, is Action.Flash, is Action.Patch -> Internal(config)
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.core.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.squareup.moshi.JsonClass
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class UpdateInfo(
|
||||
|
@@ -27,13 +27,13 @@ class LocalModule(path: String) : Module() {
|
||||
val dir = "$PERSIST/$id"
|
||||
if (enable) {
|
||||
disableFile.delete()
|
||||
if (Const.Version.isCanary())
|
||||
if (Const.Version.atLeast_21_2())
|
||||
Shell.su("copy_sepolicy_rules").submit()
|
||||
else
|
||||
Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
|
||||
} else {
|
||||
!disableFile.createNewFile()
|
||||
if (Const.Version.isCanary())
|
||||
if (Const.Version.atLeast_21_2())
|
||||
Shell.su("copy_sepolicy_rules").submit()
|
||||
else
|
||||
Shell.su("rm -rf $dir").submit()
|
||||
@@ -45,13 +45,13 @@ class LocalModule(path: String) : Module() {
|
||||
set(remove) {
|
||||
if (remove) {
|
||||
removeFile.createNewFile()
|
||||
if (Const.Version.isCanary())
|
||||
if (Const.Version.atLeast_21_2())
|
||||
Shell.su("copy_sepolicy_rules").submit()
|
||||
else
|
||||
Shell.su("rm -rf $PERSIST/$id").submit()
|
||||
} else {
|
||||
!removeFile.delete()
|
||||
if (Const.Version.isCanary())
|
||||
if (Const.Version.atLeast_21_2())
|
||||
Shell.su("copy_sepolicy_rules").submit()
|
||||
else
|
||||
Shell.su("cp -af $ruleFile $PERSIST/$id").submit()
|
||||
|
@@ -7,7 +7,7 @@ import com.topjohnwu.magisk.core.model.ModuleJson
|
||||
import com.topjohnwu.magisk.data.repository.NetworkService
|
||||
import com.topjohnwu.magisk.ktx.get
|
||||
import com.topjohnwu.magisk.ktx.legalFilename
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
|
@@ -33,6 +33,7 @@ object HideAPK {
|
||||
private const val ALPHA = "abcdefghijklmnopqrstuvwxyz"
|
||||
private const val ALPHADOTS = "$ALPHA....."
|
||||
private const val APP_NAME = "Magisk Manager"
|
||||
private const val ANDROID_MANIFEST = "AndroidManifest.xml"
|
||||
|
||||
// Some arbitrary limit
|
||||
const val MAX_LABEL_LENGTH = 32
|
||||
@@ -71,7 +72,7 @@ object HideAPK {
|
||||
): Boolean {
|
||||
try {
|
||||
val jar = JarMap.open(apk)
|
||||
val je = jar.getJarEntry(Const.ANDROID_MANIFEST)
|
||||
val je = jar.getJarEntry(ANDROID_MANIFEST)
|
||||
val xml = AXML(jar.getRawData(je))
|
||||
|
||||
if (!xml.findAndPatch(APPLICATION_ID to pkg, APP_NAME to label.toString()))
|
||||
@@ -123,6 +124,7 @@ object HideAPK {
|
||||
Config.suManager = pkg
|
||||
grantUriPermission(pkg, APK_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)
|
||||
}
|
||||
|
||||
@@ -167,7 +169,7 @@ object HideAPK {
|
||||
Config.suManager = ""
|
||||
grantUriPermission(APPLICATION_ID, APK_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)
|
||||
}
|
||||
|
||||
|
@@ -8,8 +8,10 @@ import android.widget.Toast
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.os.postDelayed
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
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.inputStream
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||
@@ -40,6 +42,8 @@ import org.koin.core.inject
|
||||
import timber.log.Timber
|
||||
import java.io.*
|
||||
import java.nio.ByteBuffer
|
||||
import java.security.SecureRandom
|
||||
import java.util.*
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
@@ -107,6 +111,8 @@ abstract class MagiskInstallImpl : KoinComponent {
|
||||
}
|
||||
|
||||
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 {
|
||||
ZipInputStream(zipUri.inputStream().buffered()).use { zi ->
|
||||
@@ -185,9 +191,10 @@ abstract class MagiskInstallImpl : KoinComponent {
|
||||
if (rawData.size < 256)
|
||||
continue
|
||||
|
||||
// Patch flags to AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED
|
||||
// Patch flags to AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED |
|
||||
// AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED
|
||||
console.add("-- Patching: vbmeta.img")
|
||||
ByteBuffer.wrap(rawData).putInt(120, 2)
|
||||
ByteBuffer.wrap(rawData).putInt(120, 3)
|
||||
tarOut.putNextEntry(newEntry("vbmeta.img", rawData.size.toLong()))
|
||||
tarOut.write(rawData)
|
||||
} else {
|
||||
@@ -198,7 +205,7 @@ abstract class MagiskInstallImpl : KoinComponent {
|
||||
}
|
||||
val boot = SuFile.open(installDir, "boot.img")
|
||||
val recovery = SuFile.open(installDir, "recovery.img")
|
||||
if (recovery.exists() && boot.exists()) {
|
||||
if (Config.recovery && recovery.exists() && boot.exists()) {
|
||||
// Install Magisk to recovery
|
||||
srcBoot = recovery.path
|
||||
// Repack boot image to prevent restore
|
||||
@@ -225,7 +232,7 @@ abstract class MagiskInstallImpl : KoinComponent {
|
||||
|
||||
private fun handleFile(uri: Uri): Boolean {
|
||||
val outStream: OutputStream
|
||||
val outFile: MediaStoreUtils.UriFile
|
||||
var outFile: MediaStoreUtils.UriFile? = null
|
||||
|
||||
// Process input file
|
||||
try {
|
||||
@@ -237,27 +244,40 @@ abstract class MagiskInstallImpl : KoinComponent {
|
||||
return false
|
||||
}
|
||||
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())) {
|
||||
outFile = MediaStoreUtils.getFile("magisk_patched.tar")
|
||||
handleTar(src, outFile.uri.outputStream())
|
||||
outFile = MediaStoreUtils.getFile("$filename.tar", true)
|
||||
handleTar(src, outFile!!.uri.outputStream())
|
||||
} else {
|
||||
// Raw image
|
||||
srcBoot = File(installDir, "boot.img").path
|
||||
console.add("- Copying image to cache")
|
||||
FileOutputStream(srcBoot).use { src.copyTo(it) }
|
||||
outFile = MediaStoreUtils.getFile("magisk_patched.img")
|
||||
outFile.uri.outputStream()
|
||||
outFile = MediaStoreUtils.getFile("$filename.img", true)
|
||||
outFile!!.uri.outputStream()
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
console.add("! Process error")
|
||||
outFile?.delete()
|
||||
Timber.e(e)
|
||||
return false
|
||||
}
|
||||
|
||||
// Patch file
|
||||
if (!patchBoot())
|
||||
if (!patchBoot()) {
|
||||
outFile!!.delete()
|
||||
return false
|
||||
}
|
||||
|
||||
// Output file
|
||||
try {
|
||||
@@ -276,6 +296,7 @@ abstract class MagiskInstallImpl : KoinComponent {
|
||||
console.add("****************************")
|
||||
} catch (e: IOException) {
|
||||
console.add("! Failed to output to $outFile")
|
||||
outFile!!.delete()
|
||||
Timber.e(e)
|
||||
return false
|
||||
}
|
||||
@@ -325,7 +346,7 @@ abstract class MagiskInstallImpl : KoinComponent {
|
||||
val signed = File(installDir, "signed.img")
|
||||
try {
|
||||
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) {
|
||||
console.add("! Unable to sign image")
|
||||
@@ -339,6 +360,13 @@ abstract class MagiskInstallImpl : KoinComponent {
|
||||
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 {
|
||||
if (!"direct_install $installDir $srcBoot".sh().isSuccess)
|
||||
return false
|
||||
@@ -373,10 +401,11 @@ abstract class MagiskInstallImpl : KoinComponent {
|
||||
|
||||
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() =
|
||||
findSecondaryImage() && extractZip() && patchBoot() && flashBoot() && postOTA()
|
||||
protected suspend fun secondSlot() = findSecondaryImage() && extractZip() &&
|
||||
patchBoot() && copySepolicyRules() && flashBoot() && postOTA()
|
||||
|
||||
protected fun fixEnv(zip: Uri): Boolean {
|
||||
installDir = SuFile("/data/adb/magisk")
|
||||
|
@@ -7,10 +7,12 @@ import android.util.Base64OutputStream
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.signing.CryptoUtils.readCertificate
|
||||
import com.topjohnwu.signing.CryptoUtils.readPrivateKey
|
||||
import com.topjohnwu.signing.KeyData
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
|
||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.math.BigInteger
|
||||
import java.security.KeyPairGenerator
|
||||
@@ -58,10 +60,10 @@ class Keygen(context: Context) : CertKeyProvider {
|
||||
|
||||
class TestProvider : CertKeyProvider {
|
||||
override val cert by lazy {
|
||||
readCertificate(javaClass.getResourceAsStream("/keys/testkey.x509.pem"))
|
||||
readCertificate(ByteArrayInputStream(KeyData.testCert()))
|
||||
}
|
||||
override val key by lazy {
|
||||
readPrivateKey(javaClass.getResourceAsStream("/keys/testkey.pk8"))
|
||||
readPrivateKey(ByteArrayInputStream(KeyData.testKey()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentResolver
|
||||
import android.content.ContentUris
|
||||
import android.content.ContentValues
|
||||
@@ -40,15 +39,17 @@ object MediaStoreUtils {
|
||||
|
||||
private val relativePath get() = relativePath(Config.downloadDir)
|
||||
|
||||
@RequiresApi(api = 29)
|
||||
@RequiresApi(api = 30)
|
||||
@Throws(IOException::class)
|
||||
private fun insertFile(displayName: String): MediaStoreFile {
|
||||
val values = ContentValues()
|
||||
values.put(MediaStore.MediaColumns.RELATIVE_PATH, relativePath)
|
||||
values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)
|
||||
|
||||
// before Android 11, MediaStore can not rename new file when file exists,
|
||||
// insert will return null. use newFile() instead.
|
||||
// When a file with the same name exists and was not created by us:
|
||||
// - 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 projection = arrayOf(MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DATA)
|
||||
@@ -65,14 +66,8 @@ object MediaStoreUtils {
|
||||
throw IOException("Can't insert $displayName.")
|
||||
}
|
||||
|
||||
@RequiresApi(api = 29)
|
||||
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)
|
||||
// Before Android 10, we wrote the DISPLAY_NAME field when insert, so it can be used.
|
||||
val selection = "${MediaStore.MediaColumns.DISPLAY_NAME} == ?"
|
||||
@@ -92,11 +87,17 @@ object MediaStoreUtils {
|
||||
return null
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Throws(IOException::class)
|
||||
fun getFile(displayName: String): UriFile {
|
||||
return queryFile(displayName) ?:
|
||||
/* this code path will never happen pre 29 */ insertFile(displayName)
|
||||
fun getFile(displayName: String, skipQuery: Boolean = false): 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))
|
||||
}
|
||||
|
||||
return if (skipQuery) insertFile(displayName)
|
||||
else queryFile(displayName) ?: insertFile(displayName)
|
||||
}
|
||||
|
||||
fun Uri.inputStream() = cr.openInputStream(this) ?: throw FileNotFoundException()
|
||||
|
@@ -29,6 +29,6 @@ val viewModelModules = module {
|
||||
viewModel { MainViewModel() }
|
||||
|
||||
// Legacy
|
||||
viewModel { (args: FlashFragmentArgs) -> FlashViewModel(args, get()) }
|
||||
viewModel { (args: FlashFragmentArgs) -> FlashViewModel(args) }
|
||||
viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) }
|
||||
}
|
||||
|
193
app/src/main/java/com/topjohnwu/magisk/ktx/RecyclerView.kt
Normal file
193
app/src/main/java/com/topjohnwu/magisk/ktx/RecyclerView.kt
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,9 +7,11 @@ import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
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.content.pm.ServiceInfo.FLAG_ISOLATED_PROCESS
|
||||
import android.content.pm.ServiceInfo.FLAG_USE_APP_ZYGOTE
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.database.Cursor
|
||||
@@ -57,32 +59,10 @@ import java.lang.reflect.Array as JArray
|
||||
|
||||
val packageName: String get() = get<Context>().packageName
|
||||
|
||||
val ApplicationInfo.processes: List<String> @SuppressLint("InlinedApi") get() {
|
||||
val pm = get<PackageManager>()
|
||||
val appProcessName = processName ?: packageName
|
||||
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 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()
|
||||
}
|
||||
}
|
||||
val ServiceInfo.isIsolated get() = (flags and FLAG_ISOLATED_PROCESS) != 0
|
||||
|
||||
@get:SuppressLint("InlinedApi")
|
||||
val ServiceInfo.useAppZygote get() = (flags and FLAG_USE_APP_ZYGOTE) != 0
|
||||
|
||||
fun Context.rawResource(id: Int) = resources.openRawResource(id)
|
||||
|
||||
|
@@ -10,7 +10,6 @@ import android.view.WindowManager
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.setPadding
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.navigation.NavDirections
|
||||
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.HideTopViewOnScrollBehavior
|
||||
import com.topjohnwu.magisk.utils.HideableBehavior
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
class MainViewModel : BaseViewModel()
|
||||
@@ -39,14 +38,6 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
|
||||
override val viewModel by viewModel<MainViewModel>()
|
||||
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
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -100,8 +91,6 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
|
||||
(currentFragment as? ReselectionTarget)?.onReselected()
|
||||
}
|
||||
|
||||
binding.mainNavigation.viewTreeObserver.addOnGlobalLayoutListener(navObserver)
|
||||
|
||||
val section = if (intent.action == ACTION_APPLICATION_PREFERENCES) Const.Nav.SETTINGS
|
||||
else intent.getStringExtra(Const.Key.OPEN_SECTION)
|
||||
getScreen(section)?.navigate()
|
||||
@@ -116,16 +105,11 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
binding.mainNavigation.viewTreeObserver.removeOnGlobalLayoutListener(navObserver)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> onBackPressed()
|
||||
|
@@ -32,6 +32,10 @@ class FlashFragment : BaseUIFragment<FlashViewModel, FragmentFlashMd2Binding>()
|
||||
super.onStart()
|
||||
setHasOptionsMenu(true)
|
||||
activity.setTitle(R.string.flash_screen_title)
|
||||
|
||||
viewModel.subtitle.observe(this) {
|
||||
activity.supportActionBar?.setSubtitle(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
|
@@ -1,9 +1,10 @@
|
||||
package com.topjohnwu.magisk.ui.flash
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.net.Uri
|
||||
import android.view.MenuItem
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
@@ -13,31 +14,28 @@ import com.topjohnwu.magisk.arch.itemBindingOf
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.tasks.FlashZip
|
||||
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.events.SnackbarEvent
|
||||
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.view.Notifications
|
||||
import com.topjohnwu.superuser.CallbackList
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class FlashViewModel(
|
||||
args: FlashFragmentArgs,
|
||||
private val resources: Resources
|
||||
args: FlashFragmentArgs
|
||||
) : BaseViewModel() {
|
||||
|
||||
@get:Bindable
|
||||
var showReboot = Shell.rootAccess()
|
||||
set(value) = set(value, field, { field = it }, BR.showReboot)
|
||||
|
||||
@get:Bindable
|
||||
var behaviorText = resources.getString(R.string.flashing)
|
||||
set(value) = set(value, field, { field = it }, BR.behaviorText)
|
||||
private val _subtitle = MutableLiveData(R.string.flashing)
|
||||
val subtitle get() = _subtitle as LiveData<Int>
|
||||
|
||||
val adapter = RvBindingAdapter<ConsoleItem>()
|
||||
val items = diffListOf<ConsoleItem>()
|
||||
@@ -92,9 +90,9 @@ class FlashViewModel(
|
||||
|
||||
private fun onResult(success: Boolean) {
|
||||
state = if (success) State.LOADED else State.LOADING_FAILED
|
||||
behaviorText = when {
|
||||
success -> resources.getString(R.string.done)
|
||||
else -> resources.getString(R.string.failure)
|
||||
when {
|
||||
success -> _subtitle.postValue(R.string.done)
|
||||
else -> _subtitle.postValue(R.string.failure)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,18 +104,16 @@ class FlashViewModel(
|
||||
}
|
||||
|
||||
private fun savePressed() = withExternalRW {
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val name = Const.MAGISK_INSTALL_LOG_FILENAME.format(now.toTime(timeFormatStandard))
|
||||
val file = MediaStoreUtils.getFile(name)
|
||||
file.uri.outputStream().bufferedWriter().use { writer ->
|
||||
logItems.forEach {
|
||||
writer.write(it)
|
||||
writer.newLine()
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val name = "magisk_install_log_%s.log".format(now.toTime(timeFormatStandard))
|
||||
val file = MediaStoreUtils.getFile(name, true)
|
||||
file.uri.outputStream().bufferedWriter().use { writer ->
|
||||
logItems.forEach {
|
||||
writer.write(it)
|
||||
writer.newLine()
|
||||
}
|
||||
SnackbarEvent(file.toString()).publish()
|
||||
}
|
||||
SnackbarEvent(file.toString()).publish()
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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 }
|
||||
}
|
@@ -12,6 +12,9 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseUIFragment
|
||||
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.utils.MotionRevealHelper
|
||||
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
|
||||
lama.isAutoMeasureEnabled = false
|
||||
}
|
||||
|
105
app/src/main/java/com/topjohnwu/magisk/ui/hide/HideInfo.kt
Normal file
105
app/src/main/java/com/topjohnwu/magisk/ui/hide/HideInfo.kt
Normal 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")
|
||||
}
|
@@ -12,14 +12,13 @@ import com.topjohnwu.magisk.utils.set
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class HideItem(
|
||||
app: HideAppTarget
|
||||
) : ObservableItem<HideItem>(), Comparable<HideItem> {
|
||||
class HideRvItem(
|
||||
val info: HideAppInfo
|
||||
) : 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 = app.processes.map { HideProcessItem(it) }
|
||||
val processes = info.processes.map { HideProcessRvItem(it) }
|
||||
|
||||
@get:Bindable
|
||||
var isExpanded = false
|
||||
@@ -41,11 +40,10 @@ class HideItem(
|
||||
if (value == true) {
|
||||
processes
|
||||
.filterNot { it.isHidden }
|
||||
.filter { isExpanded || it.process.name == it.process.packageName }
|
||||
.filter { isExpanded || it.defaultSelection }
|
||||
} else {
|
||||
processes
|
||||
.filter { it.isHidden }
|
||||
.filter { isExpanded || it.process.name == it.process.packageName }
|
||||
}.forEach { it.toggle() }
|
||||
}
|
||||
|
||||
@@ -69,14 +67,19 @@ class HideItem(
|
||||
else -> null
|
||||
}
|
||||
} 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 {
|
||||
private val comparator = compareBy<HideItem>(
|
||||
private val comparator = compareBy<HideRvItem>(
|
||||
{ it.itemsChecked == 0 },
|
||||
{ it.info }
|
||||
)
|
||||
@@ -84,16 +87,17 @@ class HideItem(
|
||||
|
||||
}
|
||||
|
||||
class HideProcessItem(
|
||||
class HideProcessRvItem(
|
||||
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
|
||||
var isHidden = process.isHidden
|
||||
set(value) = set(value, field, { field = it }, BR.hidden) {
|
||||
val arg = if (isHidden) "add" else "rm"
|
||||
var isHidden
|
||||
get() = process.isHidden
|
||||
set(value) = set(value, process.isHidden, { process.isHidden = it }, BR.hidden) {
|
||||
val arg = if (it) "add" else "rm"
|
||||
val (name, pkg) = process
|
||||
Shell.su("magiskhide --$arg $pkg $name").submit()
|
||||
}
|
||||
@@ -102,7 +106,10 @@ class HideProcessItem(
|
||||
isHidden = !isHidden
|
||||
}
|
||||
|
||||
override fun contentSameAs(other: HideProcessItem) = process == other.process
|
||||
override fun itemSameAs(other: HideProcessItem) = process.name == other.process.name
|
||||
val defaultSelection get() =
|
||||
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
|
||||
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.ui.hide
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||
import android.os.Process
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@@ -14,7 +15,6 @@ import com.topjohnwu.magisk.arch.itemBindingOf
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.ktx.get
|
||||
import com.topjohnwu.magisk.ktx.packageName
|
||||
import com.topjohnwu.magisk.ktx.processes
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.set
|
||||
import com.topjohnwu.superuser.Shell
|
||||
@@ -45,11 +45,11 @@ class HideViewModel : BaseViewModel(), Queryable {
|
||||
submitQuery()
|
||||
}
|
||||
|
||||
val items = filterableListOf<HideItem>()
|
||||
val itemBinding = itemBindingOf<HideItem> {
|
||||
val items = filterableListOf<HideRvItem>()
|
||||
val itemBinding = itemBindingOf<HideRvItem> {
|
||||
it.bindExtra(BR.viewModel, this)
|
||||
}
|
||||
val itemInternalBinding = itemBindingOf<HideProcessItem> {
|
||||
val itemInternalBinding = itemBindingOf<HideProcessRvItem> {
|
||||
it.bindExtra(BR.viewModel, this)
|
||||
}
|
||||
|
||||
@@ -62,14 +62,13 @@ class HideViewModel : BaseViewModel(), Queryable {
|
||||
state = State.LOADING
|
||||
val (apps, diff) = withContext(Dispatchers.Default) {
|
||||
val pm = get<PackageManager>()
|
||||
val hides = Shell.su("magiskhide --ls").exec().out.map { HideTarget(it) }
|
||||
val apps = pm.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES)
|
||||
val hideList = Shell.su("magiskhide --ls").exec().out.map { CmdlineHiddenItem(it) }
|
||||
val apps = pm.getInstalledApplications(MATCH_UNINSTALLED_PACKAGES)
|
||||
.asSequence()
|
||||
.filter { it.enabled && !blacklist.contains(it.packageName) }
|
||||
.map { HideAppInfo(it, pm) }
|
||||
.map { createTarget(it, hides) }
|
||||
.map { HideAppInfo(it, pm, hideList) }
|
||||
.filter { it.processes.isNotEmpty() }
|
||||
.map { HideItem(it) }
|
||||
.map { HideRvItem(it) }
|
||||
.toList()
|
||||
.sorted()
|
||||
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() {
|
||||
items.filter {
|
||||
fun showHidden() = it.itemsChecked != 0
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package com.topjohnwu.magisk.ui.home
|
||||
|
||||
import android.os.Build
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
@@ -68,8 +67,7 @@ class HomeViewModel(
|
||||
set(value) = set(value, field, { field = it }, BR.stateManagerProgress)
|
||||
|
||||
@get:Bindable
|
||||
val showUninstall get() =
|
||||
Info.env.magiskVersionCode > 0 && stateMagisk != MagiskState.LOADING && isConnected.get()
|
||||
val showUninstall get() = Info.env.isActive && state != State.LOADING
|
||||
|
||||
@get:Bindable
|
||||
val showSafetyNet get() = Info.hasGMS && isConnected.get()
|
||||
@@ -82,8 +80,6 @@ class HomeViewModel(
|
||||
|
||||
override fun refresh() = viewModelScope.launch {
|
||||
state = State.LOADING
|
||||
notifyPropertyChanged(BR.showUninstall)
|
||||
notifyPropertyChanged(BR.showSafetyNet)
|
||||
svc.fetchUpdate()?.apply {
|
||||
state = State.LOADED
|
||||
stateMagisk = when {
|
||||
@@ -93,7 +89,6 @@ class HomeViewModel(
|
||||
}
|
||||
|
||||
stateManager = when {
|
||||
!app.isUpdateChannelCorrect && isConnected.get() -> MagiskState.NOT_INSTALLED
|
||||
app.isObsolete -> MagiskState.OBSOLETE
|
||||
else -> MagiskState.UP_TO_DATE
|
||||
}
|
||||
@@ -107,6 +102,8 @@ class HomeViewModel(
|
||||
ensureEnv()
|
||||
}
|
||||
} ?: apply { state = State.LOADING_FAILED }
|
||||
notifyPropertyChanged(BR.showUninstall)
|
||||
notifyPropertyChanged(BR.showSafetyNet)
|
||||
}
|
||||
|
||||
val showTest = false
|
||||
@@ -127,14 +124,18 @@ class HomeViewModel(
|
||||
|
||||
fun onDeletePressed() = UninstallDialog().publish()
|
||||
|
||||
fun onManagerPressed() =
|
||||
if (isConnected.get()) ManagerInstallDialog().publish()
|
||||
else SnackbarEvent(R.string.no_connection).publish()
|
||||
fun onManagerPressed() = when (state) {
|
||||
State.LOADED -> ManagerInstallDialog().publish()
|
||||
State.LOADING -> SnackbarEvent(R.string.loading).publish()
|
||||
else -> SnackbarEvent(R.string.no_connection).publish()
|
||||
}
|
||||
|
||||
fun onMagiskPressed() = if (isConnected.get()) withExternalRW {
|
||||
HomeFragmentDirections.actionHomeFragmentToInstallFragment().publish()
|
||||
} else {
|
||||
SnackbarEvent(R.string.no_connection).publish()
|
||||
fun onMagiskPressed() = when (state) {
|
||||
State.LOADED -> withExternalRW {
|
||||
HomeFragmentDirections.actionHomeFragmentToInstallFragment().publish()
|
||||
}
|
||||
State.LOADING -> SnackbarEvent(R.string.loading).publish()
|
||||
else -> SnackbarEvent(R.string.no_connection).publish()
|
||||
}
|
||||
|
||||
fun onSafetyNetPressed() =
|
||||
@@ -150,17 +151,7 @@ class HomeViewModel(
|
||||
MagiskState.NOT_INSTALLED,
|
||||
MagiskState.LOADING
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
if (invalidStates.any { it == stateMagisk } || shownDialog) return
|
||||
|
||||
val result = Shell.su("env_check").await()
|
||||
if (!result.isSuccess) {
|
||||
@@ -171,8 +162,6 @@ class HomeViewModel(
|
||||
|
||||
private val MagiskJson.isObsolete
|
||||
get() = Info.env.isActive && Info.env.magiskVersionCode < versionCode
|
||||
private val ManagerJson.isUpdateChannelCorrect
|
||||
get() = versionCode > 0
|
||||
private val ManagerJson.isObsolete
|
||||
get() = BuildConfig.VERSION_CODE < versionCode
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}
|
@@ -9,6 +9,9 @@ import androidx.core.view.isVisible
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseUIFragment
|
||||
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.utils.MotionRevealHelper
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
@@ -42,6 +45,21 @@ class LogFragment : BaseUIFragment<LogViewModel, FragmentLogMd2Binding>() {
|
||||
binding.logFilterToggle.setOnClickListener {
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
|
@@ -3,20 +3,24 @@ package com.topjohnwu.magisk.ui.log
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||
import com.topjohnwu.magisk.arch.diffListOf
|
||||
import com.topjohnwu.magisk.arch.itemBindingOf
|
||||
import com.topjohnwu.magisk.data.repository.LogRepository
|
||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
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.view.TextItem
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
||||
class LogViewModel(
|
||||
private val repo: LogRepository
|
||||
@@ -54,14 +58,23 @@ class LogViewModel(
|
||||
|
||||
fun saveMagiskLog() = withExternalRW {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val now = Calendar.getInstance()
|
||||
val filename = "magisk_log_%04d%02d%02d_%02d%02d%02d.log".format(
|
||||
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND)
|
||||
)
|
||||
val logFile = MediaStoreUtils.getFile(filename)
|
||||
logFile.uri.outputStream().writer().use { it.write(consoleText) }
|
||||
val filename = "magisk_log_%s.log".format(now.toTime(timeFormatStandard))
|
||||
val logFile = MediaStoreUtils.getFile(filename, true)
|
||||
logFile.uri.outputStream().bufferedWriter().use { file ->
|
||||
file.write("---System Properties---\n\n")
|
||||
|
||||
ProcessBuilder("getprop").start()
|
||||
.inputStream.reader().use { it.copyTo(file) }
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ import com.topjohnwu.magisk.arch.ReselectionTarget
|
||||
import com.topjohnwu.magisk.arch.ViewEvent
|
||||
import com.topjohnwu.magisk.core.download.BaseDownloader
|
||||
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.utils.EndlessRecyclerScrollListener
|
||||
import com.topjohnwu.magisk.utils.MotionRevealHelper
|
||||
@@ -62,6 +62,40 @@ class ModuleFragment : BaseUIFragment<ModuleViewModel, FragmentModuleMd2Binding>
|
||||
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() {
|
||||
|
@@ -158,7 +158,7 @@ sealed class BaseSettingsItem : ObservableItem<BaseSettingsItem>() {
|
||||
runCatching { getStringArray(id) }.getOrDefault(emptyArray())
|
||||
|
||||
override fun onPressed(view: View, callback: Callback) {
|
||||
if (entries.isEmpty() || entryValues.isEmpty()) return
|
||||
if (entries.isEmpty()) return
|
||||
super.onPressed(view, callback)
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,9 @@ import android.view.View
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseUIFragment
|
||||
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 org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
@@ -24,6 +27,21 @@ class SettingsFragment : BaseUIFragment<SettingsViewModel, FragmentSettingsMd2Bi
|
||||
binding.settingsList.setOnViewReadyListener {
|
||||
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() {
|
||||
|
@@ -20,6 +20,7 @@ import com.topjohnwu.magisk.databinding.DialogSettingsAppNameBinding
|
||||
import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding
|
||||
import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
|
||||
import com.topjohnwu.magisk.ktx.get
|
||||
import com.topjohnwu.magisk.utils.TransitiveText
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.asTransitive
|
||||
import com.topjohnwu.magisk.utils.set
|
||||
@@ -143,11 +144,12 @@ object UpdateChannel : BaseSettingsItem.Selector() {
|
||||
set(value) = setV(value, field, { field = it }) { Config.updateChannel = it }
|
||||
|
||||
override val title = R.string.settings_update_channel_title.asTransitive()
|
||||
override val entries
|
||||
get() = resources.getStringArray(R.array.update_channel).let {
|
||||
if (BuildConfig.DEBUG) it.toMutableList().apply { add("Canary") }.toTypedArray() else it
|
||||
}
|
||||
override val entryValRes = R.array.value_array
|
||||
override val entries: Array<String> = resources.getStringArray(R.array.update_channel).let {
|
||||
if (BuildConfig.DEBUG) it.toMutableList().apply { add("Canary") }.toTypedArray() else it
|
||||
}
|
||||
override val description
|
||||
get() = entries.getOrNull(value)?.asTransitive()
|
||||
?: TransitiveText.String(if (value == -1) entries[0] else "Canary")
|
||||
}
|
||||
|
||||
object UpdateChannelUrl : BaseSettingsItem.Input() {
|
||||
@@ -256,22 +258,20 @@ object Superuser : BaseSettingsItem.Section() {
|
||||
object AccessMode : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.superuser_access.asTransitive()
|
||||
override val entryRes = R.array.su_access
|
||||
override val entryValRes = R.array.value_array
|
||||
|
||||
override var value = Config.rootMode
|
||||
set(value) = setV(value, field, { field = it }) {
|
||||
Config.rootMode = entryValues[it].toInt()
|
||||
Config.rootMode = it
|
||||
}
|
||||
}
|
||||
|
||||
object MultiuserMode : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.multiuser_mode.asTransitive()
|
||||
override val entryRes = R.array.multiuser_mode
|
||||
override val entryValRes = R.array.value_array
|
||||
|
||||
override var value = Config.suMultiuserMode
|
||||
set(value) = setV(value, field, { field = it }) {
|
||||
Config.suMultiuserMode = entryValues[it].toInt()
|
||||
Config.suMultiuserMode = it
|
||||
}
|
||||
|
||||
override val description
|
||||
@@ -285,11 +285,10 @@ object MultiuserMode : BaseSettingsItem.Selector() {
|
||||
object MountNamespaceMode : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.mount_namespace_mode.asTransitive()
|
||||
override val entryRes = R.array.namespace
|
||||
override val entryValRes = R.array.value_array
|
||||
|
||||
override var value = Config.suMntNamespaceMode
|
||||
set(value) = setV(value, field, { field = it }) {
|
||||
Config.suMntNamespaceMode = entryValues[it].toInt()
|
||||
Config.suMntNamespaceMode = it
|
||||
}
|
||||
|
||||
override val description
|
||||
@@ -299,11 +298,10 @@ object MountNamespaceMode : BaseSettingsItem.Selector() {
|
||||
object AutomaticResponse : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.auto_response.asTransitive()
|
||||
override val entryRes = R.array.auto_response
|
||||
override val entryValRes = R.array.value_array
|
||||
|
||||
override var value = Config.suAutoResponse
|
||||
set(value) = setV(value, field, { field = it }) {
|
||||
Config.suAutoResponse = entryValues[it].toInt()
|
||||
Config.suAutoResponse = it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,10 +322,9 @@ object RequestTimeout : BaseSettingsItem.Selector() {
|
||||
object SUNotification : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.superuser_notification.asTransitive()
|
||||
override val entryRes = R.array.su_notification
|
||||
override val entryValRes = R.array.value_array
|
||||
|
||||
override var value = Config.suNotification
|
||||
set(value) = setV(value, field, { field = it }) {
|
||||
Config.suNotification = entryValues[it].toInt()
|
||||
Config.suNotification = it
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,13 @@
|
||||
package com.topjohnwu.magisk.ui.superuser
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseUIFragment
|
||||
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
|
||||
|
||||
class SuperuserFragment : BaseUIFragment<SuperuserViewModel, FragmentSuperuserMd2Binding>() {
|
||||
@@ -15,6 +20,25 @@ class SuperuserFragment : BaseUIFragment<SuperuserViewModel, FragmentSuperuserMd
|
||||
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) {}
|
||||
|
||||
}
|
||||
|
@@ -2,25 +2,24 @@ package com.topjohnwu.magisk.view
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.InsetDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatDialog
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.databinding.PropertyChangeRegistry
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
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.R
|
||||
import com.topjohnwu.magisk.arch.itemBindingOf
|
||||
@@ -47,36 +46,22 @@ class MagiskDialog(
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
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 {
|
||||
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
setLayout(
|
||||
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
|
||||
setBackgroundDrawable(InsetDrawable(materialShapeDrawable, inset, inset, inset, inset))
|
||||
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setCancelable(flag: Boolean) {
|
||||
val listener = if (!flag) {
|
||||
null
|
||||
} else {
|
||||
setCanceledOnTouchOutside(true)
|
||||
View.OnClickListener { dismiss() }
|
||||
}
|
||||
binding.dialogBaseOutsideContainer.setOnClickListener(listener)
|
||||
}
|
||||
|
||||
inner class Data: ObservableHost {
|
||||
inner class Data : ObservableHost {
|
||||
override var callbacks: PropertyChangeRegistry? = null
|
||||
|
||||
@get:Bindable
|
||||
@@ -88,7 +73,7 @@ class MagiskDialog(
|
||||
set(value) = set(value, field, { field = it }, BR.title)
|
||||
|
||||
@get:Bindable
|
||||
var message : CharSequence = ""
|
||||
var message: CharSequence = ""
|
||||
set(value) = set(value, field, { field = it }, BR.message)
|
||||
|
||||
val buttonPositive = Button()
|
||||
@@ -101,7 +86,7 @@ class MagiskDialog(
|
||||
POSITIVE, NEUTRAL, NEGATIVE, IDGAF
|
||||
}
|
||||
|
||||
inner class Button: ObservableHost {
|
||||
inner class Button : ObservableHost {
|
||||
override var callbacks: PropertyChangeRegistry? = null
|
||||
|
||||
@get:Bindable
|
||||
|
@@ -1,5 +1,8 @@
|
||||
package com.topjohnwu.signing;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1Encodable;
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
@@ -14,6 +17,7 @@ import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -84,8 +88,10 @@ public class SignBoot {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean doSignature(String target, InputStream imgIn, OutputStream imgOut,
|
||||
InputStream cert, InputStream key) {
|
||||
public static boolean doSignature(
|
||||
@Nullable X509Certificate cert, @Nullable PrivateKey key,
|
||||
@NonNull InputStream imgIn, @NonNull OutputStream imgOut, @NonNull String target
|
||||
) {
|
||||
try {
|
||||
PushBackRWStream in = new PushBackRWStream(imgIn, imgOut);
|
||||
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
|
||||
@@ -96,16 +102,16 @@ public class SignBoot {
|
||||
in.unread(hdr);
|
||||
BootSignature bootsig = new BootSignature(target, signableSize);
|
||||
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(certificate);
|
||||
bootsig.setCertificate(cert);
|
||||
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(privateKey, in, signableSize);
|
||||
bootsig.setSignature(sig, CryptoUtils.getSignatureAlgorithmIdentifier(privateKey));
|
||||
byte[] sig = bootsig.sign(key, in, signableSize);
|
||||
bootsig.setSignature(sig, CryptoUtils.getSignatureAlgorithmIdentifier(key));
|
||||
byte[] encoded_bootsig = bootsig.getEncoded();
|
||||
imgOut.write(encoded_bootsig);
|
||||
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 {
|
||||
// Read the header for size
|
||||
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
|
||||
@@ -142,8 +148,8 @@ public class SignBoot {
|
||||
}
|
||||
|
||||
BootSignature bootsig = new BootSignature(signature);
|
||||
if (certIn != null) {
|
||||
bootsig.setCertificate(CryptoUtils.readCertificate(certIn));
|
||||
if (cert != null) {
|
||||
bootsig.setCertificate(cert);
|
||||
}
|
||||
if (bootsig.verify(rawImg, signableSize)) {
|
||||
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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -17,8 +17,9 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@{viewModel.insets.left}"
|
||||
android:paddingRight="@{viewModel.insets.right}"
|
||||
app:consumeSystemWindowsInsets="start|end"
|
||||
app:edgeToEdge="true"
|
||||
app:fitsSystemWindowsInsets="start|end"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
@@ -34,7 +35,7 @@
|
||||
style="@style/WidgetFoundation.Appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@{viewModel.insets.top}">
|
||||
app:fitsSystemWindowsInsets="top">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/main_toolbar"
|
||||
@@ -72,7 +73,9 @@
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:layout_marginStart="@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">
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
@@ -81,6 +84,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:textStyle="bold"
|
||||
android:fitsSystemWindows="false"
|
||||
android:paddingBottom="0dp"
|
||||
app:fitsSystemWindowsInsets="start|end"
|
||||
app:elevation="0dp"
|
||||
app:itemHorizontalTranslationEnabled="false"
|
||||
app:itemIconTint="@color/color_menu_tint"
|
||||
|
@@ -12,219 +12,185 @@
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/dialog_base_outside_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:layout_width="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="0dp"
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/dialog_base_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_begin="16dp" />
|
||||
|
||||
<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_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_max="400dp">
|
||||
tools:src="@drawable/ic_delete_md2" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="@style/WidgetFoundation.Card.Elevated"
|
||||
<TextView
|
||||
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_height="wrap_content"
|
||||
android:focusable="false"
|
||||
app:cardElevation="@dimen/margin_generic"
|
||||
app:cardUseCompatPadding="true">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<TextView
|
||||
android:id="@+id/dialog_base_message"
|
||||
gone="@{data.message.length == 0}"
|
||||
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
|
||||
android:id="@+id/dialog_base_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_begin="16dp" />
|
||||
<FrameLayout
|
||||
android:id="@+id/dialog_base_container"
|
||||
gone="@{data.message.length != 0}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<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" />
|
||||
</FrameLayout>
|
||||
|
||||
<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_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_delete_md2" />
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<TextView
|
||||
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" />
|
||||
<Space
|
||||
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.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">
|
||||
<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">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<Button
|
||||
android:id="@+id/dialog_base_button_4"
|
||||
style="@style/WidgetFoundation.Button.Text"
|
||||
gone="@{data.buttonIDGAF.icon == 0 && 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
|
||||
android:id="@+id/dialog_base_message"
|
||||
gone="@{data.message.length == 0}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@{data.message}"
|
||||
android:textAppearance="@style/AppearanceFoundation.Body"
|
||||
tools:lines="3"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
<Button
|
||||
android:id="@+id/dialog_base_button_2"
|
||||
style="@style/WidgetFoundation.Button.Text"
|
||||
gone="@{data.buttonNeutral.icon == 0 && 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: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
|
||||
android:id="@+id/dialog_base_container"
|
||||
gone="@{data.message.length != 0}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<Space
|
||||
android:id="@+id/spacer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
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 && 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 && 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
|
||||
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 && 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 && 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 && 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 && 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.appcompat.widget.ButtonBarLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</layout>
|
||||
|
@@ -18,7 +18,8 @@
|
||||
<HorizontalScrollView
|
||||
android:layout_width="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">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
@@ -31,9 +32,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@{viewModel.insets.left}"
|
||||
android:paddingRight="@{viewModel.insets.right}"
|
||||
android:paddingBottom="@{viewModel.insets.bottom}"
|
||||
app:fitsSystemWindowsInsets="start|end|bottom"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:listitem="@layout/item_console_md2" />
|
||||
@@ -46,39 +45,17 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="@dimen/l1"
|
||||
android:layout_marginBottom="@{(int) @dimen/l1 + viewModel.insets.bottom}"
|
||||
android:layout_marginBottom="@dimen/l1"
|
||||
android:onClick="@{() -> viewModel.restartPressed()}"
|
||||
android:text="@string/reboot"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="?colorOnPrimary"
|
||||
android:textStyle="bold"
|
||||
app:layout_fitsSystemWindowsInsets="bottom"
|
||||
app:backgroundTint="?colorPrimary"
|
||||
app:icon="@drawable/ic_restart"
|
||||
app:iconTint="?colorOnPrimary" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="@style/WidgetFoundation.Card.Elevated"
|
||||
goneUnless="@{viewModel.loading}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
app:contentPadding="@dimen/l1">
|
||||
|
||||
<TextView
|
||||
movieBehavior="@{viewModel.loading}"
|
||||
movieBehaviorText="@{viewModel.behaviorText}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:textAppearance="@style/AppearanceFoundation.Body"
|
||||
android:textColor="?colorOnSurface"
|
||||
android:textStyle="bold"
|
||||
tools:text="Flashing..." />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</layout>
|
||||
|
@@ -17,7 +17,6 @@
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/hide_content"
|
||||
dividerVertical="@{@drawable/divider_l_50}"
|
||||
invisibleUnless="@{viewModel.loaded || !viewModel.items.empty}"
|
||||
itemBinding="@{viewModel.itemBinding}"
|
||||
items="@{viewModel.items}"
|
||||
@@ -25,10 +24,8 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/l1"
|
||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}"
|
||||
android:paddingEnd="@dimen/l1"
|
||||
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}"
|
||||
android:paddingTop="@dimen/internal_action_bar_size"
|
||||
app:fitsSystemWindowsInsets="top|bottom"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_hide_md2"
|
||||
tools:paddingTop="40dp" />
|
||||
@@ -41,8 +38,9 @@
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginStart="@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:layout_fitsSystemWindowsInsets="bottom"
|
||||
app:srcCompat="@drawable/ic_search_md2"
|
||||
app:tint="?colorPrimary"
|
||||
tools:layout_marginBottom="64dp" />
|
||||
|
@@ -22,8 +22,9 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
||||
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l3}"
|
||||
android:paddingTop="@dimen/internal_action_bar_size"
|
||||
android:paddingBottom="@dimen/l3"
|
||||
app:fitsSystemWindowsInsets="top|bottom"
|
||||
tools:layout_marginTop="24dp">
|
||||
|
||||
<LinearLayout
|
||||
|
@@ -20,8 +20,9 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
||||
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l2}"
|
||||
android:paddingTop="@dimen/internal_action_bar_size"
|
||||
android:paddingBottom="@dimen/l2"
|
||||
app:fitsSystemWindowsInsets="top|bottom"
|
||||
tools:paddingTop="24dp">
|
||||
|
||||
<FrameLayout
|
||||
@@ -34,7 +35,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/l1">
|
||||
android:paddingTop="@dimen/l_50">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="@style/WidgetFoundation.Card"
|
||||
|
@@ -29,7 +29,8 @@
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginStart="@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:srcCompat="@drawable/ic_folder_list"
|
||||
app:tint="?colorPrimary"
|
||||
|
@@ -31,8 +31,6 @@
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/module_list"
|
||||
adapter="@{viewModel.adapter}"
|
||||
dividerHorizontal="@{@drawable/divider_l1}"
|
||||
dividerVertical="@{@drawable/divider_l_50}"
|
||||
gone="@{viewModel.loading && viewModel.items.empty}"
|
||||
itemBinding="@{viewModel.itemBinding}"
|
||||
items="@{viewModel.items}"
|
||||
@@ -40,10 +38,8 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/l1"
|
||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}"
|
||||
android:paddingEnd="0dp"
|
||||
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}"
|
||||
android:paddingTop="@dimen/internal_action_bar_size"
|
||||
app:fitsSystemWindowsInsets="top|bottom"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_module_md2" />
|
||||
|
||||
@@ -54,7 +50,8 @@
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginStart="@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:srcCompat="@drawable/ic_search_md2"
|
||||
app:tint="?colorPrimary"
|
||||
|
@@ -22,8 +22,8 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
||||
android:paddingBottom="@{viewModel.insets.bottom}"
|
||||
android:paddingTop="@dimen/internal_action_bar_size"
|
||||
app:fitsSystemWindowsInsets="top|bottom"
|
||||
tools:paddingBottom="48dp"
|
||||
tools:paddingTop="24dp">
|
||||
|
||||
|
@@ -15,8 +15,6 @@
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
adapter="@{viewModel.adapter}"
|
||||
dividerHorizontal="@{@drawable/divider_l_50}"
|
||||
dividerVertical="@{@drawable/divider_l_50}"
|
||||
itemBinding="@{viewModel.itemBinding}"
|
||||
items="@{viewModel.items}"
|
||||
android:id="@+id/settings_list"
|
||||
@@ -25,10 +23,8 @@
|
||||
android:focusableInTouchMode="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/l1"
|
||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
||||
android:paddingEnd="@dimen/l_50"
|
||||
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l1}"
|
||||
android:paddingTop="@dimen/internal_action_bar_size"
|
||||
app:fitsSystemWindowsInsets="top|bottom"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:layout_marginTop="24dp"
|
||||
tools:listitem="@layout/item_settings"
|
||||
|
@@ -20,8 +20,6 @@
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/superuser_list"
|
||||
adapter="@{viewModel.adapter}"
|
||||
dividerHorizontal="@{@drawable/divider_l1}"
|
||||
dividerVertical="@{@drawable/divider_l_50}"
|
||||
goneUnless="@{viewModel.loaded || !viewModel.items.empty}"
|
||||
itemBinding="@{viewModel.itemBinding}"
|
||||
items="@{viewModel.items}"
|
||||
@@ -29,9 +27,8 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/l1"
|
||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}"
|
||||
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l2}"
|
||||
android:paddingTop="@dimen/internal_action_bar_size"
|
||||
app:fitsSystemWindowsInsets="top|bottom"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_policy_md2" />
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<?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>
|
||||
|
||||
@@ -17,15 +18,17 @@
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
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:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l1}">
|
||||
android:paddingBottom="@dimen/l1"
|
||||
app:fitsSystemWindowsInsets="top|bottom">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/theme_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/l1"
|
||||
android:useDefaultMargins="true">
|
||||
|
||||
<include
|
||||
|
@@ -21,7 +21,8 @@
|
||||
android:paddingStart="@dimen/l1"
|
||||
android:paddingTop="@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:paddingBottom="64dp">
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
@@ -32,8 +33,8 @@
|
||||
precomputedText="@{viewModel.consoleText}"
|
||||
android:textAppearance="@style/AppearanceFoundation.Caption"
|
||||
android:textSize="10sp"
|
||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
||||
android:paddingBottom="@{viewModel.insets.bottom}"
|
||||
android:paddingTop="@dimen/internal_action_bar_size"
|
||||
app:layout_fitsSystemWindowsInsets="top|bottom"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
@@ -16,16 +16,15 @@
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/log_superuser"
|
||||
itemBinding="@{viewModel.itemBinding}"
|
||||
items="@{viewModel.items}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/l1"
|
||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
||||
android:paddingEnd="@dimen/l1"
|
||||
android:paddingBottom="@{viewModel.insets.bottom}"
|
||||
android:paddingTop="@dimen/internal_action_bar_size"
|
||||
app:fitsSystemWindowsInsets="top|bottom"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_log_access_md2"
|
||||
tools:paddingTop="24dp" />
|
||||
|
@@ -18,14 +18,13 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l1}"
|
||||
android:paddingBottom="@dimen/l1"
|
||||
app:fitsSystemWindowsInsets="bottom"
|
||||
tools:layout_gravity="bottom"
|
||||
tools:paddingBottom="64dp">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/module_filter_list"
|
||||
dividerHorizontal="@{@drawable/divider_l1}"
|
||||
dividerVertical="@{@drawable/divider_l_50}"
|
||||
itemBinding="@{viewModel.itemSearchBinding}"
|
||||
items="@{viewModel.itemsSearch}"
|
||||
android:layout_width="match_parent"
|
||||
@@ -33,8 +32,8 @@
|
||||
android:layout_marginBottom="@dimen/l1"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
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"
|
||||
app:fitsSystemWindowsInsets="top"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/module_filter_title_search"
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.topjohnwu.magisk.ui.hide.HideItem" />
|
||||
type="com.topjohnwu.magisk.ui.hide.HideRvItem" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.topjohnwu.magisk.ui.hide.HideProcessItem" />
|
||||
type="com.topjohnwu.magisk.ui.hide.HideProcessRvItem" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
|
@@ -1,5 +1,8 @@
|
||||
## v8.0.3
|
||||
## v8.0.6
|
||||
|
||||
- Switch to the new Magisk Module Repo setup in preparation to allow 3rd party repos
|
||||
- Add tapjacking protection on Superuser request dialog
|
||||
- Stability changes and bug fixes
|
||||
- Minor UI changes
|
||||
- Update internal scripts
|
||||
|
||||
## v8.0.5
|
||||
|
||||
- Fix sepolicy rule copying
|
||||
|
@@ -30,10 +30,16 @@ direct_install() {
|
||||
rm -f $MAGISKBIN/new-boot.img
|
||||
echo "- Flashing new boot image"
|
||||
flash_image $1/new-boot.img $2
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "! Insufficient partition size"
|
||||
return 1
|
||||
fi
|
||||
case $? in
|
||||
1)
|
||||
echo "! Insufficient partition size"
|
||||
return 1
|
||||
;;
|
||||
2)
|
||||
echo "! $2 is read only"
|
||||
return 2
|
||||
;;
|
||||
esac
|
||||
rm -rf $1
|
||||
return 0
|
||||
}
|
||||
|
@@ -6,8 +6,8 @@
|
||||
<string name="logs">Журналы</string>
|
||||
<string name="settings">Налады</string>
|
||||
<string name="refresh">Абнавіць даныя</string>
|
||||
<string name="install">Усталяваць</string>
|
||||
<string name="section_home">На хатнюю старонку</string>
|
||||
<string name="install">Усталёўка</string>
|
||||
<string name="section_home">Хатняя старонка</string>
|
||||
<string name="section_theme">Тэмы</string>
|
||||
<string name="safetynet">SafetyNet</string>
|
||||
<!--Home-->
|
||||
@@ -16,7 +16,7 @@
|
||||
<string name="manager">Кіраўнік</string>
|
||||
<string name="loading">Загрузка…</string>
|
||||
<string name="update">Абнавіць</string>
|
||||
<string name="not_available">Н/Д</string>
|
||||
<string name="not_available">Не</string>
|
||||
<string name="hide">Схаваць</string>
|
||||
<string name="status">Статус</string>
|
||||
<string name="home_package">Пакунак</string>
|
||||
@@ -26,7 +26,7 @@
|
||||
<string name="home_support_content">Magisk ёсць і заўсёды будзе бясплатным праектам з адкрытым зыходным кодам. Але вы заўсёды можаце ахвяраваць нам на распрацоўку.</string>
|
||||
<string name="home_status_normal">Звычайны</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="invalid_update_channel">Хібны канал абнаўлення</string>
|
||||
<string name="uninstall_magisk_title">Выдаліць Magisk</string>
|
||||
|
@@ -1,169 +1,247 @@
|
||||
<resources>
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="modules">Moduly</string>
|
||||
<string name="superuser">Superuser</string>
|
||||
<string name="logs">Log</string>
|
||||
<!--Sections-->
|
||||
<string name="modules">Správce modulů</string>
|
||||
<string name="superuser">SuperUser</string>
|
||||
<string name="logs">Protokol</string>
|
||||
<string name="settings">Nastavení</string>
|
||||
<string name="refresh">Obnovit lokální data</string>
|
||||
<string name="install">Instalovat</string>
|
||||
<string name="unsupport_magisk_title">Nepodporovaná verze Magisk</string>
|
||||
<string name="section_home">Domů</string>
|
||||
<string name="section_theme">Téma</string>
|
||||
<string name="safetynet">SafetyNet</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="invalid_update_channel">Neplatný kanál aktualizace</string>
|
||||
<string name="safetynet_api_error">Chyba SafetyNet API</string>
|
||||
<string name="safetynet_res_invalid">Odpověď je neplatná.</string>
|
||||
<string name="keep_force_encryption">Udržet "force encryption"</string>
|
||||
<string name="keep_dm_verity">Udržet "AVB 2.0/dm-verity"</string>
|
||||
<string name="uninstall_magisk_title">Odinstalovat Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Všechny moduly budou zakázány/odstraněny. Root bude odstraněn a pokud jsou data dešifrována, můžou být zašifrována.</string>
|
||||
<string name="update">Aktualizovat</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Žádné informace)</string>
|
||||
<string name="reboot_recovery">Restartovat do Recovery</string>
|
||||
<string name="reboot_bootloader">Restartovat do Bootloaderu</string>
|
||||
<string name="reboot_download">Restartovat do Download</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Dostupná aktualizace</string>
|
||||
<string name="home_installed_version">Nainstalováno</string>
|
||||
<string name="sorting_order">Pořadí řazení</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveLog">Uložit log</string>
|
||||
<string name="menuClearLog">Smazat log</string>
|
||||
<string name="logs_cleared">Log byl smazán.</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<!--Home-->
|
||||
<string name="no_connection">Žádné připojení</string>
|
||||
<string name="app_changelog">Seznam změn</string>
|
||||
<string name="manager">Správce</string>
|
||||
<string name="loading">Načítání…</string>
|
||||
<string name="update">Aktualizovat</string>
|
||||
<string name="not_available">N/A</string>
|
||||
<string name="hide">Skrýt</string>
|
||||
<string name="status">Stav</string>
|
||||
<string name="home_package">Balíček</string>
|
||||
|
||||
<!-- System Components, Notifications -->
|
||||
<string name="update_channel">Aktualizace Magisk</string>
|
||||
<string name="progress_channel">Oznámení o průběhu</string>
|
||||
<string name="download_complete">Stahování dokončeno</string>
|
||||
<string name="download_file_error">Chyba při stahování souboru</string>
|
||||
<string name="magisk_update_title">Aktualizace Magisk je dostupná!</string>
|
||||
<string name="manager_update_title">Aktualizace Magisk Manager je dostupná!</string>
|
||||
<string name="home_notice_content">Zkontrolujte, zda používáte Magisk Manager s otevřeným kódem. Správce z neznámého zdroje může provádět nebezpečné akce!</string>
|
||||
<string name="home_support_title">Podpořte nás</string>
|
||||
<string name="home_item_source">Zdroj</string>
|
||||
<string name="home_support_content">Magisk je a vždy bude svobodný s otevřeným kódem. Můžete nám však zaslat malý dar jako poděkování.</string>
|
||||
<string name="home_status_normal">Normální</string>
|
||||
<string name="home_status_stub">Testovací</string>
|
||||
<string name="home_installed_version">Nainstalovaná</string>
|
||||
<string name="home_latest_version">Poslední</string>
|
||||
<string name="invalid_update_channel">Neplatný kanál aktualizace</string>
|
||||
<string name="uninstall_magisk_title">Odinstalovat Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Všechny moduly budou zakázány/odstraněny!\nROOT bude odstraněn!\nPokud jsou data dešifrována, můžou být zašifrována!</string>
|
||||
<string name="home_check_safetynet">Zkontrolovat SafetyNet</string>
|
||||
|
||||
<!-- Installation -->
|
||||
<string name="manager_download_install">Stiskněte pro stažení a instalaci.</string>
|
||||
<string name="download_zip_only">Stáhnout pouze zip</string>
|
||||
<!--Install-->
|
||||
<string name="keep_force_encryption">Ponechat Force Encryption</string>
|
||||
<string name="keep_dm_verity">Ponechat AVB 2.0/DM-Verity</string>
|
||||
<string name="recovery_mode">Režim Recovery</string>
|
||||
<string name="install_options_title">Možnosti</string>
|
||||
<string name="install_method_title">Způsob</string>
|
||||
<string name="install_next">Další</string>
|
||||
<string name="install_start">Spustit</string>
|
||||
<string name="manager_download_install">Stiskněte pro stažení a instalaci</string>
|
||||
<string name="download_zip_only">Stáhnout pouze soubor ZIP</string>
|
||||
<string name="direct_install">Přímá instalace (doporučeno)</string>
|
||||
<string name="install_inactive_slot">Instalace do druhého slotu (po OTA)</string>
|
||||
<string name="install_inactive_slot_msg">Vaše zařízení bude po restartu VYNUCENĚ spuštěno do aktuálního neaktivního slotu!\nTuto možnost použijte pouze po dokončení OTA.\nPokračovat?</string>
|
||||
<string name="install_inactive_slot_msg">Vaše zařízení bude po restartu VYNUCENĚ spuštěno do aktuálního neaktivního slotu!\nTuto možnost použijte pouze po dokončení OTA.\nChcete pokračovat?</string>
|
||||
<string name="setup_title">Další nastavení</string>
|
||||
<string name="select_patch_file">Vybrat a opravit soubor</string>
|
||||
<string name="patch_file_msg">Vyberte obraz raw (*.img) nebo soubor tar pro ODIN (*.tar)</string>
|
||||
<string name="patch_file_msg">Vyberte soubor RAW (*.img) nebo soubor TAR pro ODIN (*.tar)</string>
|
||||
<string name="reboot_delay_toast">Restartování za 5 sekund…</string>
|
||||
<string name="flash_screen_title">Instalace</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="repo_install_title">Instalovat %1$s</string>
|
||||
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
|
||||
<string name="download">Stáhnout</string>
|
||||
<string name="reboot">Restartovat</string>
|
||||
<string name="release_notes">Poznámky k vydání</string>
|
||||
<string name="repo_cache_cleared">Mezipaměť smazána</string>
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Požadavek SuperUser</string>
|
||||
<string name="touch_filtered_warning">Protože aplikace zavírá požadavek SuperUser, Magisk nemůže ověřit Vaši odpověď</string>
|
||||
<string name="deny">Zakázat</string>
|
||||
<string name="prompt">Zeptat se</string>
|
||||
<string name="grant">Povolit</string>
|
||||
<string name="su_warning">Povolí plný přístup k Vašemu zařízení.\nZakažte, pokud si nejste jisti!</string>
|
||||
<string name="forever">Trvale</string>
|
||||
<string name="once">Jednou</string>
|
||||
<string name="tenmin">10 minut</string>
|
||||
<string name="twentymin">20 minut</string>
|
||||
<string name="thirtymin">30 minut</string>
|
||||
<string name="sixtymin">60 minut</string>
|
||||
<string name="su_allow_toast">Pro %1$s bylo oprávnění SuperUser povoleno</string>
|
||||
<string name="su_deny_toast">Pro %1$s bylo oprávnění SuperUser zakázáno</string>
|
||||
<string name="su_snack_grant">SuperUser oprávnění pro %1$s je povoleno</string>
|
||||
<string name="su_snack_deny">SuperUser oprávnění pro %1$s je zakázáno</string>
|
||||
<string name="su_snack_notif_on">Oznámení pro %1$s jsou povolena</string>
|
||||
<string name="su_snack_notif_off">Oznámení pro %1$s jsou zakázána</string>
|
||||
<string name="su_snack_log_on">Protokolování %1$s je povoleno</string>
|
||||
<string name="su_snack_log_off">Protokolování %1$s je zakázáno</string>
|
||||
<string name="su_revoke_title">Smazat?</string>
|
||||
<string name="su_revoke_msg">Chcete smazat protokol k oprávnění pro %1$s?</string>
|
||||
<string name="toast">Text</string>
|
||||
<string name="none">Žádné</string>
|
||||
|
||||
<string name="flashing">Instalování</string>
|
||||
<string name="hide_manager_title">Skrytí Magisk Manageru…</string>
|
||||
<string name="hide_manager_fail_toast">Skrytí Magisk Manageru selhalo.</string>
|
||||
<string name="open_link_failed_toast">Nebyla nalezena žádná aplikace pro otevření odkazu.</string>
|
||||
<string name="complete_uninstall">Dokončete odinstalaci</string>
|
||||
<string name="restore_img">Obnovit obrazy</string>
|
||||
<string name="restore_img_msg">Obnovování…</string>
|
||||
<string name="restore_done">Obnovení bylo provedeno!</string>
|
||||
<string name="restore_fail">Výchozí záloha neexistuje!</string>
|
||||
<string name="proprietary_title">Stáhnout proprietární kód</string>
|
||||
<string name="proprietary_notice">Magisk Manager je FOSS a neobsahuje proprietární kód SafetyNet API společnosti Google.\n\nChcete povolit aplikaci Magisk Manager stažení rozšíření (obsahuje GoogleApiClient) pro kontrolu SafetyNet?</string>
|
||||
<string name="setup_fail">Nastavení selhalo.</string>
|
||||
<string name="env_fix_title">Vyžaduje se další nastavení</string>
|
||||
<string name="env_fix_msg">Vaše zařízení potřebuje další nastavení, aby Magisk fungoval správně. Stáhne se instalační zip Magisk, chcete pokračovat?</string>
|
||||
<string name="setup_msg">Nastavení je spuštěno…</string>
|
||||
<string name="superuser_toggle_notification">Oznámení</string>
|
||||
<string name="superuser_toggle_revoke">Smazat</string>
|
||||
<string name="superuser_policy_none">Žádná aplikace nepožádala o oprávnění SuperUser.</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_clear_cache_title">Smazat uchovanou mezipaměť</string>
|
||||
<string name="settings_clear_cache_summary">Smaže informace online použití v mezipaměti, donutí aplikaci obnovit informace online.</string>
|
||||
<!--Logs-->
|
||||
<string name="log_data_none">Žádné protokoly. Vyzkoušejte nějakou aplikaci vyžadující oprávnění SuperUser.</string>
|
||||
<string name="log_data_magisk_none">Protokoly Magisk jsou prázdné. To je zvláštní!</string>
|
||||
<string name="menuSaveLog">Uložit protokol</string>
|
||||
<string name="menuClearLog">Smazat protokol</string>
|
||||
<string name="logs_cleared">Protokol byl smazán</string>
|
||||
<string name="pid">PID:%1$d</string>
|
||||
<string name="target_uid">Cílové UID: %1$d</string>
|
||||
|
||||
<!--SafetyNet-->
|
||||
<string name="safetynet_api_error">Chyba SafetyNet API</string>
|
||||
<string name="safetynet_res_invalid">Odpověď je neplatná</string>
|
||||
<string name="safetynet_attest_success">Úspěšné!</string>
|
||||
<string name="safetynet_attest_failure">Chyba ověření!</string>
|
||||
<string name="safetynet_attest_loading">Čekejte…</string>
|
||||
<string name="safetynet_attest_restart">Zkusit znovu</string>
|
||||
|
||||
<!--MagiskHide-->
|
||||
<string name="show_system_app">Zobrazit systémové aplikace</string>
|
||||
<string name="show_os_app">Zobrazit OS aplikace</string>
|
||||
<string name="hide_filter_hint">Filtrovat podle názvu</string>
|
||||
<string name="hide_scroll_up">Posunout nahoru</string>
|
||||
<string name="hide_filters">Filtry</string>
|
||||
<string name="hide_search">Vyhledávání</string>
|
||||
|
||||
<!--Module-->
|
||||
<string name="no_info_provided">(žádné informace)</string>
|
||||
<string name="reboot_userspace">Restartovat do UserSpace</string>
|
||||
<string name="reboot_recovery">Restartovat do Recovery</string>
|
||||
<string name="reboot_bootloader">Restartovat do Bootloader</string>
|
||||
<string name="reboot_download">Restartovat do Download</string>
|
||||
<string name="reboot_edl">Restartovat do EDL</string>
|
||||
<string name="module_version_author">%1$s z %2$s</string>
|
||||
<string name="module_section_pending">Aktualizace</string>
|
||||
<string name="module_section_pending_action">Aktualizovat vše</string>
|
||||
<string name="module_state_remove">Odstranit</string>
|
||||
<string name="module_state_restore">Obnovit</string>
|
||||
<string name="module_action_install_external">Instalace z úložiště</string>
|
||||
<string name="update_available">Dostupná aktualizace</string>
|
||||
<string name="module_installed">@string/home_installed_version</string>
|
||||
<string name="module_section_online">Online</string>
|
||||
<string name="sorting_order">Seřadit</string>
|
||||
|
||||
<!--Settings-->
|
||||
<string name="settings_dark_mode_title">Režim motivu</string>
|
||||
<string name="settings_dark_mode_message">Vyberte režim, který nejlépe vyhovuje Vašemu stylu!</string>
|
||||
<string name="settings_dark_mode_light">Světlý</string>
|
||||
<string name="settings_dark_mode_system">Podle systému</string>
|
||||
<string name="settings_dark_mode_dark">Tmavý</string>
|
||||
<string name="settings_download_path_title">Složka pro stahování</string>
|
||||
<string name="settings_download_path_message">Soubory budou uloženy do %1$s.</string>
|
||||
<string name="settings_clear_cache_title">Smazat mezipaměť</string>
|
||||
<string name="settings_clear_cache_summary">Smažete online informace o použití z mezipaměti, a tím na aplikaci vynutíte obnovení online informací.</string>
|
||||
<string name="settings_hide_manager_title">Skrýt Magisk Manager</string>
|
||||
<string name="settings_hide_manager_summary">Nahradí Magisk Manager náhodným názvem balíčku.</string>
|
||||
<string name="settings_hide_manager_summary">Nahradíte Magisk Manager náhodným názvem balíčku.</string>
|
||||
<string name="settings_restore_manager_title">Obnovit Magisk Manager</string>
|
||||
<string name="settings_restore_manager_summary">Obnoví Magisk Manager na původní název balíčku.</string>
|
||||
<string name="settings_restore_manager_summary">Obnovíte Magisk Manager na původní název balíčku.</string>
|
||||
<string name="language">Jazyk</string>
|
||||
<string name="system_default">(Výchozí systémový)</string>
|
||||
<string name="settings_check_update_title">Zkontrolovat aktualizace</string>
|
||||
<string name="settings_check_update_summary">Pravidelně kontrolujte aktualizace na pozadí.</string>
|
||||
<string name="system_default">(výchozí podle systému)</string>
|
||||
<string name="settings_check_update_title">Automatické aktualizace</string>
|
||||
<string name="settings_check_update_summary">Povolíte pravidelnou kontrolu aktualizace na pozadí.</string>
|
||||
<string name="settings_update_channel_title">Kanál aktualizace</string>
|
||||
<string name="settings_update_stable">Stabilní</string>
|
||||
<string name="settings_update_beta">Beta</string>
|
||||
<string name="settings_update_custom">Vlastní</string>
|
||||
<string name="settings_update_custom_msg">Vložte vlastní URL</string>
|
||||
<string name="settings_magiskhide_summary">Skrýt Magisk z různých detekcí.</string>
|
||||
<string name="settings_hosts_title">Nesystémoví hostitelé</string>
|
||||
<string name="settings_hosts_summary">Podpora nesystémových hostitelů pro aplikace Adblock.</string>
|
||||
<string name="settings_magiskhide_summary">Skryjete Magisk před různými detekcemi.</string>
|
||||
<string name="settings_hosts_title">Nesystémový hostitel</string>
|
||||
<string name="settings_hosts_summary">Přidáte modul pro podporu nesystémových hostitelů v aplikaci AdBlock.</string>
|
||||
<string name="settings_hosts_toast">Přidán systémový modul hostitelů</string>
|
||||
|
||||
<string name="settings_app_name_hint">Nový název</string>
|
||||
<string name="settings_app_name_helper">Název aplikace bude nahrazen tímto názvem.</string>
|
||||
<string name="settings_app_name_error">Neplatný formát</string>
|
||||
<string name="settings_su_app_adb">Aplikace a ADB</string>
|
||||
<string name="settings_su_app">Pouze aplikace</string>
|
||||
<string name="settings_su_adb">Pouze ADB</string>
|
||||
<string name="settings_su_disable">Zakázáno</string>
|
||||
<string name="settings_su_disable">Zakázat</string>
|
||||
<string name="settings_su_request_10">10 sekund</string>
|
||||
<string name="settings_su_request_15">15 sekund</string>
|
||||
<string name="settings_su_request_20">20 sekund</string>
|
||||
<string name="settings_su_request_30">30 sekund</string>
|
||||
<string name="settings_su_request_45">45 sekund</string>
|
||||
<string name="settings_su_request_60">60 sekund</string>
|
||||
<string name="superuser_access">Přístup Superuser</string>
|
||||
<string name="superuser_access">Přístup SuperUser</string>
|
||||
<string name="auto_response">Automatická odezva</string>
|
||||
<string name="request_timeout">Časový limit požadavku</string>
|
||||
<string name="superuser_notification">Oznámení Superuser</string>
|
||||
<string name="superuser_notification">Oznámení SuperUser</string>
|
||||
<string name="settings_su_reauth_title">Opětovné ověření po aktualizaci</string>
|
||||
<string name="settings_su_reauth_summary">Opětovné ověření oprávnění Superuser po aktualizaci aplikace</string>
|
||||
<string name="settings_su_reauth_summary">Opětovné ověření oprávnění SuperUser po aktualizaci aplikace.</string>
|
||||
<string name="settings_su_tapjack_title">Povolit ochranu před TapJack</string>
|
||||
<string name="settings_su_tapjack_summary">Okno dialogu SuperUser nebude reagovat na kliknutí v případě, že je zavřené nebo překryté jiným oknem.</string>
|
||||
<string name="settings_su_biometric_title">Povolit biometrické ověření</string>
|
||||
<string name="settings_su_biometric_summary">Použijte biometrické ověření pro povolení požadavků SuperUser.</string>
|
||||
<string name="no_biometric">Nepodporované zařízení nebo není biometrické ověření povolené</string>
|
||||
<string name="settings_customization">Přizpůsobit</string>
|
||||
<string name="setting_add_shortcut_summary">Přidejte odkaz na domovskou obrazovku v případě, že se po skrytí aplikace její název a ikona těžko rozpoznávají.</string>
|
||||
<string name="settings_doh_title">DNS nebo HTTPS</string>
|
||||
<string name="settings_doh_description">Řešení pro opravy DNS v některých zemích.</string>
|
||||
|
||||
<string name="multiuser_mode">Režim více uživatelů</string>
|
||||
<string name="settings_owner_only">Pouze vlastník zařízení</string>
|
||||
<string name="settings_owner_manage">Spravováno vlastníkem zařízení</string>
|
||||
<string name="settings_user_independent">Nezávislý uživatel</string>
|
||||
<string name="owner_only_summary">Pouze vlastník má root přístup.</string>
|
||||
<string name="owner_manage_summary">Root přístup spravuje pouze vlastník a přijímá požadavky k přístupu.</string>
|
||||
<string name="user_indepenent_summary">Každý uživatel má svá vlastní pravidla root.</string>
|
||||
<string name="settings_owner_only">Vlastník zařízení</string>
|
||||
<string name="settings_owner_manage">Správce zařízení</string>
|
||||
<string name="settings_user_independent">Všichni uživatelé</string>
|
||||
<string name="owner_only_summary">Pouze vlastník má přístup ROOT.</string>
|
||||
<string name="owner_manage_summary">Přístup ROOT má správce zařízení, který přijímá požadavky k přístupu.</string>
|
||||
<string name="user_indepenent_summary">Každý uživatel má svá vlastní pravidla přístupu ROOT.</string>
|
||||
|
||||
<string name="mount_namespace_mode">Režim připojení jmenného prostoru</string>
|
||||
<string name="settings_ns_global">Globální jmenný prostor</string>
|
||||
<string name="settings_ns_requester">Zděděný jmenný prostor</string>
|
||||
<string name="settings_ns_requester">Odvozený jmenný prostor</string>
|
||||
<string name="settings_ns_isolate">Izolovaný jmenný prostor</string>
|
||||
<string name="global_summary">Všechny relace root používají globální připojení jmenného prostoru.</string>
|
||||
<string name="requester_summary">Kořenové relace dědí jmenný prostor žadatele.</string>
|
||||
<string name="isolate_summary">Každá relace root bude mít svůj vlastní izolovaný jmenný prostor.</string>
|
||||
<string name="global_summary">Všechny relace ROOT používají globální jmenný prostor.</string>
|
||||
<string name="requester_summary">Relace ROOT je odvozena od jmenného prostoru žadatele.</string>
|
||||
<string name="isolate_summary">Každá relace ROOT má svůj vlastní izolovaný jmenný prostor.</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Požadavek Superuser</string>
|
||||
<string name="deny">Zamítnout</string>
|
||||
<string name="prompt">Dotaz</string>
|
||||
<string name="grant">Povolit</string>
|
||||
<string name="su_warning">Povolí plný přístup k vašemu zařízení.\nZamítněte, pokud si nejste jisti!</string>
|
||||
<string name="forever">Navždy</string>
|
||||
<string name="once">Jednou</string>
|
||||
<string name="tenmin">10 minut</string>
|
||||
<string name="twentymin">20 minut</string>
|
||||
<string name="thirtymin">30 minut</string>
|
||||
<string name="sixtymin">60 minut</string>
|
||||
<string name="su_allow_toast">Pro %1$s bylo oprávnění Superuser povoleno</string>
|
||||
<string name="su_deny_toast">Pro %1$s bylo oprávnění Superuser zamítnuto</string>
|
||||
<string name="su_snack_grant">Superuser oprávnění pro %1$s je povoleno</string>
|
||||
<string name="su_snack_deny">Superuser oprávnění pro %1$s je zamítnuto</string>
|
||||
<string name="su_snack_notif_on">Oznámení pro %1$s jsou povolena</string>
|
||||
<string name="su_snack_notif_off">Oznámení pro %1$s jsou zakázána</string>
|
||||
<string name="su_snack_log_on">Logování %1$s je povoleno</string>
|
||||
<string name="su_snack_log_off">Logování %1$s je zakázáno</string>
|
||||
<string name="su_revoke_title">Smazat?</string>
|
||||
<string name="su_revoke_msg">Smazat záznam ohledně oprávnění pro %1$s?</string>
|
||||
<string name="toast">Informační text</string>
|
||||
<string name="none">Žádný</string>
|
||||
<!--Notifications-->
|
||||
<string name="update_channel">Aktualizace Magisk</string>
|
||||
<string name="progress_channel">Oznámení o průběhu</string>
|
||||
<string name="download_complete">Stahování dokončeno</string>
|
||||
<string name="download_file_error">Chyba při stahování souboru</string>
|
||||
<string name="download_open_parent">Zobrazit výchozí složku</string>
|
||||
<string name="download_open_self">Zobrazit soubor</string>
|
||||
<string name="magisk_update_title">Aktualizace Magisk je dostupná!</string>
|
||||
<string name="manager_update_title">Aktualizace Magisk Manager je dostupná!</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Cílové UID: %1$d</string>
|
||||
|
||||
<!-- MagiskHide -->
|
||||
<string name="show_system_app">Zobrazit systémové aplikace</string>
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="yes">ANO</string>
|
||||
<string name="no">NE</string>
|
||||
<string name="repo_install_title">Instalovat %1$s</string>
|
||||
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
|
||||
<string name="download">Stáhnout</string>
|
||||
<string name="reboot">Restartovat</string>
|
||||
<string name="release_notes">Poznámky k vydání</string>
|
||||
<string name="repo_cache_cleared">Mezipaměť smazána</string>
|
||||
<string name="flashing">Instalování…</string>
|
||||
<string name="done">Hotovo!</string>
|
||||
<string name="failure">Selhalo!</string>
|
||||
<string name="hide_manager_title">Skrývání Magisk Manager…</string>
|
||||
<string name="hide_manager_fail_toast">Skrývání Magisk Manager selhalo.</string>
|
||||
<string name="restore_manager_fail_toast">Obnovení Magisk Manager selhalo.</string>
|
||||
<string name="open_link_failed_toast">Nebyla nalezena žádná aplikace pro otevření odkazu.</string>
|
||||
<string name="complete_uninstall">Odinstalovat</string>
|
||||
<string name="restore_img">Obnovit obrazy</string>
|
||||
<string name="restore_img_msg">Obnovování…</string>
|
||||
<string name="restore_done">Obnovení bylo provedeno!</string>
|
||||
<string name="restore_fail">Výchozí záloha neexistuje!</string>
|
||||
<string name="proprietary_title">Stáhnout kód</string>
|
||||
<string name="proprietary_notice">Magisk Manager je FOSS a neobsahuje kód SafetyNet API společnosti Google.\n\nChcete povolit aplikaci Magisk Manager stažení rozšíření (obsahuje GoogleApiClient) pro kontrolu SafetyNet?</string>
|
||||
<string name="setup_fail">Nastavení selhalo</string>
|
||||
<string name="env_fix_title">Vyžaduje se další nastavení</string>
|
||||
<string name="env_fix_msg">Vaše zařízení potřebuje další nastavení, aby Magisk fungoval správně. Stáhne se instalační soubor (.zip) Magisk. Chcete pokračovat?</string>
|
||||
<string name="setup_msg">Nastavení je spuštěno…</string>
|
||||
<string name="authenticate">Ověřit</string>
|
||||
<string name="unsupport_magisk_title">Nepodporovaná verze Magisk</string>
|
||||
<string name="unsupport_magisk_msg">Tato verze Magisk Manager nepodporuje verzi Magisk nižší než %1$s.\n\nMůžete buď ručně aktualizovat Magisk, nebo nainstalovat starší verzi aplikace.</string>
|
||||
<string name="external_rw_permission_denied">Udělte oprávnění pro povolení této funkce.</string>
|
||||
<string name="add_shortcut_title">Přidat odkaz na domovskou obrazovku</string>
|
||||
<string name="add_shortcut_msg">Po skrytí Magisk Manager se může jeho název a ikona těžko rozpoznat. Chcete přidat odkaz na domovskou obrazovku?</string>
|
||||
<string name="app_not_found">Nelze nalézt žádnou aplikaci, která dokáže provést tuto akci.</string>
|
||||
|
||||
</resources>
|
||||
|
@@ -15,7 +15,7 @@
|
||||
<string name="no_connection">Keine Verbindung verfügbar</string>
|
||||
<string name="app_changelog">Änderungen</string>
|
||||
<string name="manager">Manager</string>
|
||||
<string name="loading">Lädt…</string>
|
||||
<string name="loading">Laden…</string>
|
||||
<string name="update">Update</string>
|
||||
<string name="not_available">N/A</string>
|
||||
<string name="hide">Verstecken</string>
|
||||
@@ -40,7 +40,7 @@
|
||||
<string name="recovery_mode">Recovery Modus</string>
|
||||
<string name="install_options_title">Optionen</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="manager_download_install">Tippen zum Herunterladen und Installieren</string>
|
||||
<string name="download_zip_only">Nur Zip herunterladen</string>
|
||||
|
@@ -170,6 +170,8 @@
|
||||
<string name="superuser_notification">Notificación de superusuario</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_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_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>
|
||||
|
@@ -22,7 +22,7 @@
|
||||
<string name="status">Status</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_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>
|
||||
@@ -85,11 +85,11 @@
|
||||
<string name="superuser_policy_none">Belum ada aplikasi yang meminta izin superuser.</string>
|
||||
|
||||
<!--Logs-->
|
||||
<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_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="menuSaveLog">Simpan log</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="target_uid">Target UID: %1$d</string>
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
<string name="safetynet_attest_loading">Tunggu sebentar…</string>
|
||||
<string name="safetynet_attest_restart">Coba lagi</string>
|
||||
|
||||
<!-- MagiskHide -->
|
||||
<!--MagiskHide-->
|
||||
<string name="show_system_app">Tampilkan aplikasi sistem</string>
|
||||
<string name="show_os_app">Tampilkan aplikasi OS</string>
|
||||
<string name="hide_filter_hint">Filter menurut nama</string>
|
||||
@@ -109,7 +109,7 @@
|
||||
<string name="hide_filters">Filter</string>
|
||||
<string name="hide_search">Telusuri</string>
|
||||
|
||||
<!--Module -->
|
||||
<!--Module-->
|
||||
<string name="no_info_provided">(Info tidak tersedia)</string>
|
||||
<string name="reboot_userspace">Nyalakan ulang secara halus</string>
|
||||
<string name="reboot_recovery">Nyalakan ke mode Recovery</string>
|
||||
@@ -127,7 +127,7 @@
|
||||
<string name="module_section_online">Online</string>
|
||||
<string name="sorting_order">Urutan sortir</string>
|
||||
|
||||
<!--Settings -->
|
||||
<!--Settings-->
|
||||
<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_light">Selalu terang</string>
|
||||
@@ -220,7 +220,7 @@
|
||||
<string name="repo_cache_cleared">Cache repo dihapus</string>
|
||||
<string name="flashing">Memasang…</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_fail_toast">Gagal menyembunyikan Magisk Manager.</string>
|
||||
<string name="restore_manager_fail_toast">Gagal memulihkan Magisk Manager</string>
|
||||
|
@@ -55,6 +55,7 @@
|
||||
|
||||
<!--Superuser-->
|
||||
<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="prompt">Chiedi</string>
|
||||
<string name="grant">Consenti</string>
|
||||
@@ -101,6 +102,7 @@
|
||||
|
||||
<!-- MagiskHide -->
|
||||
<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_scroll_up">Scorri verso l\'alto</string>
|
||||
<string name="hide_filters">Filtri</string>
|
||||
@@ -108,6 +110,7 @@
|
||||
|
||||
<!--Module Fragment-->
|
||||
<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_bootloader">Riavvia in bootloader</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="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_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_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>
|
||||
@@ -217,6 +222,7 @@
|
||||
<string name="failure">Fallito</string>
|
||||
<string name="hide_manager_title">Nascondendo Magisk Manager…</string>
|
||||
<string name="hide_manager_fail_toast">Non è stato possibile nascondere Magisk Manager.</string>
|
||||
<string name="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="complete_uninstall">Disinstalla completamente</string>
|
||||
<string name="restore_img">Ripristina immagini</string>
|
||||
|
@@ -15,7 +15,7 @@
|
||||
<string name="no_connection">אין חיבור זמין</string>
|
||||
<string name="app_changelog">רשימת שינויים</string>
|
||||
<string name="manager">מנהל</string>
|
||||
<string name="loading">…טוען</string>
|
||||
<string name="loading">טוען…</string>
|
||||
<string name="update">עדכון</string>
|
||||
<string name="not_available">ל/ז</string>
|
||||
<string name="hide">הסתרה</string>
|
||||
@@ -33,6 +33,7 @@
|
||||
<string name="invalid_update_channel">ערוץ עדכון לא חוקי</string>
|
||||
<string name="uninstall_magisk_title">הסרת Magisk</string>
|
||||
<string name="uninstall_magisk_msg">כל המודולים יושבתו/יוסרו!\nגישת שורש תושבת!\nהנתונים שלך עשויים להיות מוצפנים אם לא הוצפנו כבר!</string>
|
||||
<string name="home_check_safetynet">בדיקת SafetyNet</string>
|
||||
|
||||
<!--Install-->
|
||||
<string name="keep_force_encryption">שמירה על הצפנה בכח</string>
|
||||
@@ -41,7 +42,7 @@
|
||||
<string name="install_options_title">אפשרויות</string>
|
||||
<string name="install_method_title">שיטה</string>
|
||||
<string name="install_next">הבא</string>
|
||||
<string name="install_start">מצא לדרך</string>
|
||||
<string name="install_start">צא לדרך</string>
|
||||
<string name="manager_download_install">לחץ להורדה והתקנה</string>
|
||||
<string name="download_zip_only">הורד ZIP בלבד</string>
|
||||
<string name="direct_install">התקנה ישירה (מומלץ)</string>
|
||||
@@ -55,7 +56,8 @@
|
||||
|
||||
<!--Superuser-->
|
||||
<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="grant">הענק</string>
|
||||
<string name="su_warning">מעניק גישה מלאה להתקן שלך.\nדחה באם אינך בטוח!</string>
|
||||
@@ -93,7 +95,7 @@
|
||||
|
||||
<!--SafetyNet-->
|
||||
<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_failure">האישור נכשל!</string>
|
||||
<string name="safetynet_attest_loading">רק רגע…</string>
|
||||
@@ -101,6 +103,7 @@
|
||||
|
||||
<!-- MagiskHide -->
|
||||
<string name="show_system_app">הצגת יישומי מערכת</string>
|
||||
<string name="show_os_app">הצגת יישומי מערכת הפעלה</string>
|
||||
<string name="hide_filter_hint">סינון לפי שם</string>
|
||||
<string name="hide_scroll_up">גלול למעלה</string>
|
||||
<string name="hide_filters">מסננים</string>
|
||||
@@ -108,6 +111,7 @@
|
||||
|
||||
<!--Module Fragment-->
|
||||
<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>
|
||||
@@ -120,8 +124,8 @@
|
||||
<string name="module_action_install_external">התקן מהאחסון</string>
|
||||
<string name="update_available">עדכונים זמינים</string>
|
||||
<string name="module_installed">@string/home_installed_version</string>
|
||||
<string name="module_section_online">מקוון</string>
|
||||
<string name="sorting_order">סדר מיון</string>
|
||||
<string name="external_rw_permission_denied">הענק הרשאה לאחסון כדי לאפשר פונקציונליות זו</string>
|
||||
|
||||
<!--Settings -->
|
||||
<string name="settings_dark_mode_title">מצב עיצוב</string>
|
||||
@@ -168,12 +172,15 @@
|
||||
<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_reauth_summary">אימות מחדש הרשאות של משתמש על לאחר שדרוג יישום</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="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>
|
||||
@@ -214,8 +221,9 @@
|
||||
<string name="failure">נכשל</string>
|
||||
<string name="hide_manager_title">מסתיר את מנהל Magisk…</string>
|
||||
<string name="hide_manager_fail_toast">הסתרת מנהל Magisk כשלה.</string>
|
||||
<string name="open_link_failed_toast">לא נמצאו יישומים לפתיחת קישור זה</string>
|
||||
<string name="complete_uninstall">הוסר סהצלחה</string>
|
||||
<string name="restore_manager_fail_toast">שחזור מנהל Magisk נכשל</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>
|
||||
@@ -229,5 +237,8 @@
|
||||
<string name="authenticate">אימות</string>
|
||||
<string name="unsupport_magisk_title">גרסת 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>
|
||||
|
8
app/src/main/res/values-night/styles_md2.xml
Normal file
8
app/src/main/res/values-night/styles_md2.xml
Normal 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>
|
244
app/src/main/res/values-pa/strings.xml
Normal file
244
app/src/main/res/values-pa/strings.xml
Normal 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>
|
@@ -22,7 +22,7 @@
|
||||
<string name="status">Stare</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_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>
|
||||
@@ -55,7 +55,8 @@
|
||||
<string name="flash_screen_title">Instalare</string>
|
||||
|
||||
<!--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="prompt">Solicită</string>
|
||||
<string name="grant">Acordă</string>
|
||||
@@ -81,14 +82,14 @@
|
||||
|
||||
<string name="superuser_toggle_notification">Notificări</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-->
|
||||
<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_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="menuSaveLog">Salvează jurnalul</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="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_restart">Încearcă din nou</string>
|
||||
|
||||
<!-- MagiskHide -->
|
||||
<!--MagiskHide-->
|
||||
<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_scroll_up">Derulează în sus</string>
|
||||
<string name="hide_filters">Filtre</string>
|
||||
<string name="hide_search">Căutare</string>
|
||||
|
||||
<!--Module -->
|
||||
<!--Module-->
|
||||
<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_bootloader">Repornește în modul bootloader</string>
|
||||
<string name="reboot_download">Repornește în modul download</string>
|
||||
@@ -124,7 +127,7 @@
|
||||
<string name="module_section_online">Online</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_message">Selectează modul care ți se pliază cel mai bine stilului!</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_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_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_summary">Reîmpachetează Magisk Manager cu numele aleatorii pentru pachet și aplicație</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="superuser_access">Acces pentru superutilizator</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="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_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_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>
|
||||
@@ -183,7 +188,7 @@
|
||||
<string name="settings_owner_manage">Gestionat de proprietarul dispozitivului</string>
|
||||
<string name="settings_user_independent">Utilizator independent</string>
|
||||
<string name="owner_only_summary">Numai proprietarul are acces la root</string>
|
||||
<string name="owner_manage_summary">Numai proprietarul poate 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="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="flashing">Se scrie în memoria flash…</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_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="complete_uninstall">Finalizează dezinstalarea</string>
|
||||
<string name="restore_img">Restaurează imagini</string>
|
||||
|
@@ -22,7 +22,7 @@
|
||||
<string name="status">Stav</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_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>
|
||||
@@ -44,7 +44,7 @@
|
||||
<string name="install_next">Ďalej</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="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="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>
|
||||
@@ -85,11 +85,11 @@
|
||||
<string name="superuser_policy_none">Žiadna aplikácia zatiaľ nepožiadala o povolenie Superužívateľa.</string>
|
||||
|
||||
<!--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_magisk_none">Záznamy Magisku sú prázdne, to je divné.</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="menuSaveLog">Uložiť 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="target_uid">Cieľový UID: %1$d</string>
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
<string name="safetynet_attest_loading">Momentík ...</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_os_app">Zobraziť aplikácie OS</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_search">Vyhľadávanie</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<!--Module-->
|
||||
<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_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_message">Vyberte režim, ktorý najlepšie vyhovuje vášmu štýlu!</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="flashing">Flashovanie...</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_fail_toast">Skrytie Magisk Managera zlyhalo</string>
|
||||
<string name="restore_manager_fail_toast">Obnovenie Magisk Managera zlyhalo</string>
|
||||
|
238
app/src/main/res/values-sq/strings.xml
Normal file
238
app/src/main/res/values-sq/strings.xml
Normal file
@@ -0,0 +1,238 @@
|
||||
<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">Gjithmonë</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="none">Asnjë</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="settings_su_request_10">10 Sekonda</string>
|
||||
<string name="settings_su_request_15">15 Sekonda</string>
|
||||
<string name="settings_su_request_20">20 Sekonda</string>
|
||||
<string name="settings_su_request_30">30 Sekonda</string>
|
||||
<string name="settings_su_request_45">45 Sekonda</string>
|
||||
<string name="settings_su_request_60">60 Sekonda</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">Rikthimi i 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>
|
@@ -1,11 +1,11 @@
|
||||
<resources>
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<!--Sections-->
|
||||
<string name="modules">Modüller</string>
|
||||
<string name="superuser">Yetkili Kullanıcı</string>
|
||||
<string name="logs">Günlük</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="section_home">Ana Ekran</string>
|
||||
<string name="section_theme">Temalar</string>
|
||||
@@ -14,7 +14,7 @@
|
||||
<!--Home-->
|
||||
<string name="no_connection">Bağlantı yok</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="update">Güncelle</string>
|
||||
<string name="not_available">N/A</string>
|
||||
@@ -22,13 +22,13 @@
|
||||
<string name="status">Durum</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_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_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="invalid_update_channel">Geçersiz Güncelleme Kanalı</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>
|
||||
|
||||
<!--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="recovery_mode">Kurtarma Modu</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="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_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="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>
|
||||
@@ -56,12 +56,13 @@
|
||||
|
||||
<!--Superuser-->
|
||||
<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="prompt">Sor</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="forever">Daima</string>
|
||||
<string name="once">Bir kere</string>
|
||||
<string name="once">Bir kereliğine</string>
|
||||
<string name="tenmin">10 dakika</string>
|
||||
<string name="twentymin">20 dakika</string>
|
||||
<string name="thirtymin">30 dakika</string>
|
||||
@@ -81,14 +82,14 @@
|
||||
|
||||
<string name="superuser_toggle_notification">Bildirimler</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-->
|
||||
<string name="log_data_none">Günlük boş, daha fazla uygulama için SU etkinleştirmeyi deneyin.</string>
|
||||
<string name="log_data_magisk_none">Magisk günlükleri boş, bu garip.</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="menuSaveLog">Günlüğü kaydet</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="target_uid">Hedef UID: %1$d</string>
|
||||
|
||||
@@ -96,41 +97,43 @@
|
||||
<string name="safetynet_api_error">SafetyNet API Hatası</string>
|
||||
<string name="safetynet_res_invalid">Yanıt geçersiz</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_restart">Tekrar deneyiniz</string>
|
||||
<string name="safetynet_attest_restart">Tekrar dene</string>
|
||||
|
||||
<!-- MagiskHide -->
|
||||
<string name="show_system_app">Sistem uygulamalarını göster</string>
|
||||
<!--MagiskHide-->
|
||||
<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_scroll_up">Yukarı kaydır</string>
|
||||
<string name="hide_filters">Filtreler</string>
|
||||
<string name="hide_search">Ara</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Hiçbir açıklama sağlanmadı)</string>
|
||||
<!--Module-->
|
||||
<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_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="module_version_author">%1$s - %2$s</string>
|
||||
<string name="module_section_pending">Güncellemeler</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_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="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>
|
||||
|
||||
<!--Settings -->
|
||||
<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_light">Her zaman aydınlık</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_download_path_title">İndirme Yolu</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_system">Sistemi Takip Et</string>
|
||||
<string name="settings_dark_mode_dark">Her Zaman Karanlık</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_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>
|
||||
@@ -143,9 +146,9 @@
|
||||
<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_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_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_magiskhide_summary">Magisk\'i çeşitli algılamalardan gizle</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">Sadece uygulamalar</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_15">15 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="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_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_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="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="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="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="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="settings_ns_global">Evrensel Ad Alanı</string>
|
||||
<string name="mount_namespace_mode">Ad Alanı Modunu Bağla</string>
|
||||
<string name="settings_ns_global">Global 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="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_open_parent">Üst klasörde 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="manager_update_title">Yeni Magisk Manager Güncellemesi Mevcut!</string>
|
||||
<string name="magisk_update_title">Magisk Güncellemesi Mevcut!</string>
|
||||
<string name="manager_update_title">Magisk Manager Güncellemesi Mevcut!</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="yes">Evet</string>
|
||||
@@ -217,25 +222,26 @@
|
||||
<string name="done">Tamamlandı!</string>
|
||||
<string name="failure">Başarısız</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="open_link_failed_toast">Bağlantıyı açabilecek uygulama bulunamadı.</string>
|
||||
<string name="hide_manager_fail_toast">Magisk Manager\'ı gizleme başarısız</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="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_done">Yenileme tamamlandı!</string>
|
||||
<string name="restore_fail">Stok önyükleme yedeği yok!</string>
|
||||
<string name="restore_done">Geri yükleme tamamlandı!</string>
|
||||
<string name="restore_fail">Stock ön yükleme yedeği yok!</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="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="setup_msg">Ortam kurulumu çalışıyor…</string>
|
||||
<string name="authenticate">Kimlik doğrulaması</string>
|
||||
<string name="setup_msg">Ortam kurulumu çalıştırılıyor…</string>
|
||||
<string name="authenticate">Kimlik Doğrulaması</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="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_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>
|
||||
|
||||
</resources>
|
||||
|
@@ -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>
|
18
app/src/main/res/values-v19/themes.xml
Normal file
18
app/src/main/res/values-v19/themes.xml
Normal 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>
|
@@ -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>
|
38
app/src/main/res/values-v21/themes.xml
Normal file
38
app/src/main/res/values-v21/themes.xml
Normal 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>
|
17
app/src/main/res/values-v23/themes.xml
Normal file
17
app/src/main/res/values-v23/themes.xml
Normal 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>
|
24
app/src/main/res/values-v27/themes.xml
Normal file
24
app/src/main/res/values-v27/themes.xml
Normal 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>
|
@@ -16,14 +16,6 @@
|
||||
<item>@string/settings_su_app_adb</item>
|
||||
</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">
|
||||
<item>@string/settings_su_request_10</item>
|
||||
<item>@string/settings_su_request_15</item>
|
||||
|
@@ -19,4 +19,32 @@
|
||||
|
||||
<!--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>
|
||||
|
@@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<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>
|
||||
|
@@ -1,20 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="SplashThemeBase" parent="android:Theme.DeviceDefault.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/ic_splash_activity</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
</style>
|
||||
<style name="SplashTheme" parent="Theme.Splash.Light" />
|
||||
|
||||
<style name="SplashTheme" parent="SplashThemeBase" />
|
||||
|
||||
<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" />
|
||||
<style name="Foundation" parent="Theme.Foundation.Light" />
|
||||
|
||||
<!--region Do not remove-->
|
||||
<style name="Empty" />
|
||||
@@ -28,7 +17,7 @@
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
|
||||
<style name="Foundation.Default" parent="Foundation.Compat">
|
||||
<style name="Foundation.Default">
|
||||
<item name="android:includeFontPadding">false</item>
|
||||
<item name="actionBarSize">@dimen/internal_action_bar_size</item>
|
||||
<item name="popupMenuStyle">@style/Foundation.PopupMenu</item>
|
||||
|
41
app/src/main/res/values/themes.xml
Normal file
41
app/src/main/res/values/themes.xml
Normal 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>
|
@@ -14,12 +14,12 @@ buildscript {
|
||||
maven { url = uri("https://kotlin.bintray.com/kotlinx") }
|
||||
}
|
||||
|
||||
val vNav = "2.3.1"
|
||||
val vNav = "2.3.2"
|
||||
extra["vNav"] = vNav
|
||||
|
||||
dependencies {
|
||||
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}")
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@@ -110,12 +110,12 @@ subprojects {
|
||||
buildTypes {
|
||||
signingConfigs.getByName("config").also {
|
||||
getByName("debug") {
|
||||
// If keystore exists, sign the APK with custom signature
|
||||
if (it.storeFile?.exists() == true)
|
||||
signingConfig = it
|
||||
signingConfig = if (it.storeFile?.exists() == true) it
|
||||
else signingConfigs.getByName("debug")
|
||||
}
|
||||
getByName("release") {
|
||||
signingConfig = it
|
||||
signingConfig = if (it.storeFile?.exists() == true) it
|
||||
else signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user