Compare commits

..

1 Commits

Author SHA1 Message Date
GitHub Actions
01fe801ea7 add device: non-GKI device 2024-08-20 03:15:13 +00:00
220 changed files with 3722 additions and 5984 deletions

1
.github/FUNDING.yml vendored
View File

@@ -2,3 +2,4 @@
github: tiann
patreon: weishu
custom: https://vxposed.com/donate.html

View File

@@ -26,7 +26,7 @@ jobs:
- name: Make pull request
if: steps.handle-add-device.outputs.success == 'true'
id: cpr
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "[add device]: ${{ steps.handle-add-device.outputs.device }}"
@@ -37,7 +37,6 @@ jobs:
branch: "add-device-${{ github.event.issue.number }}"
labels: add-device
delete-branch: true
sign-commits: true
- name: Check outputs
if: ${{ steps.cpr.outputs.pull-request-number }}
run: |

View File

@@ -37,7 +37,7 @@ on:
jobs:
build:
name: Build ${{ inputs.version_name }}
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@master

View File

@@ -7,9 +7,9 @@ jobs:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.226
tag: android12-5.10-2024-11
os_patch_level: 2024-11
version_name: android12-5.10.209
tag: android12-5.10-2024-05
os_patch_level: 2024-05
patch_path: "5.10"
debug: true
build-debug-kernel-a13:
@@ -17,11 +17,11 @@ jobs:
matrix:
include:
- version: "5.10"
sub_level: 223
os_patch_level: 2024-11
sub_level: 209
os_patch_level: 2024-05
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
sub_level: 148
os_patch_level: 2024-05
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
@@ -34,29 +34,15 @@ jobs:
matrix:
include:
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
sub_level: 148
os_patch_level: 2024-05
- version: "6.1"
sub_level: 115
os_patch_level: 2024-12
sub_level: 75
os_patch_level: 2024-05
uses: ./.github/workflows/gki-kernel.yml
with:
version: android14-${{ matrix.version }}
version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: true
build-debug-kernel-a15:
strategy:
matrix:
include:
- version: "6.6"
sub_level: 57
os_patch_level: 2024-12
uses: ./.github/workflows/gki-kernel.yml
with:
version: android15-${{ matrix.version }}
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: true

View File

@@ -21,16 +21,12 @@ jobs:
strategy:
matrix:
include:
- sub_level: 198
os_patch_level: 2024-01
- sub_level: 205
os_patch_level: 2024-03
- sub_level: 209
os_patch_level: 2024-05
- sub_level: 218
os_patch_level: 2024-08
- sub_level: 226
os_patch_level: 2024-11
- sub_level: 233
os_patch_level: 2025-02
- sub_level: 236
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -67,7 +63,7 @@ jobs:
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
BRANCH=main-kernel-build-2023
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
@@ -116,7 +112,7 @@ jobs:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.223
tag: android12-5.10-2024-11
os_patch_level: 2024-11
version_name: android12-5.10.209
tag: android12-5.10-2024-05
os_patch_level: 2024-05
patch_path: "5.10"

View File

@@ -21,51 +21,30 @@ jobs:
strategy:
matrix:
include:
- version: "5.10"
sub_level: 189
os_patch_level: 2023-11
- version: "5.10"
sub_level: 198
os_patch_level: 2024-01
- version: "5.10"
sub_level: 205
os_patch_level: 2024-03
- version: "5.10"
sub_level: 209
os_patch_level: 2024-05
- version: "5.10"
sub_level: 210
os_patch_level: 2024-06
- version: "5.10"
sub_level: 214
os_patch_level: 2024-07
- version: "5.10"
sub_level: 218
os_patch_level: 2024-08
- version: "5.10"
sub_level: 223
os_patch_level: 2024-11
- version: "5.10"
sub_level: 228
os_patch_level: 2025-01
- version: "5.10"
sub_level: 234
os_patch_level: 2025-03
- version: "5.15"
sub_level: 123
os_patch_level: 2023-11
- version: "5.15"
sub_level: 137
os_patch_level: 2024-01
- version: "5.15"
sub_level: 144
os_patch_level: 2024-03
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
- version: "5.15"
sub_level: 149
os_patch_level: 2024-07
- version: "5.15"
sub_level: 151
os_patch_level: 2024-08
- version: "5.15"
sub_level: 153
os_patch_level: 2024-09
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
- version: "5.15"
sub_level: 178
os_patch_level: 2024-11
- version: "5.15"
sub_level: 170
os_patch_level: 2025-01
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -102,7 +81,7 @@ jobs:
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
BRANCH=main-kernel-build-2023
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
@@ -152,11 +131,11 @@ jobs:
matrix:
include:
- version: "5.10"
sub_level: 223
os_patch_level: 2024-11
sub_level: 209
os_patch_level: 2024-05
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
sub_level: 148
os_patch_level: 2024-05
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}

View File

@@ -21,63 +21,33 @@ jobs:
strategy:
matrix:
include:
- version: "5.15"
sub_level: 131
os_patch_level: 2023-11
- version: "5.15"
sub_level: 137
os_patch_level: 2024-01
- version: "5.15"
sub_level: 144
os_patch_level: 2024-03
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
- version: "5.15"
sub_level: 149
os_patch_level: 2024-06
- version: "5.15"
sub_level: 153
os_patch_level: 2024-07
- version: "5.15"
sub_level: 158
os_patch_level: 2024-08
- version: "5.15"
sub_level: 164
os_patch_level: 2024-09
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
- version: "5.15"
sub_level: 170
os_patch_level: 2025-01
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
- version: "6.1"
sub_level: 25
os_patch_level: 2023-10
- version: "6.1"
sub_level: 43
os_patch_level: 2023-11
- version: "6.1"
sub_level: 57
os_patch_level: 2024-01
- version: "6.1"
sub_level: 68
os_patch_level: 2024-03
- version: "6.1"
sub_level: 75
os_patch_level: 2024-05
- version: "6.1"
sub_level: 78
os_patch_level: 2024-06
- version: "6.1"
sub_level: 84
os_patch_level: 2024-07
- version: "6.1"
sub_level: 90
os_patch_level: 2024-08
- version: "6.1"
sub_level: 93
os_patch_level: 2024-09
- version: "6.1"
sub_level: 99
os_patch_level: 2024-10
- version: "6.1"
sub_level: 112
os_patch_level: 2024-11
- version: "6.1"
sub_level: 115
os_patch_level: 2024-12
- version: "6.1"
sub_level: 118
os_patch_level: 2025-01
- version: "6.1"
sub_level: 128
os_patch_level: 2025-03
- version: "6.1"
sub_level: 134
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -114,7 +84,7 @@ jobs:
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
BRANCH=main-kernel-build-2023
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
@@ -164,11 +134,11 @@ jobs:
matrix:
include:
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
sub_level: 148
os_patch_level: 2024-05
- version: "6.1"
sub_level: 115
os_patch_level: 2024-12
sub_level: 75
os_patch_level: 2024-05
uses: ./.github/workflows/gki-kernel.yml
with:
version: android14-${{ matrix.version }}

View File

@@ -23,34 +23,7 @@ jobs:
include:
- version: "6.6"
sub_level: 30
os_patch_level: 2024-08
- version: "6.6"
sub_level: 46
os_patch_level: 2024-09
- version: "6.6"
sub_level: 50
os_patch_level: 2024-10
- version: "6.6"
sub_level: 56
os_patch_level: 2024-11
- version: "6.6"
sub_level: 57
os_patch_level: 2024-12
- version: "6.6"
sub_level: 58
os_patch_level: 2025-01
- version: "6.6"
sub_level: 66
os_patch_level: 2025-02
- version: "6.6"
sub_level: 77
os_patch_level: 2025-03
- version: "6.6"
sub_level: 82
os_patch_level: 2025-04
- version: "6.6"
sub_level: 87
os_patch_level: 2025-05
os_patch_level: 2024-07
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -137,12 +110,12 @@ jobs:
matrix:
include:
- version: "6.6"
sub_level: 57
os_patch_level: 2024-12
sub_level: 30
os_patch_level: 2024-07
uses: ./.github/workflows/gki-kernel.yml
with:
version: android15-${{ matrix.version }}
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
patch_path: ${{ matrix.version }}

View File

@@ -32,7 +32,7 @@ jobs:
defconfig: arm64_arcvm_defconfig
name: Build ChromeOS ARCVM kernel
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
env:
LTO: thin
ROOT_DIR: /
@@ -50,7 +50,7 @@ jobs:
sudo ln -s --force python3 /usr/bin/python
export LLVM_VERSION=14
export LLVM_VERSION=12
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $LLVM_VERSION

View File

@@ -15,23 +15,23 @@ jobs:
matrix:
include:
- version: "android12-5.10"
sub_level: 236
os_patch_level: 2025-05
sub_level: 209
os_patch_level: 2024-05
- version: "android13-5.10"
sub_level: 234
os_patch_level: 2025-03
sub_level: 209
os_patch_level: 2024-05
- version: "android13-5.15"
sub_level: 178
os_patch_level: 2025-03
sub_level: 148
os_patch_level: 2024-05
- version: "android14-5.15"
sub_level: 178
os_patch_level: 2025-03
sub_level: 148
os_patch_level: 2024-05
- version: "android14-6.1"
sub_level: 134
os_patch_level: 2025-05
sub_level: 75
os_patch_level: 2024-05
- version: "android15-6.6"
sub_level: 87
os_patch_level: 2025-05
sub_level: 30
os_patch_level: 2024-07
uses: ./.github/workflows/gki-kernel.yml
with:
version: ${{ matrix.version }}

View File

@@ -22,16 +22,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: rustup update stable
- run: rustup update --force-non-host stable-x86_64-unknown-linux-gnu
- uses: Swatinem/rust-cache@v2
with:
workspaces: userspace/ksud
- name: Install cross
run: |
RUSTFLAGS="" cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1
cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1
- name: Run clippy
run: |
cross clippy --manifest-path userspace/ksud/Cargo.toml --target aarch64-linux-android --release
cross clippy --manifest-path userspace/ksud/Cargo.toml --target x86_64-linux-android --release
cross clippy --manifest-path userspace/ksud/Cargo.toml --target x86_64-linux-android --release

View File

@@ -37,7 +37,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: latest
node-version: 20
cache: yarn # or pnpm / yarn
cache-dependency-path: website/yarn.lock
- name: Setup Pages
@@ -64,4 +64,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v4

View File

@@ -131,15 +131,8 @@ jobs:
DRIVER_KCONFIG=$GKI_ROOT/common/drivers/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Apply Compilation Patches"
if [ ! -e build/build.sh ]; then
GLIBC_VERSION=$(ldd --version 2>/dev/null | head -n 1 | awk '{print $NF}')
echo "GLIBC_VERSION: $GLIBC_VERSION"
if [ "$(printf '%s\n' "2.38" "$GLIBC_VERSION" | sort -V | head -n1)" = "2.38" ]; then
echo "Patching resolve_btfids/Makefile"
cd $GKI_ROOT/common/ && sed -i '/\$(Q)\$(MAKE) -C \$(SUBCMD_SRC) OUTPUT=\$(abspath \$(dir \$@))\/ \$(abspath \$@)/s//$(Q)$(MAKE) -C $(SUBCMD_SRC) EXTRA_CFLAGS="$(CFLAGS)" OUTPUT=$(abspath $(dir $@))\/ $(abspath $@)/' tools/bpf/resolve_btfids/Makefile || echo "No patch needed."
fi
fi
echo "[+] Apply KernelSU patches"
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch || echo "[-] No patch found"
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
echo "[+] Enable debug features for kernel"
@@ -198,11 +191,6 @@ jobs:
- name: Make working directory clean to avoid dirty
working-directory: android-kernel
run: |
# Fix bazel build error
if [ -f common/BUILD.bazel ]; then
[ -f android/abi_gki_protected_exports_aarch64 ] || sed -i '/^[[:space:]]*"protected_exports_list"[[:space:]]*:[[:space:]]*"android\/abi_gki_protected_exports_aarch64",$/d' common/BUILD.bazel
fi
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
git config --global user.email "bot@kernelsu.org"
git config --global user.name "KernelSUBot"
@@ -260,4 +248,4 @@ jobs:
if: ${{ inputs.build_lkm == true }}
with:
name: ${{ inputs.version }}-lkm
path: ./output/*_kernelsu.ko
path: ./output/*_kernelsu.ko

View File

@@ -45,7 +45,7 @@ jobs:
- name: Install cross
run: |
RUSTFLAGS="" cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1
cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1
- name: Build ksud
run: CROSS_NO_WARNINGS=0 cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud/Cargo.toml

View File

@@ -39,20 +39,6 @@ jobs:
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Rename ksud
run: |
mkdir -p ksud
for dir in ./ksud-*; do
if [ -d "$dir" ]; then
echo "----- Rename $dir -----"
ksud_platform_name=$(basename "$dir")
find "$dir" -type f -name "ksud" -path "*/release/*" | while read -r ksud_file; do
if [ -f "$ksud_file" ]; then
mv "$ksud_file" "ksud/$ksud_platform_name"
fi
done
fi
done
- name: Zip AnyKernel3
run: |
for dir in AnyKernel3-*; do
@@ -93,4 +79,4 @@ jobs:
boot-images-*/Image-*/*.img.gz
kernel-WSA*.zip
kernel-ARCVM*.zip
ksud/ksud-*
ksud-*

View File

@@ -1,10 +1,10 @@
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
A kernel-based root solution for Android devices.
A Kernel-based root solution for Android devices.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
@@ -18,19 +18,19 @@ A kernel-based root solution for Android devices.
2. Module system based on [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Lock up the root power in a cage.
## Compatibility state
## Compatibility State
KernelSU officially supports Android GKI 2.0 devices (kernel 5.10+). Older kernels (4.14+) are also supported, but the kernel will need to be built manually.
KernelSU officially supports Android GKI 2.0 devices (kernel 5.10+). Older kernels (4.14+) are also compatible, but the kernel will have to be built manually.
With this, WSA, ChromeOS, and container-based Android are all supported.
Currently, only the `arm64-v8a` and `x86_64` architectures are supported.
Currently, only `arm64-v8a` and `x86_64` are supported.
## Usage
- [Installation](https://kernelsu.org/guide/installation.html)
- [How to build](https://kernelsu.org/guide/how-to-build.html)
- [Official website](https://kernelsu.org/)
- [Installation Instruction](https://kernelsu.org/guide/installation.html)
- [How to build?](https://kernelsu.org/guide/how-to-build.html)
- [Official Website](https://kernelsu.org/)
## Translation
@@ -51,7 +51,7 @@ For information on reporting security vulnerabilities in KernelSU, see [SECURITY
## Credits
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): The KernelSU idea.
- [Magisk](https://github.com/topjohnwu/Magisk): The powerful root tool.
- [genuine](https://github.com/brevent/genuine/): APK v2 signature validation.
- [Diamorphine](https://github.com/m0nad/Diamorphine): Some rootkit skills.
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): the KernelSU idea.
- [Magisk](https://github.com/topjohnwu/Magisk): the powerful root tool.
- [genuine](https://github.com/brevent/genuine/): apk v2 signature validation.
- [Diamorphine](https://github.com/m0nad/Diamorphine): some rootkit skills.

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -1,4 +1,4 @@
[English](README.md) | **Español** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | **Español** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | **हिंदी** | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | **हिंदी**
# KernelSU

View File

@@ -1,58 +0,0 @@
[English](REAME.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | **Italiano**
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Una soluzione per il root basata sul kernel per i dispositivi Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Canale Telegraml](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![Licenza componenti kernel: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![Licenza elementi non kern](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Funzionalità
1. `su` e accesso root basato sul kernel.
2. Sistema di moduli per la modifica del sistema basato su [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [App profile](https://kernelsu.org/guide/app-profile.html): Limita i poteri dell'accesso root a permessi specifici.
## Compatibilità
KernelSU supporta ufficialmente i dispositivi Android GKI 2.0 (kernel 5.10 o superiore). I kernel precedenti (kernel 4.14+) sono anche compatibili, ma il kernel deve essere compilato manualmente.
Questo implica che WSA, ChromeOS e tutti le varianti di Android basate su container e virtualizzazione sono supportate.
Allo stato attuale solo le architetture a 64-bit ARM (arm64-v8a) e x86 (x86_64) sono supportate.
## Utilizzo
- [Istruzioni per l'installazione](https://kernelsu.org/guide/installation.html)
- [Come compilare manualmente?](https://kernelsu.org/guide/how-to-build.html)
- [Sito web ufficiale](https://kernelsu.org/)
## Traduzioni
Per aiutare a tradurre KernelSU o migliorare le traduzioni esistenti, si è pregati di utilizzare
To help translate KernelSU or improve existing translations, please use [Weblate](https://hosted.weblate.org/engage/kernelsu/). Le richieste di pull delle traduzioni del manager non saranno più accettate perché sarebbero in conflitto con Weblate.
## Discussione
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Securezza
Per informazioni riguardo la segnalazione di vulnerabilità di sicurezza per KernelSU, leggi [SECURITY.md](/SECURITY.md).
## Licenza
- I file nella cartella `kernel` sono forniti secondo la licenza [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Tutte le altre parti, ad eccezione della certella `kernel`, seguono la licenza [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
## Riconoscimenti e attribuzioni
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): l'idea alla base di KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): la potente utilità per il root.
- [genuine](https://github.com/brevent/genuine/): verifica della firma apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): alcune capacità di rootkit.

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **한국어** | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **한국어** | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | **Polski** | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | **Polski** | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
@@ -15,26 +15,26 @@ Uma solução root baseada em kernel para dispositivos Android.
## Características
1. `su` e gerenciamento de acesso root baseado em kernel.
2. Sistema de módulos baseado em [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
2. Sistema modular baseado em [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [Perfil do Aplicativo](https://kernelsu.org/pt_BR/guide/app-profile.html): Tranque o poder root em uma gaiola.
## Estado de compatibilidade
O KernelSU oferece suporte oficial a dispositivos Android GKI 2.0 (kernel 5.10+). Kernels mais antigos (4.14+) também são compatíveis, mas será necessário construir o kernel manualmente.
O KernelSU oferece suporte oficial a dispositivos Android GKI 2.0 (kernel 5.10+). Kernels mais antigos (4.14+) também são compatíveis, mas o kernel terá que ser construído manualmente.
Com isso, WSA, ChromeOS e Android baseado em contêiner são todos suportados.
Atualmente, apenas as arquiteturas `arm64-v8a` e `x86_64` são compatíveis.
Atualmente, apenas `arm64-v8a` e `x86_64` são suportados.
## Uso
- [Instalação](https://kernelsu.org/pt_BR/guide/installation.html)
- [Como compilar](https://kernelsu.org/pt_BR/guide/how-to-build.html)
- [Como compilar o KernelSU?](https://kernelsu.org/pt_BR/guide/how-to-build.html)
- [Site oficial](https://kernelsu.org/pt_BR/)
## Tradução
Para contribuir com a tradução do KernelSU ou aprimorar traduções existentes, por favor, use o [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR para a tradução do Manager não são mais aceitas, pois podem entrar em conflito com o Weblate.
Para contribuir com a tradução do KernelSU ou aprimorar traduções existentes, por favor, utilize o [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR para a tradução do Gerenciador não são mais aceitas, pois podem entrar em conflito com o Weblate.
## Discussão
@@ -51,7 +51,7 @@ Para obter informações sobre como relatar vulnerabilidades de segurança do Ke
## Créditos
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): A ideia do KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): A poderosa ferramenta root.
- [genuine](https://github.com/brevent/genuine/): Validação de assinatura APK v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): Algumas habilidades de rootkit.
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): a ideia do KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): a poderosa ferramenta root.
- [genuine](https://github.com/brevent/genuine/): validação de assinatura apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): algumas habilidades de rootkit.

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -1,57 +1,56 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="標誌">
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
基於 Android 裝置核心的 Root 解決方案
基於核心的 Android 裝置 Root 解決方案
[![最新版本](https://img.shields.io/github/v/release/tiann/KernelSU?label=%e7%99%bc%e8%a1%8c%e7%89%88%e6%9c%ac&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/%e6%9c%ac%e5%9c%9f%e5%8c%96%e7%bf%bb%e8%ad%af-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![頻道](https://img.shields.io/badge/%e8%bf%bd%e8%b9%a4-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![授權條款:《GPL v2](https://img.shields.io/badge/%e6%8e%88%e6%ac%8a%e6%a2%9d%e6%ac%be-%E3%80%8AGPL%20v2%E3%80%8B-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub 授權條款](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## 特色功能
## 功能
1.核心 `su` 管理 Root 存取。
2. [OverlayFS](https://zh.wikipedia.org/zh-tw/OverlayFS) 運作模組系統。
3. [App Profile](https://kernelsu.org/zh_TW/guide/app-profile.html):使 Root 掌握的生殺大權受制於此。
- 基於核心 `su` Root 存取權管理
- 基於 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 模組系統。
- [App Profile](https://kernelsu.org/zh_TW/guide/app-profile.html): 將 Root 的權限鎖在牢籠中.
## 相容
## 相容性狀
理論上採以 Android GKI 2.0 的裝置核心版本 5.10+),皆受 KernelSU 支援採以老舊核心版本4.14+)的裝置在手動建置核心後,亦受支援
KernelSU 官方支援 Android GKI 2.0 的裝置 (核心版本 5.10+ );舊版核心同樣相容 (最低 4.14+ ),但需要自行編譯核心
另可在 WSAChromeOS 一類的容器式 Android 運作。
WSAChromeOS和執行在容器中的 Android 也可以與 KernelSU 一同運作。
目前僅適用 `arm64-v8a` 以及 `x86_64` 架構
目前支援架構:`arm64-v8a` `x86_64`
## 使用手冊
## 使用方法
- [安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
- [如何建置 KernelSU](https://kernelsu.org/zh_TW/guide/how-to-build.html)
- [如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
- [官方網站](https://kernelsu.org/zh_TW/)
## 多語翻譯
## 翻譯
要協助 KernelSU 邁向多語化,抑或改進翻譯品質,請前往 [Weblate](https://hosted.weblate.org/engage/kernelsu/) 進行翻譯。為避免與 Weblate 上的翻譯發生衝突,現已不再受理翻譯相關的管理工具 PR
要協助翻譯 KernelSU 或改進現有翻譯,請使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。 翻譯管理器的PR不再被接受因為它會與Weblate衝突
## 綜合討論
## 討論
- Telegram[@KernelSU](https://t.me/KernelSU)
## 安全政策
## 安全
有關報告 KernelSU 中的安全漏洞的資訊,請參閱 [SECURITY.md](/SECURITY.md)。
欲要得知、回報 KernelSU 的安全性漏洞,請參閱 [SECURITY.md](/SECURITY.md)。
## 授權
## 授權條款
- 目錄 `kernel` 下所有檔案為 [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。
-`kernel` 目錄的其他部分均為 [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。
- 位於 `kernel` 資料夾的檔案以[《GPL-2.0-only》](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)規範。
- 非位於 `kernel` 資料夾的其他檔案以[《GPL-3.0-or-later》](https://www.gnu.org/licenses/gpl-3.0.html)規範。
## 致謝
## 致謝名單
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU 的靈感來源
- [Magisk](https://github.com/topjohnwu/Magisk):強而有力的 Root 工具
- [genuine](https://github.com/brevent/genuine/):用於確效 Apk v2 簽章。
- [Diamorphine](https://github.com/m0nad/Diamorphine): 用於增進 Rootkit 技巧。
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU 的靈感。
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy 實作。
- [genuine](https://github.com/brevent/genuine/)apk v2 簽章驗證
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU

View File

@@ -10,12 +10,12 @@ yarn add kernelsu
### exec
Spawns a **root** shell and runs a command within that shell, returning a Promise that resolves with the `stdout` and `stderr` outputs upon completion.
Spawns a **root** shell and runs a command within that shell, passing the `stdout` and `stderr` to a Promise when complete.
- `command` `<string>` The command to run, with space-separated arguments.
- `options` `<Object>`
- `cwd` - Current working directory of the child process.
- `env` - Environment key-value pairs.
- `cwd` - Current working directory of the child process
- `env` - Environment key-value pairs
```javascript
import { exec } from 'kernelsu';
@@ -31,13 +31,13 @@ if (errno === 0) {
Spawns a new process using the given `command` in **root** shell, with command-line arguments in `args`. If omitted, `args` defaults to an empty array.
Returns a `ChildProcess` instance. Instances of `ChildProcess` represent spawned child processes.
Returns a `ChildProcess`, Instances of the ChildProcess represent spawned child processes.
- `command` `<string>` The command to run.
- `args` `<string[]>` List of string arguments.
- `options` `<Object>`:
- `cwd` `<string>` - Current working directory of the child process.
- `env` `<Object>` - Environment key-value pairs.
- `cwd` `<string>` - Current working directory of the child process
- `env` `<Object>` - Environment key-value pairs
Example of running `ls -lh /data`, capturing `stdout`, `stderr`, and the exit code:
@@ -63,9 +63,9 @@ ls.on('exit', (code) => {
##### Event 'exit'
- `code` `<number>` The exit code if the child process exited on its own.
- `code` `<number>` The exit code if the child exited on its own.
The `'exit'` event is emitted when the child process ends. If the process exits, `code` contains the final exit code; otherwise, it is null.
The `'exit'` event is emitted after the child process ends. If the process exited, `code` is the final exit code of the process, otherwise null
##### Event 'error'
@@ -109,13 +109,3 @@ Show a toast message.
import { toast } from 'kernelsu';
toast('Hello, world!');
```
### moduleInfo
Get module info.
```javascript
import { moduleInfo } from 'kernelsu';
// print moduleId in console
console.log(moduleInfo());
```

5
js/index.d.ts vendored
View File

@@ -37,12 +37,9 @@ declare function fullScreen(isFullScreen: boolean);
declare function toast(message: string);
declare function moduleInfo(): string;
export {
exec,
spawn,
fullScreen,
toast,
moduleInfo
toast
}

View File

@@ -113,7 +113,3 @@ export function fullScreen(isFullScreen) {
export function toast(message) {
ksu.toast(message);
}
export function moduleInfo() {
return ksu.moduleInfo();
}

View File

@@ -1,6 +1,6 @@
{
"name": "kernelsu",
"version": "1.0.7",
"version": "1.0.6",
"description": "Library for KernelSU's module WebUI",
"main": "index.js",
"types": "index.d.ts",

View File

@@ -1,4 +1,3 @@
#include <linux/capability.h>
#include <linux/compiler.h>
#include <linux/fs.h>
#include <linux/gfp.h>
@@ -63,14 +62,12 @@ static void remove_uid_from_arr(uid_t uid)
static void init_default_profiles()
{
kernel_cap_t full_cap = CAP_FULL_SET;
default_root_profile.uid = 0;
default_root_profile.gid = 0;
default_root_profile.groups_count = 1;
default_root_profile.groups[0] = 0;
memcpy(&default_root_profile.capabilities.effective, &full_cap,
sizeof(default_root_profile.capabilities.effective));
memset(&default_root_profile.capabilities, 0xff,
sizeof(default_root_profile.capabilities));
default_root_profile.namespaces = 0;
strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
@@ -111,7 +108,6 @@ void ksu_show_allow_list(void)
static void ksu_grant_root_to_shell()
{
struct app_profile profile = {
.version = KSU_APP_PROFILE_VER,
.allow_su = true,
.current_uid = 2000,
};
@@ -154,6 +150,11 @@ static bool profile_valid(struct app_profile *profile)
return false;
}
if (forbid_system_uid(profile->current_uid)) {
pr_err("uid lower than 2000 is unsupported: %d\n", profile->current_uid);
return false;
}
if (profile->version < KSU_APP_PROFILE_VER) {
pr_info("Unsupported profile version: %d\n", profile->version);
return false;

View File

@@ -15,7 +15,6 @@
#include <linux/sched.h>
#include <linux/security.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/uidgid.h>
@@ -49,10 +48,6 @@ static bool ksu_module_mounted = false;
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
static bool ksu_su_compat_enabled = true;
extern void ksu_sucompat_init();
extern void ksu_sucompat_exit();
static inline bool is_allow_su()
{
if (is_manager()) {
@@ -108,12 +103,49 @@ static void setup_groups(struct root_profile *profile, struct cred *cred)
groups_sort(group_info);
set_groups(cred, group_info);
put_group_info(group_info);
}
static void disable_seccomp()
void escape_to_root(void)
{
assert_spin_locked(&current->sighand->siglock);
struct cred *cred;
cred = (struct cred *)__task_cred(current);
if (cred->euid.val == 0) {
pr_warn("Already root, don't escape!\n");
return;
}
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
cred->uid.val = profile->uid;
cred->suid.val = profile->uid;
cred->euid.val = profile->uid;
cred->fsuid.val = profile->uid;
cred->gid.val = profile->gid;
cred->fsgid.val = profile->gid;
cred->sgid.val = profile->gid;
cred->egid.val = profile->gid;
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
sizeof(kernel_cap_t));
// setup capabilities
// we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
u64 cap_for_ksud =
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
memcpy(&cred->cap_effective, &cap_for_ksud,
sizeof(cred->cap_effective));
memcpy(&cred->cap_inheritable, &profile->capabilities.effective,
sizeof(cred->cap_inheritable));
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
sizeof(cred->cap_permitted));
memcpy(&cred->cap_bset, &profile->capabilities.effective,
sizeof(cred->cap_bset));
memcpy(&cred->cap_ambient, &profile->capabilities.effective,
sizeof(cred->cap_ambient));
// disable seccomp
#if defined(CONFIG_GENERIC_ENTRY) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
@@ -127,62 +159,9 @@ static void disable_seccomp()
current->seccomp.filter = NULL;
#else
#endif
}
void escape_to_root(void)
{
struct cred *cred;
cred = prepare_creds();
if (!cred) {
pr_warn("prepare_creds failed!\n");
return;
}
if (cred->euid.val == 0) {
pr_warn("Already root, don't escape!\n");
abort_creds(cred);
return;
}
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
cred->uid.val = profile->uid;
cred->suid.val = profile->uid;
cred->euid.val = profile->uid;
cred->fsuid.val = profile->uid;
cred->gid.val = profile->gid;
cred->fsgid.val = profile->gid;
cred->sgid.val = profile->gid;
cred->egid.val = profile->gid;
cred->securebits = 0;
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
sizeof(kernel_cap_t));
// setup capabilities
// we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
u64 cap_for_ksud =
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
memcpy(&cred->cap_effective, &cap_for_ksud,
sizeof(cred->cap_effective));
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
sizeof(cred->cap_permitted));
memcpy(&cred->cap_bset, &profile->capabilities.effective,
sizeof(cred->cap_bset));
setup_groups(profile, cred);
commit_creds(cred);
// Refer to kernel/seccomp.c: seccomp_set_mode_strict
// When disabling Seccomp, ensure that current->sighand->siglock is held during the operation.
spin_lock_irq(&current->sighand->siglock);
disable_seccomp();
spin_unlock_irq(&current->sighand->siglock);
setup_selinux(profile->selinux_domain);
}
@@ -214,7 +193,7 @@ int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
return 0;
}
if (!strstr(buf, "/system/packages.list")) {
if (strcmp(buf, "/system/packages.list")) {
return 0;
}
pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname,
@@ -225,26 +204,6 @@ int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
return 0;
}
static void nuke_ext4_sysfs() {
struct path path;
int err = kern_path("/data/adb/modules", 0, &path);
if (err) {
pr_err("nuke path err: %d\n", err);
return;
}
struct super_block* sb = path.dentry->d_inode->i_sb;
const char* name = sb->s_type->name;
if (strcmp(name, "ext4") != 0) {
pr_info("nuke but module aren't mounted\n");
path_put(&path);
return;
}
ext4_unregister_sysfs(sb);
path_put(&path);
}
int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
@@ -303,12 +262,12 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (copy_to_user(arg3, &version, sizeof(version))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
u32 version_flags = 0;
#ifdef MODULE
version_flags |= 0x1;
u32 is_lkm = 0x1;
#else
u32 is_lkm = 0x0;
#endif
if (arg4 &&
copy_to_user(arg4, &version_flags, sizeof(version_flags))) {
if (arg4 && copy_to_user(arg4, &is_lkm, sizeof(is_lkm))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
@@ -339,7 +298,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
case EVENT_MODULE_MOUNTED: {
ksu_module_mounted = true;
pr_info("module mounted!\n");
nuke_ext4_sysfs();
break;
}
default:
@@ -413,17 +371,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
if (arg2 == CMD_GET_MANAGER_UID) {
uid_t manager_uid = ksu_get_manager_uid();
if (copy_to_user(arg3, &manager_uid, sizeof(manager_uid))) {
pr_err("get manager uid failed\n");
}
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
}
// all other cmds are for 'root manager'
if (!from_manager) {
return 0;
@@ -466,42 +413,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
if (arg2 == CMD_IS_SU_ENABLED) {
if (copy_to_user(arg3, &ksu_su_compat_enabled,
sizeof(ksu_su_compat_enabled))) {
pr_err("copy su compat failed\n");
return 0;
}
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
}
if (arg2 == CMD_ENABLE_SU) {
bool enabled = (arg3 != 0);
if (enabled == ksu_su_compat_enabled) {
pr_info("cmd enable su but no need to change.\n");
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {// return the reply_ok directly
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
}
if (enabled) {
ksu_sucompat_init();
} else {
ksu_sucompat_exit();
}
ksu_su_compat_enabled = enabled;
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
}
return 0;
}
@@ -552,13 +463,11 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
if (path.dentry != path.mnt->mnt_root) {
// it is not root mountpoint, maybe umounted by others already.
path_put(&path);
return;
}
// we are only interest in some specific mounts
if (check_mnt && !should_umount(&path)) {
path_put(&path);
return;
}
@@ -619,15 +528,14 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
// filter the mountpoint whose target is `/data/adb`
try_umount("/odm", true, 0);
try_umount("/system", true, 0);
try_umount("/vendor", true, 0);
try_umount("/product", true, 0);
try_umount("/system_ext", true, 0);
try_umount("/data/adb/modules", false, MNT_DETACH);
// try umount ksu temp path
try_umount("/debug_ramdisk", false, MNT_DETACH);
try_umount("/sbin", false, MNT_DETACH);
return 0;
}

View File

@@ -21,9 +21,6 @@
#define CMD_SET_APP_PROFILE 11
#define CMD_UID_GRANTED_ROOT 12
#define CMD_UID_SHOULD_UMOUNT 13
#define CMD_IS_SU_ENABLED 14
#define CMD_ENABLE_SU 15
#define CMD_GET_MANAGER_UID 16
#define EVENT_POST_FS_DATA 1
#define EVENT_BOOT_COMPLETED 2

View File

@@ -19,24 +19,19 @@
static struct policydb *get_policydb(void)
{
struct policydb *db;
struct selinux_policy *policy = selinux_state.policy;
struct selinux_policy *policy = rcu_dereference(selinux_state.policy);
db = &policy->policydb;
return db;
}
static DEFINE_MUTEX(ksu_rules);
void apply_kernelsu_rules()
{
struct policydb *db;
if (!getenforce()) {
pr_info("SELinux permissive or disabled, apply rules!\n");
}
mutex_lock(&ksu_rules);
db = get_policydb();
rcu_read_lock();
struct policydb *db = get_policydb();
ksu_permissive(db, KERNEL_SU_DOMAIN);
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject");
@@ -123,11 +118,11 @@ void apply_kernelsu_rules()
// Allow all binder transactions
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL);
// Allow system server kill su process
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
// Allow system server kill su process
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
mutex_unlock(&ksu_rules);
rcu_read_unlock();
}
#define MAX_SEPOL_LEN 128
@@ -189,8 +184,6 @@ static void reset_avc_cache()
int handle_sepolicy(unsigned long arg3, void __user *arg4)
{
struct policydb *db;
if (!arg4) {
return -1;
}
@@ -208,9 +201,9 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
u32 cmd = data.cmd;
u32 subcmd = data.subcmd;
mutex_lock(&ksu_rules);
rcu_read_lock();
db = get_policydb();
struct policydb *db = get_policydb();
int ret = -1;
if (cmd == CMD_NORMAL_PERM) {
@@ -460,7 +453,7 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
}
exit:
mutex_unlock(&ksu_rules);
rcu_read_unlock();
// only allow and xallow needs to reset avc cache, but we cannot do that because
// we are in atomic context. so we just reset it every time.

View File

@@ -191,7 +191,7 @@ int ksu_handle_devpts(struct inode *inode)
#ifdef CONFIG_KPROBES
static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
static int sys_faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct pt_regs *real_regs = PT_REAL_REGS(regs);
int *dfd = (int *)&PT_REGS_PARM1(real_regs);
@@ -202,18 +202,17 @@ static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
return ksu_handle_faccessat(dfd, filename_user, mode, NULL);
}
static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
static int sys_newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct pt_regs *real_regs = PT_REAL_REGS(regs);
int *dfd = (int *)&PT_REGS_PARM1(real_regs);
const char __user **filename_user =
(const char **)&PT_REGS_PARM2(real_regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(real_regs);
int *flags = (int *)&PT_REGS_SYSCALL_PARM4(real_regs);
return ksu_handle_stat(dfd, filename_user, flags);
}
static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct pt_regs *real_regs = PT_REAL_REGS(regs);
const char __user **filename_user =
@@ -223,6 +222,21 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
NULL);
}
static struct kprobe faccessat_kp = {
.symbol_name = SYS_FACCESSAT_SYMBOL,
.pre_handler = sys_faccessat_handler_pre,
};
static struct kprobe newfstatat_kp = {
.symbol_name = SYS_NEWFSTATAT_SYMBOL,
.pre_handler = sys_newfstatat_handler_pre,
};
static struct kprobe execve_kp = {
.symbol_name = SYS_EXECVE_SYMBOL,
.pre_handler = sys_execve_handler_pre,
};
static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs)
{
struct inode *inode;
@@ -232,55 +246,35 @@ static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs)
return ksu_handle_devpts(inode);
}
static struct kprobe *init_kprobe(const char *name,
kprobe_pre_handler_t handler)
{
struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
if (!kp)
return NULL;
kp->symbol_name = name;
kp->pre_handler = handler;
static struct kprobe pts_unix98_lookup_kp = { .symbol_name =
"pts_unix98_lookup",
.pre_handler =
pts_unix98_lookup_pre };
int ret = register_kprobe(kp);
pr_info("sucompat: register_%s kprobe: %d\n", name, ret);
if (ret) {
kfree(kp);
return NULL;
}
return kp;
}
static void destroy_kprobe(struct kprobe **kp_ptr)
{
struct kprobe *kp = *kp_ptr;
if (!kp)
return;
unregister_kprobe(kp);
synchronize_rcu();
kfree(kp);
*kp_ptr = NULL;
}
static struct kprobe *su_kps[4];
#endif
// sucompat: permited process can execute 'su' to gain root access.
void ksu_sucompat_init()
{
#ifdef CONFIG_KPROBES
su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre);
su_kps[1] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre);
su_kps[2] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre);
su_kps[3] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre);
int ret;
ret = register_kprobe(&execve_kp);
pr_info("sucompat: execve_kp: %d\n", ret);
ret = register_kprobe(&newfstatat_kp);
pr_info("sucompat: newfstatat_kp: %d\n", ret);
ret = register_kprobe(&faccessat_kp);
pr_info("sucompat: faccessat_kp: %d\n", ret);
ret = register_kprobe(&pts_unix98_lookup_kp);
pr_info("sucompat: devpts_kp: %d\n", ret);
#endif
}
void ksu_sucompat_exit()
{
#ifdef CONFIG_KPROBES
for (int i = 0; i < ARRAY_SIZE(su_kps); i++) {
destroy_kprobe(&su_kps[i]);
}
unregister_kprobe(&execve_kp);
unregister_kprobe(&newfstatat_kp);
unregister_kprobe(&faccessat_kp);
unregister_kprobe(&pts_unix98_lookup_kp);
#endif
}

View File

@@ -148,12 +148,6 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
if (!strncmp(name, "..", namelen) || !strncmp(name, ".", namelen))
return FILLDIR_ACTOR_CONTINUE; // Skip "." and ".."
if (d_type == DT_DIR && namelen >= 8 && !strncmp(name, "vmdl", 4) &&
!strncmp(name + namelen - 4, ".tmp", 4)) {
pr_info("Skipping directory: %.*s\n", namelen, name);
return FILLDIR_ACTOR_CONTINUE; // Skip staging package
}
if (snprintf(dirpath, DATA_PATH_LEN, "%s/%.*s", my_ctx->parent_dir,
namelen, name) >= DATA_PATH_LEN) {
pr_err("Path too long: %s/%.*s\n", my_ctx->parent_dir, namelen,
@@ -213,8 +207,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
int i, stop = 0;
struct list_head data_path_list;
INIT_LIST_HEAD(&data_path_list);
unsigned long data_app_magic = 0;
// Initialize APK cache list
struct apk_path_hash *pos, *n;
list_for_each_entry(pos, &apk_path_hash_list, list) {
@@ -227,7 +220,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
data.depth = depth;
list_add_tail(&data.list, &data_path_list);
for (i = depth; i >= 0; i--) {
for (i = depth; i > 0; i--) {
struct data_path *pos, *n;
list_for_each_entry_safe(pos, n, &data_path_list, list) {
@@ -245,24 +238,6 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file));
goto skip_iterate;
}
// grab magic on first folder, which is /data/app
if (!data_app_magic) {
if (file->f_inode->i_sb->s_magic) {
data_app_magic = file->f_inode->i_sb->s_magic;
pr_info("%s: dir: %s got magic! 0x%lx\n", __func__, pos->dirpath, data_app_magic);
} else {
filp_close(file, NULL);
goto skip_iterate;
}
}
if (file->f_inode->i_sb->s_magic != data_app_magic) {
pr_info("%s: skip: %s magic: 0x%lx expected: 0x%lx\n", __func__, pos->dirpath,
file->f_inode->i_sb->s_magic, data_app_magic);
filp_close(file, NULL);
goto skip_iterate;
}
iterate_dir(file, &ctx.ctx);
filp_close(file, NULL);
@@ -376,14 +351,12 @@ void track_throne()
if (ksu_is_manager_uid_valid()) {
pr_info("manager is uninstalled, invalidate it!\n");
ksu_invalidate_manager_uid();
goto prune;
}
pr_info("Searching manager...\n");
search_manager("/data/app", 2, &uid_list);
pr_info("Search manager finished\n");
}
prune:
// then prune the allowlist
ksu_prune_allowlist(is_uid_exist, &uid_list);
out:

3
manager/.gitignore vendored
View File

@@ -1,10 +1,9 @@
*.iml
.gradle
local.properties
.idea
.kotlin
.DS_Store
build
captures
.cxx
local.properties
key.jks

View File

@@ -1,7 +1,4 @@
@file:Suppress("UnstableApiUsage")
import com.android.build.gradle.internal.api.BaseVariantOutputImpl
import com.android.build.gradle.tasks.PackageAndroidArtifact
plugins {
alias(libs.plugins.agp.app)
@@ -49,13 +46,7 @@ android {
useLegacyPackaging = true
}
resources {
// https://stackoverflow.com/a/58956288
// It will break Layout Inspector, but it's unused for release build.
excludes += "META-INF/*.version"
// https://github.com/Kotlin/kotlinx.coroutines?tab=readme-ov-file#avoiding-including-the-debug-infrastructure-in-the-resulting-apk
excludes += "DebugProbesKt.bin"
// https://issueantenna.com/repo/kotlin/kotlinx.coroutines/issues/3158
excludes += "kotlin-tooling-metadata.json"
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
@@ -70,30 +61,13 @@ android {
val output = it as BaseVariantOutputImpl
output.outputFileName = "KernelSU_${managerVersionName}_${managerVersionCode}-$name.apk"
}
kotlin.sourceSets {
getByName(name) {
kotlin.srcDir("build/generated/ksp/$name/kotlin")
}
}
}
// https://stackoverflow.com/a/77745844
tasks.withType<PackageAndroidArtifact> {
doFirst { appMetadata.asFile.orNull?.writeText("") }
}
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
androidResources {
generateLocaleConfig = true
}
}
ksp {
arg("compose-destinations.defaultTransitions", "none")
}
dependencies {
@@ -114,7 +88,12 @@ dependencies {
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.compose.destinations.core)
implementation(libs.com.google.accompanist.drawablepainter)
implementation(libs.com.google.accompanist.navigation.animation)
implementation(libs.com.google.accompanist.systemuicontroller)
implementation(libs.com.google.accompanist.webview)
implementation(libs.compose.destinations.animations.core)
ksp(libs.compose.destinations.ksp)
implementation(libs.com.github.topjohnwu.libsu.core)

View File

@@ -0,0 +1,9 @@
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.conscrypt.Conscrypt$Version
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.conscrypt.ConscryptHostnameVerifier
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE

View File

@@ -12,8 +12,8 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/Theme.KernelSU"
tools:targetApi="34">
<activity
@@ -22,12 +22,16 @@
android:theme="@style/Theme.KernelSU">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".ui.webui.WebUIActivity"
<activity android:name=".ui.webui.WebUIActivity"
android:autoRemoveFromRecents="true"
android:documentLaunchMode="intoExisting"
android:exported="false"

View File

@@ -295,14 +295,4 @@ extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_uidShouldUmount(JNIEnv *env, jobject thiz, jint uid) {
return uid_should_umount(uid);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_isSuEnabled(JNIEnv *env, jobject thiz) {
return is_su_enabled();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_setSuEnabled(JNIEnv *env, jobject thiz, jboolean enabled) {
return set_su_enabled(enabled);
}

View File

@@ -27,8 +27,6 @@
#define CMD_IS_UID_GRANTED_ROOT 12
#define CMD_IS_UID_SHOULD_UMOUNT 13
#define CMD_IS_SU_ENABLED 14
#define CMD_ENABLE_SU 15
static bool ksuctl(int cmd, void* arg1, void* arg2) {
int32_t result = 0;
@@ -50,13 +48,12 @@ bool become_manager(const char* pkg) {
}
// cache the result to avoid unnecessary syscall
static bool is_lkm = false;
int get_version(void) {
static bool is_lkm;
int get_version() {
int32_t version = -1;
int32_t flags = 0;
ksuctl(CMD_GET_VERSION, &version, &flags);
if (!is_lkm && (flags & 0x1)) {
int32_t lkm = 0;
ksuctl(CMD_GET_VERSION, &version, &lkm);
if (!is_lkm && lkm != 0) {
is_lkm = true;
}
return version;
@@ -87,14 +84,3 @@ bool set_app_profile(const app_profile *profile) {
bool get_app_profile(p_key_t key, app_profile *profile) {
return ksuctl(CMD_GET_APP_PROFILE, (void*) profile, nullptr);
}
bool set_su_enabled(bool enabled) {
return ksuctl(CMD_ENABLE_SU, (void*) enabled, nullptr);
}
bool is_su_enabled() {
bool enabled = true;
// if ksuctl failed, we assume su is enabled, and it cannot be disabled.
ksuctl(CMD_IS_SU_ENABLED, &enabled, nullptr);
return enabled;
}

View File

@@ -79,8 +79,4 @@ bool set_app_profile(const app_profile *profile);
bool get_app_profile(p_key_t key, app_profile *profile);
bool set_su_enabled(bool enabled);
bool is_su_enabled();
#endif //KERNELSU_KSU_H

View File

@@ -1,22 +1,16 @@
package me.weishu.kernelsu
import android.app.Application
import android.system.Os
import coil.Coil
import coil.ImageLoader
import me.zhanghai.android.appiconloader.coil.AppIconFetcher
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
import okhttp3.Cache
import okhttp3.OkHttpClient
import java.io.File
import java.util.Locale
lateinit var ksuApp: KernelSUApplication
class KernelSUApplication : Application() {
lateinit var okhttpClient: OkHttpClient
override fun onCreate() {
super.onCreate()
ksuApp = this
@@ -36,20 +30,7 @@ class KernelSUApplication : Application() {
if (!webroot.exists()) {
webroot.mkdir()
}
// Provide working env for rust's temp_dir()
Os.setenv("TMPDIR", cacheDir.absolutePath, true)
okhttpClient =
OkHttpClient.Builder().cache(Cache(File(cacheDir, "okhttp"), 10 * 1024 * 1024))
.addInterceptor { block ->
block.proceed(
block.request().newBuilder()
.header("User-Agent", "KernelSU/${BuildConfig.VERSION_CODE}")
.header("Accept-Language", Locale.getDefault().toLanguageTag()).build()
)
}.build()
}
}
}

View File

@@ -21,9 +21,6 @@ object Natives {
// 11640: Support query working mode, LKM or GKI
// when MINIMAL_SUPPORTED_KERNEL > 11640, we can remove this constant.
const val MINIMAL_SUPPORTED_KERNEL_LKM = 11648
// 12040: Support disable sucompat mode
const val MINIMAL_SUPPORTED_SU_COMPAT = 12040
const val KERNEL_SU_DOMAIN = "u:r:su:s0"
const val ROOT_UID = 0
@@ -58,15 +55,6 @@ object Natives {
external fun getAppProfile(key: String?, uid: Int): Profile
external fun setAppProfile(profile: Profile?): Boolean
/**
* `su` compat mode can be disabled temporarily.
* 0: disabled
* 1: enabled
* negative : error
*/
external fun isSuEnabled(): Boolean
external fun setSuEnabled(enabled: Boolean): Boolean
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
private const val NOBODY_UID = 9999

View File

@@ -1,30 +1,14 @@
package me.weishu.kernelsu.ui
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.union
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -34,96 +18,39 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationStyle
import com.ramcosta.composedestinations.generated.NavGraphs
import com.ramcosta.composedestinations.navigation.popBackStack
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.screen.BottomBarDestination
import me.weishu.kernelsu.ui.screen.NavGraphs
import me.weishu.kernelsu.ui.theme.KernelSUTheme
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.rootAvailable
import me.weishu.kernelsu.ui.util.install
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Enable edge to edge
enableEdgeToEdge()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
window.isNavigationBarContrastEnforced = false
}
super.onCreate(savedInstanceState)
val isManager = Natives.becomeManager(ksuApp.packageName)
if (isManager) install()
setContent {
KernelSUTheme {
val navController = rememberNavController()
val snackBarHostState = remember { SnackbarHostState() }
val bottomBarRoutes = remember {
BottomBarDestination.entries.map { it.direction.route }.toSet()
}
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
bottomBar = { BottomBar(navController) },
contentWindowInsets = WindowInsets(0, 0, 0, 0)
snackbarHost = { SnackbarHost(snackbarHostState) }
) { innerPadding ->
CompositionLocalProvider(
LocalSnackbarHost provides snackBarHostState,
LocalSnackbarHost provides snackbarHostState,
) {
DestinationsNavHost(
modifier = Modifier.padding(innerPadding),
navGraph = NavGraphs.root,
navController = navController,
defaultTransitions = object : NavHostAnimatedDestinationStyle() {
override val enterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition = {
// If the target is a detail page (not a bottom navigation page), slide in from the right
if (targetState.destination.route !in bottomBarRoutes) {
slideInHorizontally(initialOffsetX = { it })
} else {
// Otherwise (switching between bottom navigation pages), use fade in
fadeIn(animationSpec = tween(340))
}
}
override val exitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition = {
// If navigating from the home page (bottom navigation page) to a detail page, slide out to the left
if (initialState.destination.route in bottomBarRoutes && targetState.destination.route !in bottomBarRoutes) {
slideOutHorizontally(targetOffsetX = { -it / 4 }) + fadeOut()
} else {
// Otherwise (switching between bottom navigation pages), use fade out
fadeOut(animationSpec = tween(340))
}
}
override val popEnterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition = {
// If returning to the home page (bottom navigation page), slide in from the left
if (targetState.destination.route in bottomBarRoutes) {
slideInHorizontally(initialOffsetX = { -it / 4 }) + fadeIn()
} else {
// Otherwise (e.g., returning between multiple detail pages), use default fade in
fadeIn(animationSpec = tween(340))
}
}
override val popExitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition = {
// If returning from a detail page (not a bottom navigation page), scale down and fade out
if (initialState.destination.route !in bottomBarRoutes) {
scaleOut(targetScale = 0.9f) + fadeOut()
} else {
// Otherwise, use default fade out
fadeOut(animationSpec = tween(340))
}
}
}
navController = navController
)
}
}
@@ -134,15 +61,9 @@ class MainActivity : ComponentActivity() {
@Composable
private fun BottomBar(navController: NavHostController) {
val navigator = navController.rememberDestinationsNavigator()
val isManager = Natives.becomeManager(ksuApp.packageName)
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
NavigationBar(
tonalElevation = 8.dp,
windowInsets = WindowInsets.systemBars.union(WindowInsets.displayCutout).only(
WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom
)
) {
NavigationBar(tonalElevation = 8.dp) {
BottomBarDestination.entries.forEach { destination ->
if (!fullFeatured && destination.rootRequired) return@forEach
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
@@ -150,10 +71,11 @@ private fun BottomBar(navController: NavHostController) {
selected = isCurrentDestOnBackStack,
onClick = {
if (isCurrentDestOnBackStack) {
navigator.popBackStack(destination.direction, false)
navController.popBackStack(destination.direction, false)
}
navigator.navigate(destination.direction) {
popUpTo(NavGraphs.root) {
navController.navigate(destination.direction.route) {
popUpTo(NavGraphs.root.route) {
saveState = true
}
launchSingleTop = true

View File

@@ -1,5 +1,7 @@
package me.weishu.kernelsu.ui.component
import android.text.method.LinkMovementMethod
import android.widget.TextView
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -9,28 +11,24 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.fromHtml
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.window.Dialog
import androidx.core.content.res.ResourcesCompat
import androidx.core.text.HtmlCompat
import com.google.accompanist.drawablepainter.rememberDrawablePainter
import me.weishu.kernelsu.BuildConfig
import me.weishu.kernelsu.R
@@ -38,8 +36,9 @@ import me.weishu.kernelsu.R
@Composable
fun AboutCard() {
ElevatedCard(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp)
modifier = Modifier
.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
) {
Row(
modifier = Modifier
@@ -53,9 +52,7 @@ fun AboutCard() {
@Composable
fun AboutDialog(dismiss: () -> Unit) {
Dialog(
onDismissRequest = { dismiss() }
) {
Dialog(onDismissRequest = { dismiss() }) {
AboutCard()
}
}
@@ -63,20 +60,21 @@ fun AboutDialog(dismiss: () -> Unit) {
@Composable
private fun AboutCardContent() {
Column(
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.fillMaxWidth()
) {
val drawable = ResourcesCompat.getDrawable(
LocalContext.current.resources,
R.mipmap.ic_launcher,
LocalContext.current.theme
)
Row {
Surface(
modifier = Modifier.size(40.dp),
color = colorResource(id = R.color.ic_launcher_background),
shape = CircleShape
) {
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = "icon",
modifier = Modifier.scale(1.4f)
)
}
Image(
painter = rememberDrawablePainter(drawable),
contentDescription = "icon",
modifier = Modifier.size(40.dp)
)
Spacer(modifier = Modifier.width(12.dp))
@@ -95,31 +93,31 @@ private fun AboutCardContent() {
Spacer(modifier = Modifier.height(8.dp))
val annotatedString = AnnotatedString.Companion.fromHtml(
htmlString = stringResource(
HtmlText(
html = stringResource(
id = R.string.about_source_code,
"<b><a href=\"https://github.com/tiann/KernelSU\">GitHub</a></b>",
"<b><a href=\"https://t.me/KernelSU\">Telegram</a></b>"
),
linkStyles = TextLinkStyles(
style = SpanStyle(
color = MaterialTheme.colorScheme.primary,
textDecoration = TextDecoration.Underline
),
pressedStyle = SpanStyle(
color = MaterialTheme.colorScheme.primary,
background = MaterialTheme.colorScheme.secondaryContainer,
textDecoration = TextDecoration.Underline
)
)
)
Text(
text = annotatedString,
style = TextStyle(
fontSize = 14.sp
)
)
}
}
}
}
@Composable
fun HtmlText(html: String, modifier: Modifier = Modifier) {
val contentColor = LocalContentColor.current
AndroidView(
modifier = modifier,
factory = { context ->
TextView(context).also {
it.movementMethod = LinkMovementMethod.getInstance()
}
},
update = {
it.text = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_COMPACT)
it.setTextColor(contentColor.toArgb())
}
)
}

View File

@@ -1,7 +1,6 @@
package me.weishu.kernelsu.ui.component
import android.graphics.text.LineBreaker
import android.os.Build
import android.os.Parcelable
import android.text.Layout
import android.text.method.LinkMovementMethod
@@ -97,8 +96,8 @@ interface ConfirmDialogHandle : DialogHandle {
}
private abstract class DialogHandleBase(
val visible: MutableState<Boolean>,
val coroutineScope: CoroutineScope
protected val visible: MutableState<Boolean>,
protected val coroutineScope: CoroutineScope
) : DialogHandle {
override val isShown: Boolean
get() = visible.value
@@ -433,9 +432,7 @@ private fun MarkdownContent(content: String) {
TextView(context).apply {
movementMethod = LinkMovementMethod.getInstance()
setSpannableFactory(NoCopySpannableFactory.getInstance())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
breakStrategy = LineBreaker.BREAK_STRATEGY_SIMPLE
}
breakStrategy = LineBreaker.BREAK_STRATEGY_SIMPLE
hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT

View File

@@ -1,17 +0,0 @@
package me.weishu.kernelsu.ui.component
import androidx.compose.runtime.Composable
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
@Composable
fun KsuIsValid(
content: @Composable () -> Unit
) {
val isManager = Natives.becomeManager(ksuApp.packageName)
val ksuVersion = if (isManager) Natives.version else null
if (ksuVersion != null) {
content()
}
}

View File

@@ -5,12 +5,8 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
@@ -23,7 +19,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -53,7 +48,6 @@ fun SearchAppBar(
onBackClick: (() -> Unit)? = null,
onConfirm: (() -> Unit)? = null,
dropdownContent: @Composable (() -> Unit)? = null,
scrollBehavior: TopAppBarScrollBehavior? = null
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember { FocusRequester() }
@@ -138,13 +132,10 @@ fun SearchAppBar(
dropdownContent()
}
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
}
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun SearchAppBarPreview() {

View File

@@ -1,18 +1,14 @@
package me.weishu.kernelsu.ui.component
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.clickable
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.semantics.Role
@Composable
fun SwitchItem(
@@ -23,18 +19,10 @@ fun SwitchItem(
enabled: Boolean = true,
onCheckedChange: (Boolean) -> Unit
) {
val interactionSource = remember { MutableInteractionSource() }
ListItem(
modifier = Modifier
.toggleable(
value = checked,
interactionSource = interactionSource,
role = Role.Switch,
enabled = enabled,
indication = LocalIndication.current,
onValueChange = onCheckedChange
),
modifier = Modifier.clickable {
onCheckedChange.invoke(!checked)
},
headlineContent = {
Text(title)
},
@@ -42,12 +30,7 @@ fun SwitchItem(
{ Icon(icon, title) }
},
trailingContent = {
Switch(
checked = checked,
enabled = enabled,
onCheckedChange = onCheckedChange,
interactionSource = interactionSource
)
Switch(checked = checked, enabled = enabled, onCheckedChange = onCheckedChange)
},
supportingContent = {
if (summary != null) {
@@ -69,6 +52,6 @@ fun RadioItem(
},
leadingContent = {
RadioButton(selected = selected, onClick = onClick)
}
},
)
}

View File

@@ -1,10 +1,11 @@
@file:OptIn(ExperimentalMaterial3Api::class)
package me.weishu.kernelsu.ui.component.profile
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
@@ -19,14 +20,12 @@ import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@@ -73,7 +72,6 @@ fun RootProfileConfig(
)
}
/*
var expanded by remember { mutableStateOf(false) }
val currentNamespace = when (profile.namespace) {
Natives.Profile.Namespace.INHERITED.ordinal -> stringResource(R.string.profile_namespace_inherited)
@@ -88,7 +86,7 @@ fun RootProfileConfig(
) {
OutlinedTextField(
modifier = Modifier
.menuAnchor(MenuAnchorType.PrimaryNotEditable)
.menuAnchor()
.fillMaxWidth(),
readOnly = true,
label = { Text(stringResource(R.string.profile_namespace)) },
@@ -127,7 +125,6 @@ fun RootProfileConfig(
}
}
})
*/
UidPanel(uid = profile.uid, label = "uid", onUidChange = {
onProfileChange(
@@ -187,7 +184,7 @@ fun RootProfileConfig(
}
}
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>) -> Unit) {
val selectGroupsDialog = rememberCustomDialog { dismiss: () -> Unit ->
@@ -237,20 +234,14 @@ fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>)
)
}
OutlinedCard(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
OutlinedCard(modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable {
selectGroupsDialog.show()
}) {
Column(
modifier = Modifier
.fillMaxSize()
.clickable {
selectGroupsDialog.show()
}
.padding(16.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(stringResource(R.string.profile_groups))
FlowRow {
selected.forEach { group ->
@@ -265,7 +256,7 @@ fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>)
}
}
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun CapsPanel(
selected: Collection<Capabilities>,
@@ -308,20 +299,14 @@ fun CapsPanel(
)
}
OutlinedCard(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
OutlinedCard(modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable {
selectCapabilitiesDialog.show()
}) {
Column(
modifier = Modifier
.fillMaxSize()
.clickable {
selectCapabilitiesDialog.show()
}
.padding(16.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(stringResource(R.string.profile_capabilities))
FlowRow {
selected.forEach { group ->
@@ -344,10 +329,10 @@ private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
mutableStateOf(false)
}
var lastValidUid by remember {
mutableIntStateOf(uid)
mutableStateOf(uid)
}
val keyboardController = LocalSoftwareKeyboardController.current
val keyboardController = LocalSoftwareKeyboardController.current
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
label = { Text(label) },
@@ -380,7 +365,6 @@ private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
})
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun SELinuxPanel(
profile: Natives.Profile,
@@ -468,7 +452,7 @@ private fun SELinuxPanel(
),
label = { Text(text = stringResource(R.string.profile_selinux_context)) },
value = profile.context,
onValueChange = { }
onValueChange = { },
)
})
}

View File

@@ -12,7 +12,6 @@ import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -55,7 +54,7 @@ fun TemplateConfig(
) {
OutlinedTextField(
modifier = Modifier
.menuAnchor(MenuAnchorType.PrimaryNotEditable)
.menuAnchor()
.fillMaxWidth(),
readOnly = true,
label = { Text(stringResource(R.string.profile_template)) },

View File

@@ -7,14 +7,10 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@@ -32,11 +28,8 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -46,7 +39,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
@@ -55,13 +47,9 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.dropUnlessResumed
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
@@ -70,6 +58,8 @@ import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.profile.AppProfileConfig
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
import me.weishu.kernelsu.ui.component.profile.TemplateConfig
import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
import me.weishu.kernelsu.ui.screen.destinations.TemplateEditorScreenDestination
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.forceStopApp
import me.weishu.kernelsu.ui.util.getSepolicy
@@ -83,20 +73,19 @@ import me.weishu.kernelsu.ui.viewmodel.getTemplateInfoById
* @author weishu
* @date 2023/5/16.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@Destination
@Composable
fun AppProfileScreen(
navigator: DestinationsNavigator,
appInfo: SuperUserViewModel.AppInfo,
) {
val context = LocalContext.current
val snackBarHost = LocalSnackbarHost.current
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
val snackbarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val failToUpdateAppProfile = stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
val failToUpdateSepolicy = stringResource(R.string.failed_to_update_sepolicy).format(appInfo.label)
val suNotAllowed = stringResource(R.string.su_not_allowed).format(appInfo.label)
val failToUpdateAppProfile =
stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
val failToUpdateSepolicy =
stringResource(R.string.failed_to_update_sepolicy).format(appInfo.label)
val packageName = appInfo.packageName
val initialProfile = Natives.getAppProfile(packageName, appInfo.uid)
@@ -108,25 +97,18 @@ fun AppProfileScreen(
}
Scaffold(
topBar = {
TopBar(
onBack = dropUnlessResumed { navigator.popBackStack() },
scrollBehavior = scrollBehavior
)
},
snackbarHost = { SnackbarHost(hostState = snackBarHost) },
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
topBar = { TopBar { navigator.popBackStack() } },
) { paddingValues ->
AppProfileInner(
modifier = Modifier
.padding(paddingValues)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState()),
packageName = appInfo.packageName,
appLabel = appInfo.label,
appIcon = {
AsyncImage(
model = ImageRequest.Builder(context).data(appInfo.packageInfo).crossfade(true).build(),
model = ImageRequest.Builder(context).data(appInfo.packageInfo).crossfade(true)
.build(),
contentDescription = appInfo.label,
modifier = Modifier
.padding(4.dp)
@@ -145,19 +127,14 @@ fun AppProfileScreen(
},
onProfileChange = {
scope.launch {
if (it.allowSu) {
// sync with allowlist.c - forbid_system_uid
if (appInfo.uid < 2000 && appInfo.uid != 1000) {
snackBarHost.showSnackbar(suNotAllowed)
return@launch
}
if (!it.rootUseDefault && it.rules.isNotEmpty() && !setSepolicy(profile.name, it.rules)) {
snackBarHost.showSnackbar(failToUpdateSepolicy)
if (it.allowSu && !it.rootUseDefault && it.rules.isNotEmpty()) {
if (!setSepolicy(profile.name, it.rules)) {
snackbarHost.showSnackbar(failToUpdateSepolicy)
return@launch
}
}
if (!Natives.setAppProfile(it)) {
snackBarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid))
snackbarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid))
} else {
profile = it
}
@@ -197,9 +174,7 @@ private fun AppProfileInner(
)
Crossfade(targetState = isRootGranted, label = "") { current ->
Column(
modifier = Modifier.padding(bottom = 6.dp + 48.dp + 6.dp /* SnackBar height */)
) {
Column {
if (current) {
val initialMode = if (profile.rootUseDefault) {
Mode.Default
@@ -263,10 +238,7 @@ private enum class Mode(@StringRes private val res: Int) {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(
onBack: () -> Unit,
scrollBehavior: TopAppBarScrollBehavior? = null
) {
private fun TopBar(onBack: () -> Unit) {
TopAppBar(
title = {
Text(stringResource(R.string.profile))
@@ -276,8 +248,6 @@ private fun TopBar(
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
)
}
@@ -333,8 +303,7 @@ private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) {
touchPoint = it
expanded = true
}
}
) {
}) {
content()

View File

@@ -5,11 +5,11 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.*
import androidx.compose.ui.graphics.vector.ImageVector
import com.ramcosta.composedestinations.generated.destinations.HomeScreenDestination
import com.ramcosta.composedestinations.generated.destinations.ModuleScreenDestination
import com.ramcosta.composedestinations.generated.destinations.SuperUserScreenDestination
import com.ramcosta.composedestinations.spec.DirectionDestinationSpec
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.screen.destinations.HomeScreenDestination
import me.weishu.kernelsu.ui.screen.destinations.SuperUserScreenDestination
import me.weishu.kernelsu.ui.screen.destinations.ModuleScreenDestination
enum class BottomBarDestination(
val direction: DirectionDestinationSpec,

View File

@@ -1,150 +0,0 @@
package me.weishu.kernelsu.ui.screen
import android.os.Environment
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.dropUnlessResumed
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.KeyEventBlocker
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.runModuleAction
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@Composable
@Destination<RootGraph>
fun ExecuteModuleActionScreen(navigator: DestinationsNavigator, moduleId: String) {
var text by rememberSaveable { mutableStateOf("") }
var tempText : String
val logContent = rememberSaveable { StringBuilder() }
val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val scrollState = rememberScrollState()
var actionResult: Boolean
LaunchedEffect(Unit) {
if (text.isNotEmpty()) {
return@LaunchedEffect
}
withContext(Dispatchers.IO) {
runModuleAction(
moduleId = moduleId,
onStdout = {
tempText = "$it\n"
if (tempText.startsWith("")) { // clear command
text = tempText.substring(6)
} else {
text += tempText
}
logContent.append(it).append("\n")
},
onStderr = {
logContent.append(it).append("\n")
}
).let {
actionResult = it
}
}
if (actionResult) navigator.popBackStack()
}
Scaffold(
topBar = {
TopBar(
onBack = dropUnlessResumed {
navigator.popBackStack()
},
onSave = {
scope.launch {
val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault())
val date = format.format(Date())
val file = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"KernelSU_module_action_log_${date}.log"
)
file.writeText(logContent.toString())
snackBarHost.showSnackbar("Log saved to ${file.absolutePath}")
}
}
)
},
snackbarHost = { SnackbarHost(snackBarHost) }
) { innerPadding ->
KeyEventBlocker {
it.key == Key.VolumeDown || it.key == Key.VolumeUp
}
Column(
modifier = Modifier
.fillMaxSize(1f)
.padding(innerPadding)
.verticalScroll(scrollState),
) {
LaunchedEffect(text) {
scrollState.animateScrollTo(scrollState.maxValue)
}
Text(
modifier = Modifier.padding(8.dp),
text = text,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = FontFamily.Monospace,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
TopAppBar(
title = { Text(stringResource(R.string.action)) },
navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
},
actions = {
IconButton(onClick = onSave) {
Icon(
imageVector = Icons.Filled.Save,
contentDescription = stringResource(id = R.string.save_log),
)
}
}
)
}

View File

@@ -4,12 +4,8 @@ import android.net.Uri
import android.os.Environment
import android.os.Parcelable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
@@ -22,12 +18,8 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -38,14 +30,11 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.dropUnlessResumed
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
@@ -54,7 +43,6 @@ import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.KeyEventBlocker
import me.weishu.kernelsu.ui.util.FlashResult
import me.weishu.kernelsu.ui.util.LkmSelection
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.flashModule
@@ -67,47 +55,27 @@ import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
/**
* @author weishu
* @date 2023/1/1.
*/
enum class FlashingStatus {
FLASHING,
SUCCESS,
FAILED
}
// Lets you flash modules sequentially when mutiple zipUris are selected
fun flashModulesSequentially(
uris: List<Uri>,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit
): FlashResult {
for (uri in uris) {
flashModule(uri, onStdout, onStderr).apply {
if (code != 0) {
return FlashResult(code, err, showReboot)
}
}
}
return FlashResult(0, "", true)
}
@OptIn(ExperimentalMaterial3Api::class)
/**
* @author weishu
* @date 2023/1/1.
*/
@Composable
@Destination<RootGraph>
@Destination
fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
var text by rememberSaveable { mutableStateOf("") }
var tempText: String
val logContent = rememberSaveable { StringBuilder() }
var showFloatAction by rememberSaveable { mutableStateOf(false) }
val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val scrollState = rememberScrollState()
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
var flashing by rememberSaveable {
mutableStateOf(FlashingStatus.FLASHING)
}
@@ -117,26 +85,21 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
return@LaunchedEffect
}
withContext(Dispatchers.IO) {
flashIt(flashIt, onStdout = {
tempText = "$it\n"
if (tempText.startsWith("")) { // clear command
text = tempText.substring(6)
} else {
text += tempText
}
logContent.append(it).append("\n")
}, onStderr = {
logContent.append(it).append("\n")
}).apply {
flashIt(flashIt, onFinish = { showReboot, code ->
if (code != 0) {
text += "Error code: $code.\n $err Please save and check the log.\n"
text += "Error: exit code = $code.\nPlease save and check the log.\n"
}
if (showReboot) {
text += "\n\n\n"
showFloatAction = true
}
flashing = if (code == 0) FlashingStatus.SUCCESS else FlashingStatus.FAILED
}
}, onStdout = {
text += "$it\n"
logContent.append(it).append("\n")
}, onStderr = {
logContent.append(it).append("\n")
})
}
}
@@ -144,7 +107,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
topBar = {
TopBar(
flashing,
onBack = dropUnlessResumed {
onBack = {
navigator.popBackStack()
},
onSave = {
@@ -158,8 +121,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
file.writeText(logContent.toString())
snackBarHost.showSnackbar("Log saved to ${file.absolutePath}")
}
},
scrollBehavior = scrollBehavior
}
)
},
floatingActionButton = {
@@ -177,9 +139,8 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
text = { Text(text = reboot) },
)
}
},
snackbarHost = { SnackbarHost(hostState = snackBarHost) },
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
}
) { innerPadding ->
KeyEventBlocker {
it.key == Key.VolumeDown || it.key == Key.VolumeUp
@@ -188,7 +149,6 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
modifier = Modifier
.fillMaxSize(1f)
.padding(innerPadding)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(scrollState),
) {
LaunchedEffect(text) {
@@ -210,7 +170,7 @@ sealed class FlashIt : Parcelable {
data class FlashBoot(val boot: Uri? = null, val lkm: LkmSelection, val ota: Boolean) :
FlashIt()
data class FlashModules(val uris: List<Uri>) : FlashIt()
data class FlashModule(val uri: Uri) : FlashIt()
data object FlashRestore : FlashIt()
@@ -218,37 +178,31 @@ sealed class FlashIt : Parcelable {
}
fun flashIt(
flashIt: FlashIt,
flashIt: FlashIt, onFinish: (Boolean, Int) -> Unit,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit
): FlashResult {
return when (flashIt) {
) {
when (flashIt) {
is FlashIt.FlashBoot -> installBoot(
flashIt.boot,
flashIt.lkm,
flashIt.ota,
onFinish,
onStdout,
onStderr
)
is FlashIt.FlashModules -> {
flashModulesSequentially(flashIt.uris, onStdout, onStderr)
}
is FlashIt.FlashModule -> flashModule(flashIt.uri, onFinish, onStdout, onStderr)
FlashIt.FlashRestore -> restoreBoot(onStdout, onStderr)
FlashIt.FlashRestore -> restoreBoot(onFinish, onStdout, onStderr)
FlashIt.FlashUninstall -> uninstallPermanently(onStdout, onStderr)
FlashIt.FlashUninstall -> uninstallPermanently(onFinish, onStdout, onStderr)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(
status: FlashingStatus,
onBack: () -> Unit = {},
onSave: () -> Unit = {},
scrollBehavior: TopAppBarScrollBehavior? = null
) {
private fun TopBar(status: FlashingStatus, onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
TopAppBar(
title = {
Text(
@@ -273,9 +227,7 @@ private fun TopBar(
contentDescription = "Localized description"
)
}
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
}
)
}

View File

@@ -22,58 +22,48 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.pm.PackageInfoCompat
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination
import com.ramcosta.composedestinations.generated.destinations.SettingScreenDestination
import com.ramcosta.composedestinations.annotation.RootNavGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.*
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.KsuIsValid
import me.weishu.kernelsu.ui.screen.destinations.InstallScreenDestination
import me.weishu.kernelsu.ui.screen.destinations.SettingScreenDestination
import me.weishu.kernelsu.ui.util.*
import me.weishu.kernelsu.ui.util.module.LatestVersionInfo
@OptIn(ExperimentalMaterial3Api::class)
@Destination<RootGraph>(start = true)
@RootNavGraph(start = true)
@Destination
@Composable
fun HomeScreen(navigator: DestinationsNavigator) {
val kernelVersion = getKernelVersion()
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
Scaffold(
topBar = {
TopBar(
kernelVersion,
onSettingsClick = {
navigator.navigate(SettingScreenDestination)
},
onInstallClick = {
navigator.navigate(InstallScreenDestination)
},
scrollBehavior = scrollBehavior
)
},
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
Scaffold(topBar = {
TopBar(kernelVersion, onSettingsClick = {
navigator.navigate(SettingScreenDestination)
}, onInstallClick = {
navigator.navigate(InstallScreenDestination)
})
}) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState())
.padding(horizontal = 16.dp),
.padding(horizontal = 16.dp)
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
val isManager = Natives.becomeManager(ksuApp.packageName)
SideEffect {
if (isManager) install()
}
val ksuVersion = if (isManager) Natives.version else null
val lkmMode = ksuVersion?.let {
if (it >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && kernelVersion.isGKI()) Natives.isLkmMode else null
@@ -113,11 +103,12 @@ fun UpdateCard() {
val context = LocalContext.current
val latestVersionInfo = LatestVersionInfo()
val newVersion by produceState(initialValue = latestVersionInfo) {
value = withContext(Dispatchers.IO) {
value = withContext(Dispatchers.IO){
checkNewVersion()
}
}
val currentVersionCode = getManagerVersion(context).second
val newVersionCode = newVersion.versionCode
val newVersionUrl = newVersion.downloadUrl
@@ -165,60 +156,52 @@ fun RebootDropdownItem(@StringRes id: Int, reason: String = "") {
private fun TopBar(
kernelVersion: KernelVersion,
onInstallClick: () -> Unit,
onSettingsClick: () -> Unit,
scrollBehavior: TopAppBarScrollBehavior? = null
onSettingsClick: () -> Unit
) {
TopAppBar(
title = { Text(stringResource(R.string.app_name)) },
actions = {
if (kernelVersion.isGKI()) {
IconButton(onClick = onInstallClick) {
Icon(
imageVector = Icons.Filled.Archive,
contentDescription = stringResource(id = R.string.install)
)
}
}
var showDropdown by remember { mutableStateOf(false) }
KsuIsValid() {
IconButton(onClick = {
showDropdown = true
}) {
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = stringResource(id = R.string.reboot)
)
DropdownMenu(expanded = showDropdown, onDismissRequest = {
showDropdown = false
}) {
RebootDropdownItem(id = R.string.reboot)
val pm = LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager?
@Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm?.isRebootingUserspaceSupported == true) {
RebootDropdownItem(id = R.string.reboot_userspace, reason = "userspace")
}
RebootDropdownItem(id = R.string.reboot_recovery, reason = "recovery")
RebootDropdownItem(id = R.string.reboot_bootloader, reason = "bootloader")
RebootDropdownItem(id = R.string.reboot_download, reason = "download")
RebootDropdownItem(id = R.string.reboot_edl, reason = "edl")
}
}
}
IconButton(onClick = onSettingsClick) {
TopAppBar(title = { Text(stringResource(R.string.app_name)) }, actions = {
if (kernelVersion.isGKI()) {
IconButton(onClick = onInstallClick) {
Icon(
imageVector = Icons.Filled.Settings,
contentDescription = stringResource(id = R.string.settings)
imageVector = Icons.Filled.Archive,
contentDescription = stringResource(id = R.string.install)
)
}
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
)
}
var showDropdown by remember { mutableStateOf(false) }
IconButton(onClick = {
showDropdown = true
}) {
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = stringResource(id = R.string.reboot)
)
DropdownMenu(expanded = showDropdown, onDismissRequest = {
showDropdown = false
}) {
RebootDropdownItem(id = R.string.reboot)
val pm =
LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm?.isRebootingUserspaceSupported == true) {
RebootDropdownItem(id = R.string.reboot_userspace, reason = "userspace")
}
RebootDropdownItem(id = R.string.reboot_recovery, reason = "recovery")
RebootDropdownItem(id = R.string.reboot_bootloader, reason = "bootloader")
RebootDropdownItem(id = R.string.reboot_download, reason = "download")
RebootDropdownItem(id = R.string.reboot_edl, reason = "edl")
}
}
IconButton(onClick = onSettingsClick) {
Icon(
imageVector = Icons.Filled.Settings,
contentDescription = stringResource(id = R.string.settings)
)
}
})
}
@Composable
@@ -432,10 +415,9 @@ private fun InfoCard() {
}
}
fun getManagerVersion(context: Context): Pair<String, Long> {
fun getManagerVersion(context: Context): Pair<String, Int> {
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)!!
val versionCode = PackageInfoCompat.getLongVersionCode(packageInfo)
return Pair(packageInfo.versionName!!, versionCode)
return Pair(packageInfo.versionName!!, packageInfo.versionCode)
}
@Preview

View File

@@ -6,19 +6,11 @@ import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.FileUpload
@@ -31,9 +23,6 @@ import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -42,26 +31,22 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.dropUnlessResumed
import com.maxkeppeker.sheets.core.models.base.Header
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.DialogHandle
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberCustomDialog
import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.LkmSelection
import me.weishu.kernelsu.ui.util.getCurrentKmi
import me.weishu.kernelsu.ui.util.getSupportedKmis
@@ -73,8 +58,7 @@ import me.weishu.kernelsu.ui.util.rootAvailable
* @author weishu
* @date 2024/3/12.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@Destination
@Composable
fun InstallScreen(navigator: DestinationsNavigator) {
var installMethod by remember {
@@ -129,24 +113,12 @@ fun InstallScreen(navigator: DestinationsNavigator) {
})
}
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
Scaffold(
topBar = {
TopBar(
onBack = dropUnlessResumed { navigator.popBackStack() },
onLkmUpload = onLkmUpload,
scrollBehavior = scrollBehavior
)
},
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState())
) {
Scaffold(topBar = {
TopBar(
onBack = { navigator.popBackStack() }, onLkmUpload = onLkmUpload
)
}) {
Column(modifier = Modifier.padding(it)) {
SelectInstallMethod { method ->
installMethod = method
}
@@ -259,31 +231,16 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
Column {
radioOptions.forEach { option ->
val interactionSource = remember { MutableInteractionSource() }
Row(
verticalAlignment = Alignment.CenterVertically,
Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.toggleable(
value = option.javaClass == selectedOption?.javaClass,
onValueChange = {
onClick(option)
},
role = Role.RadioButton,
indication = LocalIndication.current,
interactionSource = interactionSource
)
) {
RadioButton(
selected = option.javaClass == selectedOption?.javaClass,
onClick = {
.clickable {
onClick(option)
},
interactionSource = interactionSource
)
Column(
modifier = Modifier.padding(vertical = 12.dp)
) {
}) {
RadioButton(selected = option.javaClass == selectedOption?.javaClass, onClick = {
onClick(option)
})
Column {
Text(
text = stringResource(id = option.label),
fontSize = MaterialTheme.typography.titleMedium.fontSize,
@@ -335,28 +292,20 @@ fun rememberSelectKmiDialog(onSelected: (String?) -> Unit): DialogHandle {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(
onBack: () -> Unit = {},
onLkmUpload: () -> Unit = {},
scrollBehavior: TopAppBarScrollBehavior? = null
) {
TopAppBar(
title = { Text(stringResource(R.string.install)) }, navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
}, actions = {
IconButton(onClick = onLkmUpload) {
Icon(Icons.Filled.FileUpload, contentDescription = null)
}
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
)
private fun TopBar(onBack: () -> Unit = {}, onLkmUpload: () -> Unit = {}) {
TopAppBar(title = { Text(stringResource(R.string.install)) }, navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
}, actions = {
IconButton(onClick = onLkmUpload) {
Icon(Icons.Filled.FileUpload, contentDescription = null)
}
})
}
@Composable
@Preview
fun SelectInstallPreview() {
fun SelectInstall_Preview() {
InstallScreen(EmptyDestinationsNavigator)
}

View File

@@ -1,66 +1,47 @@
package me.weishu.kernelsu.ui.screen
import android.app.Activity.RESULT_OK
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Wysiwyg
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.outlined.PlayArrow
import androidx.compose.material.icons.outlined.Download
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.AlertDialog
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -68,13 +49,12 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
@@ -84,21 +64,16 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.SearchAppBar
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.DownloadListener
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.download
@@ -106,24 +81,18 @@ import me.weishu.kernelsu.ui.util.hasMagisk
import me.weishu.kernelsu.ui.util.reboot
import me.weishu.kernelsu.ui.util.toggleModule
import me.weishu.kernelsu.ui.util.uninstallModule
import me.weishu.kernelsu.ui.util.getFileName
import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel
import me.weishu.kernelsu.ui.webui.WebUIActivity
import okhttp3.OkHttpClient
@OptIn(ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@Destination
@Composable
fun ModuleScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel<ModuleViewModel>()
val context = LocalContext.current
val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
LaunchedEffect(Unit) {
if (viewModel.moduleList.isEmpty() || viewModel.isNeedRefresh) {
viewModel.sortEnabledFirst = prefs.getBoolean("module_sort_enabled_first", false)
viewModel.sortActionFirst = prefs.getBoolean("module_sort_action_first", false)
viewModel.fetchModuleList()
}
}
@@ -133,132 +102,41 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
val hideInstallButton = isSafeMode || hasMagisk
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val webUILauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) { viewModel.fetchModuleList() }
Scaffold(
topBar = {
SearchAppBar(
title = { Text(stringResource(R.string.module)) },
searchText = viewModel.search,
onSearchTextChange = { viewModel.search = it },
onClearClick = { viewModel.search = "" },
dropdownContent = {
var showDropdown by remember { mutableStateOf(false) }
IconButton(
onClick = { showDropdown = true },
) {
Icon(
imageVector = Icons.Filled.MoreVert,
contentDescription = stringResource(id = R.string.settings)
)
DropdownMenu(expanded = showDropdown, onDismissRequest = {
showDropdown = false
}) {
DropdownMenuItem(text = {
Text(stringResource(R.string.module_sort_action_first))
}, trailingIcon = {
Checkbox(viewModel.sortActionFirst, null)
}, onClick = {
viewModel.sortActionFirst =
!viewModel.sortActionFirst
prefs.edit()
.putBoolean(
"module_sort_action_first",
viewModel.sortActionFirst
)
.apply()
scope.launch {
viewModel.fetchModuleList()
}
})
DropdownMenuItem(text = {
Text(stringResource(R.string.module_sort_enabled_first))
}, trailingIcon = {
Checkbox(viewModel.sortEnabledFirst, null)
}, onClick = {
viewModel.sortEnabledFirst =
!viewModel.sortEnabledFirst
prefs.edit()
.putBoolean(
"module_sort_enabled_first",
viewModel.sortEnabledFirst
)
.apply()
scope.launch {
viewModel.fetchModuleList()
}
})
}
}
},
scrollBehavior = scrollBehavior,
)
},
floatingActionButton = {
if (!hideInstallButton) {
val moduleInstall = stringResource(id = R.string.module_install)
val confirmTitle = stringResource(R.string.module)
var zipUris by remember { mutableStateOf<List<Uri>>(emptyList()) }
val confirmDialog = rememberConfirmDialog(onConfirm = {
navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(zipUris)))
viewModel.markNeedRefresh()
})
val selectZipLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode != RESULT_OK) {
return@rememberLauncherForActivityResult
}
val data = it.data ?: return@rememberLauncherForActivityResult
val clipData = data.clipData
val uris = mutableListOf<Uri>()
if (clipData != null) {
for (i in 0 until clipData.itemCount) {
clipData.getItemAt(i)?.uri?.let { uris.add(it) }
}
} else {
data.data?.let { uris.add(it) }
}
if (uris.size == 1) {
navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(listOf(uris.first()))))
} else if (uris.size > 1) {
// multiple files selected
val moduleNames = uris.mapIndexed { index, uri -> "\n${index + 1}. ${uri.getFileName(context)}" }.joinToString("")
val confirmContent = context.getString(R.string.module_install_prompt_with_name, moduleNames)
zipUris = uris
confirmDialog.showConfirm(
title = confirmTitle,
content = confirmContent,
markdown = true
)
}
Scaffold(topBar = {
TopBar()
}, floatingActionButton = if (hideInstallButton) {
{ /* Empty */ }
} else {
{
val moduleInstall = stringResource(id = R.string.module_install)
val selectZipLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode != RESULT_OK) {
return@rememberLauncherForActivityResult
}
val data = it.data ?: return@rememberLauncherForActivityResult
val uri = data.data ?: return@rememberLauncherForActivityResult
ExtendedFloatingActionButton(
onClick = {
// Select the zip files to install
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
type = "application/zip"
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
}
selectZipLauncher.launch(intent)
},
icon = { Icon(Icons.Filled.Add, moduleInstall) },
text = { Text(text = moduleInstall) },
)
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(uri)))
viewModel.markNeedRefresh()
Log.i("ModuleScreen", "select zip result: ${it.data}")
}
},
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
snackbarHost = { SnackbarHost(hostState = snackBarHost) }
) { innerPadding ->
ExtendedFloatingActionButton(
onClick = {
// select the zip file to install
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "application/zip"
selectZipLauncher.launch(intent)
},
icon = { Icon(Icons.Filled.Add, moduleInstall) },
text = { Text(text = moduleInstall) },
)
}
}) { innerPadding ->
when {
hasMagisk -> {
@@ -277,59 +155,53 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
else -> {
ModuleList(
navigator,
viewModel = viewModel,
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
boxModifier = Modifier.padding(innerPadding),
onInstallModule = {
navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(listOf(it))))
},
onClickModule = { id, name, hasWebUi ->
viewModel = viewModel, modifier = Modifier
.padding(innerPadding)
.fillMaxSize(),
onInstallModule =
{
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it)))
}, onClickModule = { id, name, hasWebUi ->
if (hasWebUi) {
webUILauncher.launch(
Intent(context, WebUIActivity::class.java)
.setData(Uri.parse("kernelsu://webui/$id"))
.putExtra("id", id)
.putExtra("name", name)
context.startActivity(Intent(context, WebUIActivity::class.java)
.setData(Uri.parse("kernelsu://webui/$id"))
.putExtra("id", id)
.putExtra("name", name)
)
}
},
context = context,
snackBarHost = snackBarHost
)
})
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun ModuleList(
navigator: DestinationsNavigator,
viewModel: ModuleViewModel,
modifier: Modifier = Modifier,
boxModifier: Modifier = Modifier,
onInstallModule: (Uri) -> Unit,
onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit,
context: Context,
snackBarHost: SnackbarHostState
onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit
) {
val failedEnable = stringResource(R.string.module_failed_to_enable)
val failedDisable = stringResource(R.string.module_failed_to_disable)
val failedUninstall = stringResource(R.string.module_uninstall_failed)
val successUninstall = stringResource(R.string.module_uninstall_success)
val reboot = stringResource(R.string.reboot)
val rebootToApply = stringResource(R.string.reboot_to_apply)
val moduleStr = stringResource(R.string.module)
val uninstall = stringResource(R.string.uninstall)
val cancel = stringResource(android.R.string.cancel)
val moduleUninstallConfirm = stringResource(R.string.module_uninstall_confirm)
val reboot = stringResource(id = R.string.reboot)
val rebootToApply = stringResource(id = R.string.reboot_to_apply)
val moduleStr = stringResource(id = R.string.module)
val uninstall = stringResource(id = R.string.uninstall)
val cancel = stringResource(id = android.R.string.cancel)
val moduleUninstallConfirm = stringResource(id = R.string.module_uninstall_confirm)
val updateText = stringResource(R.string.module_update)
val changelogText = stringResource(R.string.module_changelog)
val downloadingText = stringResource(R.string.module_downloading)
val startDownloadingText = stringResource(R.string.module_start_downloading)
val fetchChangeLogFailed = stringResource(R.string.module_changelog_failed)
val snackBarHost = LocalSnackbarHost.current
val context = LocalContext.current
val loadingDialog = rememberLoadingDialog()
val confirmDialog = rememberConfirmDialog()
@@ -342,7 +214,7 @@ private fun ModuleList(
val changelogResult = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
runCatching {
ksuApp.okhttpClient.newCall(
OkHttpClient().newCall(
okhttp3.Request.Builder().url(changelogUrl).build()
).execute().body!!.string()
}
@@ -428,31 +300,26 @@ private fun ModuleList(
} else {
null
}
val result = snackBarHost.showSnackbar(
message = message,
actionLabel = actionLabel,
duration = SnackbarDuration.Long
)
val result = snackBarHost.showSnackbar(message, actionLabel = actionLabel)
if (result == SnackbarResult.ActionPerformed) {
reboot()
}
}
PullToRefreshBox(
modifier = boxModifier,
onRefresh = {
viewModel.fetchModuleList()
},
isRefreshing = viewModel.isRefreshing
) {
val refreshState = rememberPullRefreshState(refreshing = viewModel.isRefreshing,
onRefresh = { viewModel.fetchModuleList() })
Box(modifier.pullRefresh(refreshState)) {
val context = LocalContext.current
LazyColumn(
modifier = modifier,
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = remember {
PaddingValues(
start = 16.dp,
top = 16.dp,
end = 16.dp,
bottom = 16.dp + 56.dp + 16.dp + 48.dp + 6.dp /* Scaffold Fab Spacing + Fab container height + SnackBar height */
bottom = 16.dp + 16.dp + 56.dp /* Scaffold Fab Spacing + Fab container height */
)
},
) {
@@ -487,6 +354,7 @@ private fun ModuleList(
else -> {
items(viewModel.moduleList) { module ->
var isChecked by rememberSaveable(module) { mutableStateOf(module.enabled) }
val scope = rememberCoroutineScope()
val updatedModule by produceState(initialValue = Triple("", "", "")) {
scope.launch(Dispatchers.IO) {
@@ -494,51 +362,42 @@ private fun ModuleList(
}
}
ModuleItem(
navigator = navigator,
module = module,
updateUrl = updatedModule.first,
onUninstall = {
scope.launch { onModuleUninstall(module) }
},
onCheckChanged = {
scope.launch {
val success = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
toggleModule(module.id, !module.enabled)
}
ModuleItem(module, isChecked, updatedModule.first, onUninstall = {
scope.launch { onModuleUninstall(module) }
}, onCheckChanged = {
scope.launch {
val success = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
toggleModule(module.id, !isChecked)
}
if (success) {
viewModel.fetchModuleList()
}
if (success) {
isChecked = it
viewModel.fetchModuleList()
val result = snackBarHost.showSnackbar(
message = rebootToApply,
actionLabel = reboot,
duration = SnackbarDuration.Long
)
if (result == SnackbarResult.ActionPerformed) {
reboot()
}
} else {
val message = if (module.enabled) failedDisable else failedEnable
snackBarHost.showSnackbar(message.format(module.name))
}
}
},
onUpdate = {
scope.launch {
onModuleUpdate(
module,
updatedModule.third,
updatedModule.first,
"${module.name}-${updatedModule.second}.zip"
val result = snackBarHost.showSnackbar(
rebootToApply, actionLabel = reboot
)
if (result == SnackbarResult.ActionPerformed) {
reboot()
}
} else {
val message = if (isChecked) failedDisable else failedEnable
snackBarHost.showSnackbar(message.format(module.name))
}
},
onClick = {
onClickModule(it.id, it.name, it.hasWebUi)
}
)
}, onUpdate = {
scope.launch {
onModuleUpdate(
module,
updatedModule.third,
updatedModule.first,
"${module.name}-${updatedModule.second}.zip"
)
}
}, onClick = {
onClickModule(it.id, it.name, it.hasWebUi)
})
// fix last item shadow incomplete in LazyColumn
Spacer(Modifier.height(1.dp))
@@ -549,13 +408,24 @@ private fun ModuleList(
DownloadListener(context, onInstallModule)
PullRefreshIndicator(
refreshing = viewModel.isRefreshing, state = refreshState, modifier = Modifier.align(
Alignment.TopCenter
)
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ModuleItem(
navigator: DestinationsNavigator,
private fun TopBar() {
TopAppBar(title = { Text(stringResource(R.string.module)) })
}
@Composable
private fun ModuleItem(
module: ModuleViewModel.ModuleInfo,
isChecked: Boolean,
updateUrl: String,
onUninstall: (ModuleViewModel.ModuleInfo) -> Unit,
onCheckChanged: (Boolean) -> Unit,
@@ -563,31 +433,13 @@ fun ModuleItem(
onClick: (ModuleViewModel.ModuleInfo) -> Unit
) {
ElevatedCard(
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.elevatedCardColors(containerColor = MaterialTheme.colorScheme.surface)
) {
val textDecoration = if (!module.remove) null else TextDecoration.LineThrough
val interactionSource = remember { MutableInteractionSource() }
val indication = LocalIndication.current
val viewModel = viewModel<ModuleViewModel>()
Column(
modifier = Modifier
.run {
if (module.hasWebUi) {
toggleable(
value = module.enabled,
enabled = !module.remove && module.enabled,
interactionSource = interactionSource,
role = Role.Button,
indication = indication,
onValueChange = { onClick(module) }
)
} else {
this
}
}
.padding(22.dp, 18.dp, 22.dp, 12.dp)
) {
val textDecoration = if (!module.remove) null else TextDecoration.LineThrough
Column(modifier = Modifier.clickable { onClick(module) }.padding(24.dp, 16.dp, 24.dp, 0.dp)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
@@ -595,9 +447,7 @@ fun ModuleItem(
val moduleVersion = stringResource(id = R.string.module_version)
val moduleAuthor = stringResource(id = R.string.module_author)
Column(
modifier = Modifier.fillMaxWidth(0.8f)
) {
Column(modifier = Modifier.fillMaxWidth(0.8f)) {
Text(
text = module.name,
fontSize = MaterialTheme.typography.titleMedium.fontSize,
@@ -632,9 +482,8 @@ fun ModuleItem(
) {
Switch(
enabled = !module.update,
checked = module.enabled,
onCheckedChange = onCheckChanged,
interactionSource = if (!module.hasWebUi) interactionSource else null
checked = isChecked,
onCheckedChange = onCheckChanged
)
}
}
@@ -652,114 +501,53 @@ fun ModuleItem(
textDecoration = textDecoration
)
Spacer(modifier = Modifier.height(16.dp))
HorizontalDivider(thickness = Dp.Hairline)
Spacer(modifier = Modifier.height(4.dp))
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
if (module.hasActionScript) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove && module.enabled,
onClick = {
navigator.navigate(ExecuteModuleActionScreenDestination(module.id))
viewModel.markNeedRefresh()
},
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.PlayArrow,
contentDescription = null
)
if (!module.hasWebUi && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
text = stringResource(R.string.action),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize
)
}
}
Spacer(modifier = Modifier.weight(0.1f, true))
}
if (module.hasWebUi) {
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove && module.enabled,
onClick = { onClick(module) },
interactionSource = interactionSource,
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.AutoMirrored.Outlined.Wysiwyg,
contentDescription = null
)
if (!module.hasActionScript && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.open)
)
}
}
}
Spacer(modifier = Modifier.weight(1f, true))
if (updateUrl.isNotEmpty()) {
Button(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove,
modifier = Modifier
.padding(0.dp)
.defaultMinSize(52.dp, 32.dp),
onClick = { onUpdate(module) },
shape = ButtonDefaults.textShape,
contentPadding = ButtonDefaults.TextButtonContentPadding
shape = RoundedCornerShape(6.dp),
contentPadding = PaddingValues(0.dp)
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Download,
contentDescription = null
)
if (!module.hasActionScript || !module.hasWebUi) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.module_update)
)
}
}
Spacer(modifier = Modifier.weight(0.1f, true))
}
FilledTonalButton(
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
enabled = !module.remove,
onClick = { onUninstall(module) },
contentPadding = ButtonDefaults.TextButtonContentPadding
) {
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Delete,
contentDescription = null
)
if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) {
Text(
modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.uninstall)
text = stringResource(R.string.module_update),
)
}
}
TextButton(
enabled = !module.remove,
onClick = { onUninstall(module) },
) {
Text(
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.uninstall),
)
}
if (module.hasWebUi) {
TextButton(
onClick = { onClick(module) },
) {
Text(
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.open),
)
}
}
@@ -780,10 +568,9 @@ fun ModuleItemPreview() {
description = "I am a test module and i do nothing but show a very long description",
enabled = true,
update = true,
remove = false,
remove = true,
updateJson = "",
hasWebUi = false,
hasActionScript = false
)
ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {})
}
ModuleItem(module, true, "", {}, {}, {}, {})
}

View File

@@ -1,20 +1,18 @@
package me.weishu.kernelsu.ui.screen
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.database.Cursor
import android.net.Uri
import android.provider.OpenableColumns
import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
@@ -27,23 +25,19 @@ import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.DeleteForever
import androidx.compose.material.icons.filled.DeveloperMode
import androidx.compose.material.icons.filled.Fence
import androidx.compose.material.icons.filled.FolderDelete
import androidx.compose.material.icons.filled.RemoveModerator
import androidx.compose.material.icons.filled.Save
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.filled.Update
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -54,7 +48,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.LineHeightStyle
@@ -62,7 +55,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.FileProvider
import androidx.lifecycle.compose.dropUnlessResumed
import com.maxkeppeker.sheets.core.models.base.Header
import com.maxkeppeker.sheets.core.models.base.IconSource
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
@@ -70,9 +62,6 @@ import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
@@ -85,12 +74,13 @@ import me.weishu.kernelsu.ui.component.AboutDialog
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.DialogHandle
import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.KsuIsValid
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberCustomDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.getBugreportFile
import me.weishu.kernelsu.ui.util.getFileNameFromUri
import me.weishu.kernelsu.ui.util.shrinkModules
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
@@ -100,23 +90,15 @@ import java.time.format.DateTimeFormatter
* @date 2023/1/1.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@Destination
@Composable
fun SettingScreen(navigator: DestinationsNavigator) {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val snackBarHost = LocalSnackbarHost.current
Scaffold(
topBar = {
TopBar(
onBack = dropUnlessResumed {
navigator.popBackStack()
},
scrollBehavior = scrollBehavior
)
},
snackbarHost = { SnackbarHost(snackBarHost) },
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
TopBar(onBack = {
navigator.popBackStack()
})
}
) { paddingValues ->
val aboutDialog = rememberCustomDialog {
AboutDialog(it)
@@ -127,74 +109,33 @@ fun SettingScreen(navigator: DestinationsNavigator) {
Column(
modifier = Modifier
.padding(paddingValues)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState())
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val exportBugreportLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.CreateDocument("application/gzip")
) { uri: Uri? ->
if (uri == null) return@rememberLauncherForActivityResult
scope.launch(Dispatchers.IO) {
loadingDialog.show()
context.contentResolver.openOutputStream(uri)?.use { output ->
getBugreportFile(context).inputStream().use {
it.copyTo(output)
}
}
loadingDialog.hide()
snackBarHost.showSnackbar(context.getString(R.string.log_saved))
}
}
val profileTemplate = stringResource(id = R.string.settings_profile_template)
KsuIsValid() {
ListItem(
leadingContent = { Icon(Icons.Filled.Fence, profileTemplate) },
headlineContent = { Text(profileTemplate) },
supportingContent = { Text(stringResource(id = R.string.settings_profile_template_summary)) },
modifier = Modifier.clickable {
navigator.navigate(AppProfileTemplateScreenDestination)
}
)
}
ListItem(
leadingContent = { Icon(Icons.Filled.Fence, profileTemplate) },
headlineContent = { Text(profileTemplate) },
supportingContent = { Text(stringResource(id = R.string.settings_profile_template_summary)) },
modifier = Modifier.clickable {
navigator.navigate(AppProfileTemplateScreenDestination)
}
)
var umountChecked by rememberSaveable {
mutableStateOf(Natives.isDefaultUmountModules())
}
KsuIsValid() {
SwitchItem(
icon = Icons.Filled.FolderDelete,
title = stringResource(id = R.string.settings_umount_modules_default),
summary = stringResource(id = R.string.settings_umount_modules_default_summary),
checked = umountChecked
) {
if (Natives.setDefaultUmountModules(it)) {
umountChecked = it
}
}
}
KsuIsValid() {
if (Natives.version >= Natives.MINIMAL_SUPPORTED_SU_COMPAT) {
var isSuDisabled by rememberSaveable {
mutableStateOf(!Natives.isSuEnabled())
}
SwitchItem(
icon = Icons.Filled.RemoveModerator,
title = stringResource(id = R.string.settings_disable_su),
summary = stringResource(id = R.string.settings_disable_su_summary),
checked = isSuDisabled,
) { checked ->
val shouldEnable = !checked
if (Natives.setSuEnabled(shouldEnable)) {
isSuDisabled = !shouldEnable
}
}
SwitchItem(
icon = Icons.Filled.RemoveModerator,
title = stringResource(id = R.string.settings_umount_modules_default),
summary = stringResource(id = R.string.settings_umount_modules_default_summary),
checked = umountChecked
) {
if (Natives.setDefaultUmountModules(it)) {
umountChecked = it
}
}
@@ -219,17 +160,14 @@ fun SettingScreen(navigator: DestinationsNavigator) {
prefs.getBoolean("enable_web_debugging", false)
)
}
KsuIsValid() {
SwitchItem(
icon = Icons.Filled.DeveloperMode,
title = stringResource(id = R.string.enable_web_debugging),
summary = stringResource(id = R.string.enable_web_debugging_summary),
checked = enableWebDebugging
) {
prefs.edit().putBoolean("enable_web_debugging", it).apply()
enableWebDebugging = it
}
SwitchItem(
icon = Icons.Filled.DeveloperMode,
title = stringResource(id = R.string.enable_web_debugging),
summary = stringResource(id = R.string.enable_web_debugging_summary),
checked = enableWebDebugging
) {
prefs.edit().putBoolean("enable_web_debugging", it).apply()
enableWebDebugging = it
}
var showBottomsheet by remember { mutableStateOf(false) }
@@ -246,25 +184,46 @@ fun SettingScreen(navigator: DestinationsNavigator) {
showBottomsheet = true
}
)
if (showBottomsheet) {
if (showBottomsheet){
ModalBottomSheet(
onDismissRequest = { showBottomsheet = false },
content = {
Row(
modifier = Modifier
.padding(10.dp)
.align(Alignment.CenterHorizontally)
Row(modifier = Modifier.padding(10.dp)
.align(Alignment.CenterHorizontally)
) {
Box {
Box{
Column(
modifier = Modifier
.padding(16.dp)
modifier = Modifier.padding(16.dp)
.clickable {
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH_mm")
val current = LocalDateTime.now().format(formatter)
exportBugreportLauncher.launch("KernelSU_bugreport_${current}.tar.gz")
showBottomsheet = false
scope.launch {
val bugreport = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
getBugreportFile(context)
}
}
val uri: Uri =
FileProvider.getUriForFile(
context,
"${BuildConfig.APPLICATION_ID}.fileprovider",
bugreport
)
val filename = getFileNameFromUri(context , uri)
val savefile = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "application/zip"
putExtra(Intent.EXTRA_STREAM, uri)
putExtra(Intent.EXTRA_TITLE, filename)
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
}
context.startActivity(
Intent.createChooser(
savefile,
context.getString(R.string.save_log)
)
)
}
}
) {
Icon(
@@ -284,11 +243,11 @@ fun SettingScreen(navigator: DestinationsNavigator) {
)
}
}
Box {
Box{
Column(
modifier = Modifier
.padding(16.dp)
modifier = Modifier.padding(16.dp)
.clickable {
scope.launch {
val bugreport = loadingDialog.withLoading {
@@ -304,11 +263,10 @@ fun SettingScreen(navigator: DestinationsNavigator) {
bugreport
)
val shareIntent = Intent(Intent.ACTION_SEND).apply {
putExtra(Intent.EXTRA_STREAM, uri)
setDataAndType(uri, "application/gzip")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
shareIntent.setDataAndType(uri, "application/zip")
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(
Intent.createChooser(
@@ -333,39 +291,43 @@ fun SettingScreen(navigator: DestinationsNavigator) {
trim = LineHeightStyle.Trim.None
)
}
)
}
}
}
}
)
}
val shrink = stringResource(id = R.string.shrink_sparse_image)
val shrinkMessage = stringResource(id = R.string.shrink_sparse_image_message)
KsuIsValid() {
ListItem(
leadingContent = {
Icon(
Icons.Filled.Compress,
shrink
)
},
headlineContent = { Text(shrink) },
modifier = Modifier.clickable {
scope.launch {
val result = shrinkDialog.awaitConfirm(title = shrink, content = shrinkMessage)
if (result == ConfirmResult.Confirmed) {
loadingDialog.withLoading {
shrinkModules()
}
ListItem(
leadingContent = {
Icon(
Icons.Filled.Compress,
shrink
)
},
headlineContent = { Text(shrink) },
modifier = Modifier.clickable {
scope.launch {
val result =
shrinkDialog.awaitConfirm(title = shrink, content = shrinkMessage)
if (result == ConfirmResult.Confirmed) {
loadingDialog.withLoading {
shrinkModules()
}
}
}
)
}
}
)
val lkmMode = Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode
val lkmMode =
Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode
if (lkmMode) {
UninstallItem(navigator) {
loadingDialog.withLoading(it)
@@ -377,7 +339,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
leadingContent = {
Icon(
Icons.Filled.ContactPage,
about
stringResource(id = R.string.about)
)
},
headlineContent = { Text(about) },
@@ -388,7 +350,6 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
}
@Composable
fun UninstallItem(
navigator: DestinationsNavigator,
@@ -413,9 +374,11 @@ fun UninstallItem(
UninstallType.PERMANENT -> navigator.navigate(
FlashScreenDestination(FlashIt.FlashUninstall)
)
UninstallType.RESTORE_STOCK_IMAGE -> navigator.navigate(
FlashScreenDestination(FlashIt.FlashRestore)
)
UninstallType.NONE -> Unit
}
}
@@ -493,21 +456,14 @@ fun rememberUninstallDialog(onSelected: (UninstallType) -> Unit): DialogHandle {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(
onBack: () -> Unit = {},
scrollBehavior: TopAppBarScrollBehavior? = null
) {
private fun TopBar(onBack: () -> Unit = {}) {
TopAppBar(
title = { Text(stringResource(R.string.settings)) },
navigationIcon = {
IconButton(
onClick = onBack
) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
}
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
)
}
@@ -515,4 +471,4 @@ private fun TopBar(
@Composable
private fun SettingsPreview() {
SettingScreen(EmptyDestinationsNavigator)
}
}

View File

@@ -4,18 +4,19 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.*
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
@@ -25,37 +26,27 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.AppProfileScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.SearchAppBar
import me.weishu.kernelsu.ui.screen.destinations.AppProfileScreenDestination
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@OptIn(ExperimentalMaterialApi::class)
@Destination
@Composable
fun SuperUserScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel<SuperUserViewModel>()
val scope = rememberCoroutineScope()
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val listState = rememberLazyListState()
LaunchedEffect(key1 = navigator) {
viewModel.search = ""
LaunchedEffect(Unit) {
if (viewModel.appList.isEmpty()) {
viewModel.fetchAppList()
}
}
LaunchedEffect(viewModel.search) {
if (viewModel.search.isEmpty()) {
listState.scrollToItem(0)
}
}
Scaffold(
topBar = {
SearchAppBar(
@@ -100,30 +91,32 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
}
}
},
scrollBehavior = scrollBehavior
)
},
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
}
) { innerPadding ->
PullToRefreshBox(
modifier = Modifier.padding(innerPadding),
onRefresh = {
scope.launch { viewModel.fetchAppList() }
},
isRefreshing = viewModel.isRefreshing
val refreshState = rememberPullRefreshState(
refreshing = viewModel.isRefreshing,
onRefresh = { scope.launch { viewModel.fetchAppList() } },
)
Box(
modifier = Modifier
.padding(innerPadding)
.pullRefresh(refreshState)
) {
LazyColumn(
state = listState,
modifier = Modifier
.fillMaxSize()
.nestedScroll(scrollBehavior.nestedScrollConnection)
) {
LazyColumn(Modifier.fillMaxSize()) {
items(viewModel.appList, key = { it.packageName + it.uid }) { app ->
AppItem(app) {
navigator.navigate(AppProfileScreenDestination(app))
}
}
}
PullRefreshIndicator(
refreshing = viewModel.isRefreshing,
state = refreshState,
modifier = Modifier.align(Alignment.TopCenter)
)
}
}
}

View File

@@ -2,16 +2,13 @@ package me.weishu.kernelsu.ui.screen
import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.ExperimentalMaterialApi
@@ -20,6 +17,9 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.ImportExport
import androidx.compose.material.icons.filled.Sync
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -31,10 +31,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -42,24 +38,22 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.dropUnlessResumed
import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.result.ResultRecipient
import com.ramcosta.composedestinations.result.getOr
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.screen.destinations.TemplateEditorScreenDestination
import me.weishu.kernelsu.ui.viewmodel.TemplateViewModel
/**
@@ -67,8 +61,8 @@ import me.weishu.kernelsu.ui.viewmodel.TemplateViewModel
* @date 2023/10/20.
*/
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@OptIn(ExperimentalMaterialApi::class)
@Destination
@Composable
fun AppProfileTemplateScreen(
navigator: DestinationsNavigator,
@@ -76,7 +70,6 @@ fun AppProfileTemplateScreen(
) {
val viewModel = viewModel<TemplateViewModel>()
val scope = rememberCoroutineScope()
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
LaunchedEffect(Unit) {
if (viewModel.templateList.isEmpty()) {
@@ -100,8 +93,7 @@ fun AppProfileTemplateScreen(
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
}
}
TopBar(
onBack = dropUnlessResumed { navigator.popBackStack() },
TopBar(onBack = { navigator.popBackStack() },
onSync = {
scope.launch { viewModel.fetchTemplates(true) }
},
@@ -132,8 +124,7 @@ fun AppProfileTemplateScreen(
clipboardManager.setText(AnnotatedString(it))
}
}
},
scrollBehavior = scrollBehavior
}
)
},
floatingActionButton = {
@@ -150,27 +141,29 @@ fun AppProfileTemplateScreen(
text = { Text(stringResource(id = R.string.app_profile_template_create)) },
)
},
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
PullToRefreshBox(
modifier = Modifier.padding(innerPadding),
isRefreshing = viewModel.isRefreshing,
onRefresh = {
scope.launch { viewModel.fetchTemplates() }
}
val refreshState = rememberPullRefreshState(
refreshing = viewModel.isRefreshing,
onRefresh = { scope.launch { viewModel.fetchTemplates() } },
)
Box(
modifier = Modifier
.padding(innerPadding)
.pullRefresh(refreshState)
) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.nestedScroll(scrollBehavior.nestedScrollConnection),
contentPadding = remember {
PaddingValues(bottom = 16.dp + 56.dp + 16.dp /* Scaffold Fab Spacing + Fab container height */)
}
) {
LazyColumn(Modifier.fillMaxSize(), contentPadding = remember {
PaddingValues(bottom = 16.dp + 16.dp + 56.dp /* Scaffold Fab Spacing + Fab container height */)
}) {
items(viewModel.templateList, key = { it.id }) { app ->
TemplateItem(navigator, app)
}
}
PullRefreshIndicator(
refreshing = viewModel.isRefreshing,
state = refreshState,
modifier = Modifier.align(Alignment.TopCenter)
)
}
}
}
@@ -216,8 +209,7 @@ private fun TopBar(
onBack: () -> Unit,
onSync: () -> Unit = {},
onImport: () -> Unit = {},
onExport: () -> Unit = {},
scrollBehavior: TopAppBarScrollBehavior? = null
onExport: () -> Unit = {}
) {
TopAppBar(
title = {
@@ -262,8 +254,6 @@ private fun TopBar(
})
}
}
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
}
)
}

View File

@@ -3,12 +3,8 @@ package me.weishu.kernelsu.ui.screen
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
@@ -26,9 +22,6 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -37,16 +30,13 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.lifecycle.compose.dropUnlessResumed
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.result.ResultBackNavigator
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
@@ -61,8 +51,8 @@ import me.weishu.kernelsu.ui.viewmodel.toJSON
* @author weishu
* @date 2023/10/20.
*/
@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
@Destination<RootGraph>
@OptIn(ExperimentalComposeUiApi::class)
@Destination
@Composable
fun TemplateEditorScreen(
navigator: ResultBackNavigator<Boolean>,
@@ -77,8 +67,6 @@ fun TemplateEditorScreen(
mutableStateOf(initialTemplate)
}
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
BackHandler {
navigator.navigateBack(result = !readOnly)
}
@@ -106,7 +94,7 @@ fun TemplateEditorScreen(
},
readOnly = readOnly,
summary = titleSummary,
onBack = dropUnlessResumed { navigator.navigateBack(result = !readOnly) },
onBack = { navigator.navigateBack(result = !readOnly) },
onDelete = {
if (deleteAppProfileTemplate(template.id)) {
navigator.navigateBack(result = true)
@@ -118,16 +106,12 @@ fun TemplateEditorScreen(
} else {
Toast.makeText(context, saveTemplateFailed, Toast.LENGTH_SHORT).show()
}
},
scrollBehavior = scrollBehavior
)
})
},
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState())
.pointerInteropFilter {
// disable click and ripple if readOnly
@@ -256,44 +240,39 @@ private fun TopBar(
summary: String = "",
onBack: () -> Unit,
onDelete: () -> Unit = {},
onSave: () -> Unit = {},
scrollBehavior: TopAppBarScrollBehavior? = null
onSave: () -> Unit = {}
) {
TopAppBar(
title = {
Column {
Text(title)
if (summary.isNotBlank()) {
Text(
text = summary,
style = MaterialTheme.typography.bodyMedium,
)
}
}
}, navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
}, actions = {
if (readOnly) {
return@TopAppBar
}
IconButton(onClick = onDelete) {
Icon(
Icons.Filled.DeleteForever,
contentDescription = stringResource(id = R.string.app_profile_template_delete)
TopAppBar(title = {
Column {
Text(title)
if (summary.isNotBlank()) {
Text(
text = summary,
style = MaterialTheme.typography.bodyMedium,
)
}
IconButton(onClick = onSave) {
Icon(
imageVector = Icons.Filled.Save,
contentDescription = stringResource(id = R.string.app_profile_template_save)
)
}
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
)
}
}, navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
}, actions = {
if (readOnly) {
return@TopAppBar
}
IconButton(onClick = onDelete) {
Icon(
Icons.Filled.DeleteForever,
contentDescription = stringResource(id = R.string.app_profile_template_delete)
)
}
IconButton(onClick = onSave) {
Icon(
imageVector = Icons.Filled.Save,
contentDescription = stringResource(id = R.string.app_profile_template_save)
)
}
})
}
@Composable
@@ -310,14 +289,17 @@ private fun TextEdit(
value = text,
modifier = Modifier.fillMaxWidth(),
label = { Text(label) },
suffix = {
if (errorHint.isNotBlank()) {
suffix =
if (errorHint.isNotBlank()) {
{
Text(
text = if (isError) errorHint else "",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.error
)
}
} else {
null
},
isError = isError,
keyboardOptions = KeyboardOptions(
@@ -332,7 +314,7 @@ private fun TextEdit(
}
private fun isValidTemplateId(id: String): Boolean {
return Regex("""^([A-Za-z][A-Za-z\d_]*\.)*[A-Za-z][A-Za-z\d_]*$""").matches(id)
return Regex("""^([A-Za-z]{1}[A-Za-z\d_]*\.)*[A-Za-z][A-Za-z\d_]*$""").matches(id)
}
private fun isTemplateExist(id: String): Boolean {

View File

@@ -7,8 +7,12 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import com.google.accompanist.systemuicontroller.rememberSystemUiController
private val DarkColorScheme = darkColorScheme(
primary = YELLOW,
@@ -38,6 +42,20 @@ fun KernelSUTheme(
else -> LightColorScheme
}
val systemUiController = rememberSystemUiController()
SideEffect {
systemUiController.setStatusBarColor(
color = colorScheme.surface,
darkIcons = !darkTheme
)
// To match the App Navbar color
systemUiController.setNavigationBarColor(
color = colorScheme.surfaceColorAtElevation(8.dp),
darkIcons = !darkTheme,
)
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,

View File

@@ -7,11 +7,10 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.Build
import android.os.Environment
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.core.content.ContextCompat
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.util.module.LatestVersionInfo
/**
@@ -27,7 +26,8 @@ fun download(
onDownloaded: (Uri) -> Unit = {},
onDownloading: () -> Unit = {}
) {
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadManager =
context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val query = DownloadManager.Query()
query.setFilterByStatus(DownloadManager.STATUS_RUNNING or DownloadManager.STATUS_PAUSED or DownloadManager.STATUS_PENDING)
@@ -67,7 +67,7 @@ fun checkNewVersion(): LatestVersionInfo {
// default null value if failed
val defaultValue = LatestVersionInfo()
runCatching {
ksuApp.okhttpClient.newCall(okhttp3.Request.Builder().url(url).build()).execute()
okhttp3.OkHttpClient().newCall(okhttp3.Request.Builder().url(url).build()).execute()
.use { response ->
if (!response.isSuccessful) {
return defaultValue
@@ -130,12 +130,18 @@ fun DownloadListener(context: Context, onDownloaded: (Uri) -> Unit) {
}
}
}
ContextCompat.registerReceiver(
context,
receiver,
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE),
ContextCompat.RECEIVER_EXPORTED
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.registerReceiver(
receiver,
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE),
Context.RECEIVER_EXPORTED
)
} else {
context.registerReceiver(
receiver,
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
)
}
onDispose {
context.unregisterReceiver(receiver)
}

View File

@@ -4,15 +4,16 @@ import android.content.ContentResolver
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.Parcelable
import android.os.SystemClock
import android.provider.OpenableColumns
import android.system.Os
import android.util.Log
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.io.SuFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
@@ -33,11 +34,6 @@ private fun getKsuDaemonPath(): String {
return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libksud.so"
}
data class FlashResult(val code: Int, val err: String, val showReboot: Boolean) {
constructor(result: Shell.Result, showReboot: Boolean) : this(result.code, result.err.joinToString("\n"), showReboot)
constructor(result: Shell.Result) : this(result, result.isSuccess)
}
object KsuCli {
val SHELL: Shell = createRootShell()
val GLOBAL_MNT_SHELL: Shell = createRootShell(true)
@@ -56,10 +52,10 @@ inline fun <T> withNewRootShell(
return createRootShell(globalMnt).use(block)
}
fun Uri.getFileName(context: Context): String? {
fun getFileNameFromUri(context: Context, uri: Uri): String? {
var fileName: String? = null
val contentResolver: ContentResolver = context.contentResolver
val cursor: Cursor? = contentResolver.query(this, null, null, null, null)
val cursor: Cursor? = contentResolver.query(uri, null, null, null, null)
cursor?.use {
if (it.moveToFirst()) {
fileName = it.getString(it.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
@@ -81,9 +77,9 @@ fun createRootShell(globalMnt: Boolean = false): Shell {
Log.w(TAG, "ksu failed: ", e)
try {
if (globalMnt) {
builder.build("su", "-mm")
} else {
builder.build("su")
} else {
builder.build("su", "-mm")
}
} catch (e: Throwable) {
Log.e(TAG, "su failed: ", e)
@@ -172,9 +168,10 @@ private fun flashWithIO(
fun flashModule(
uri: Uri,
onFinish: (Boolean, Int) -> Unit,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit
): FlashResult {
): Boolean {
val resolver = ksuApp.contentResolver
with(resolver.openInputStream(uri)) {
val file = File(ksuApp.cacheDir, "module.zip")
@@ -187,48 +184,27 @@ fun flashModule(
file.delete()
return FlashResult(result)
onFinish(result.isSuccess, result.code)
return result.isSuccess
}
}
fun runModuleAction(
moduleId: String, onStdout: (String) -> Unit, onStderr: (String) -> Unit
): Boolean {
val shell = createRootShell(true)
val stdoutCallback: CallbackList<String?> = object : CallbackList<String?>() {
override fun onAddElement(s: String?) {
onStdout(s ?: "")
}
}
val stderrCallback: CallbackList<String?> = object : CallbackList<String?>() {
override fun onAddElement(s: String?) {
onStderr(s ?: "")
}
}
val result = shell.newJob().add("${getKsuDaemonPath()} module action $moduleId")
.to(stdoutCallback, stderrCallback).exec()
Log.i("KernelSU", "Module runAction result: $result")
return result.isSuccess
}
fun restoreBoot(
onStdout: (String) -> Unit, onStderr: (String) -> Unit
): FlashResult {
onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit
): Boolean {
val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so")
val result = flashWithIO("${getKsuDaemonPath()} boot-restore -f --magiskboot $magiskboot", onStdout, onStderr)
return FlashResult(result)
onFinish(result.isSuccess, result.code)
return result.isSuccess
}
fun uninstallPermanently(
onStdout: (String) -> Unit, onStderr: (String) -> Unit
): FlashResult {
onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit
): Boolean {
val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so")
val result = flashWithIO("${getKsuDaemonPath()} uninstall --magiskboot $magiskboot", onStdout, onStderr)
return FlashResult(result)
onFinish(result.isSuccess, result.code)
return result.isSuccess
}
suspend fun shrinkModules(): Boolean = withContext(Dispatchers.IO) {
@@ -246,9 +222,10 @@ fun installBoot(
bootUri: Uri?,
lkm: LkmSelection,
ota: Boolean,
onFinish: (Boolean, Int) -> Unit,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit,
): FlashResult {
): Boolean {
val resolver = ksuApp.contentResolver
val bootFile = bootUri?.let { uri ->
@@ -311,7 +288,8 @@ fun installBoot(
lkmFile?.delete()
// if boot uri is empty, it is direct install, when success, we should show reboot button
return FlashResult(result, bootUri == null && result.isSuccess)
onFinish(bootUri == null && result.isSuccess, result.code)
return result.isSuccess
}
fun reboot(reason: String = "") {
@@ -334,7 +312,18 @@ fun isAbDevice(): Boolean {
}
fun isInitBoot(): Boolean {
return !Os.uname().release.contains("android12-")
val shell = getRootShell()
if (shell.isRoot) {
// if we have root, use /dev/block/by-name/init_boot to check
val abDevice = isAbDevice()
val initBootBlock = "/dev/block/by-name/init_boot${if (abDevice) "_a" else ""}"
val file = SuFile(initBootBlock)
file.shell = shell
return file.exists()
}
// https://source.android.com/docs/core/architecture/partitions/generic-boot
return ShellUtils.fastCmd(shell, "getprop ro.product.first_api_level").trim()
.toInt() >= Build.VERSION_CODES.TIRAMISU
}
suspend fun getCurrentKmi(): String = withContext(Dispatchers.IO) {

View File

@@ -1,12 +1,16 @@
package me.weishu.kernelsu.ui.util
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.ParcelFileDescriptor
import android.system.Os
import com.topjohnwu.superuser.ShellUtils
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ui.screen.getManagerVersion
import java.io.File
import java.io.FileOutputStream
import java.io.FileWriter
import java.io.PrintWriter
import java.time.LocalDateTime
@@ -24,7 +28,7 @@ fun getBugreportFile(context: Context): File {
val pstoreFile = File(bugreportDir, "pstore.tar.gz")
// Xiaomi/Readmi devices have diag in /data/vendor/diag
val diagFile = File(bugreportDir, "diag.tar.gz")
val oplusFile = File(bugreportDir, "oplus.tar.gz")
val opulsFile = File(bugreportDir, "opuls.tar.gz")
val bootlogFile = File(bugreportDir, "bootlog.tar.gz")
val mountsFile = File(bugreportDir, "mounts.txt")
val fileSystemsFile = File(bugreportDir, "filesystems.txt")
@@ -46,7 +50,7 @@ fun getBugreportFile(context: Context): File {
shell.newJob().add("tar -czf ${dropboxFile.absolutePath} -C /data/system/dropbox .").exec()
shell.newJob().add("tar -czf ${pstoreFile.absolutePath} -C /sys/fs/pstore .").exec()
shell.newJob().add("tar -czf ${diagFile.absolutePath} -C /data/vendor/diag . --exclude=./minidump.gz").exec()
shell.newJob().add("tar -czf ${oplusFile.absolutePath} -C /mnt/oplus/op2/media/log/boot_log/ .").exec()
shell.newJob().add("tar -czf ${opulsFile.absolutePath} -C /mnt/oplus/op2/media/log/boot_log/ .").exec()
shell.newJob().add("tar -czf ${bootlogFile.absolutePath} -C /data/adb/ksu/log .").exec()
shell.newJob().add("cat /proc/1/mountinfo > ${mountsFile.absolutePath}").exec()

View File

@@ -1,7 +1,7 @@
package me.weishu.kernelsu.ui.util
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.compose.runtime.Composable
import com.topjohnwu.superuser.Shell
import me.weishu.kernelsu.R

View File

@@ -10,8 +10,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.util.HanziToPinyin
import me.weishu.kernelsu.ui.util.listModules
import me.weishu.kernelsu.ui.util.overlayFsAvailable
import org.json.JSONArray
@@ -38,7 +36,6 @@ class ModuleViewModel : ViewModel() {
val remove: Boolean,
val updateJson: String,
val hasWebUi: Boolean,
val hasActionScript: Boolean,
)
data class ModuleUpdateInfo(
@@ -50,23 +47,13 @@ class ModuleViewModel : ViewModel() {
var isRefreshing by mutableStateOf(false)
private set
var search by mutableStateOf("")
var isOverlayAvailable by mutableStateOf(overlayFsAvailable())
private set
var sortEnabledFirst by mutableStateOf(false)
var sortActionFirst by mutableStateOf(false)
val moduleList by derivedStateOf {
val comparator =
compareBy<ModuleInfo>(
{ if (sortEnabledFirst) !it.enabled else 0 },
{ if (sortActionFirst) !it.hasWebUi && !it.hasActionScript else 0 },
).thenBy(Collator.getInstance(Locale.getDefault()), ModuleInfo::id)
modules.filter {
it.id.contains(search, true) || it.name.contains(search, true) || HanziToPinyin.getInstance()
.toPinyinString(it.name).contains(search, true)
}.sortedWith(comparator).also {
val comparator = compareBy(Collator.getInstance(Locale.getDefault()), ModuleInfo::id)
modules.sortedWith(comparator).also {
isRefreshing = false
}
}
@@ -100,6 +87,7 @@ class ModuleViewModel : ViewModel() {
.map { obj ->
ModuleInfo(
obj.getString("id"),
obj.optString("name"),
obj.optString("author", "Unknown"),
obj.optString("version", "Unknown"),
@@ -109,8 +97,7 @@ class ModuleViewModel : ViewModel() {
obj.getBoolean("update"),
obj.getBoolean("remove"),
obj.optString("updateJson"),
obj.optBoolean("web"),
obj.optBoolean("action")
obj.optBoolean("web")
)
}.toList()
isNeedRefresh = false
@@ -129,10 +116,6 @@ class ModuleViewModel : ViewModel() {
}
}
private fun sanitizeVersionString(version: String): String {
return version.replace(Regex("[^a-zA-Z0-9.\\-_]"), "_")
}
fun checkUpdate(m: ModuleInfo): Triple<String, String, String> {
val empty = Triple("", "", "")
if (m.updateJson.isEmpty() || m.remove || m.update || !m.enabled) {
@@ -142,8 +125,11 @@ class ModuleViewModel : ViewModel() {
val result = kotlin.runCatching {
val url = m.updateJson
Log.i(TAG, "checkUpdate url: $url")
val response = ksuApp.okhttpClient.newCall(
okhttp3.Request.Builder().url(url).build()
val response = okhttp3.OkHttpClient()
.newCall(
okhttp3.Request.Builder()
.url(url)
.build()
).execute()
Log.d(TAG, "checkUpdate code: ${response.code}")
if (response.isSuccessful) {
@@ -162,8 +148,7 @@ class ModuleViewModel : ViewModel() {
JSONObject(result)
}.getOrNull() ?: return empty
var version = updateJson.optString("version", "")
version = sanitizeVersionString(version)
val version = updateJson.optString("version", "")
val versionCode = updateJson.optInt("versionCode", 0)
val zipUrl = updateJson.optString("zipUrl", "")
val changelog = updateJson.optString("changelog", "")

View File

@@ -11,17 +11,18 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.profile.Capabilities
import me.weishu.kernelsu.profile.Groups
import me.weishu.kernelsu.ui.util.getAppProfileTemplate
import me.weishu.kernelsu.ui.util.listAppProfileTemplates
import me.weishu.kernelsu.ui.util.setAppProfileTemplate
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONArray
import org.json.JSONObject
import java.text.Collator
import java.util.Locale
import java.util.concurrent.TimeUnit
/**
@@ -137,7 +138,13 @@ class TemplateViewModel : ViewModel() {
private fun fetchRemoteTemplates() {
runCatching {
ksuApp.okhttpClient.newCall(
val client: OkHttpClient = OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build()
client.newCall(
Request.Builder().url(TEMPLATE_INDEX_URL).build()
).execute().use { response ->
if (!response.isSuccessful) {
@@ -148,7 +155,7 @@ private fun fetchRemoteTemplates() {
0.until(remoteTemplateIds.length()).forEach { i ->
val id = remoteTemplateIds.getString(i)
Log.i(TAG, "fetch template: $id")
val templateJson = ksuApp.okhttpClient.newCall(
val templateJson = client.newCall(
Request.Builder().url(TEMPLATE_URL.format(id)).build()
).runCatching {
execute().use { response ->

View File

@@ -2,18 +2,13 @@ package me.weishu.kernelsu.ui.webui
import android.annotation.SuppressLint
import android.app.ActivityManager
import android.os.Build
import android.content.Context
import android.os.Bundle
import android.view.ViewGroup.MarginLayoutParams
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.ComponentActivity
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.webkit.WebViewAssetLoader
import com.topjohnwu.superuser.Shell
import me.weishu.kernelsu.ui.util.createRootShell
@@ -26,30 +21,15 @@ class WebUIActivity : ComponentActivity() {
private var rootShell: Shell? = null
override fun onCreate(savedInstanceState: Bundle?) {
// Enable edge to edge
enableEdgeToEdge()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
window.isNavigationBarContrastEnforced = false
}
super.onCreate(savedInstanceState)
val moduleId = intent.getStringExtra("id")!!
val name = intent.getStringExtra("name")!!
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
@Suppress("DEPRECATION")
setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name"))
} else {
val taskDescription = ActivityManager.TaskDescription.Builder().setLabel("KernelSU - $name").build()
setTaskDescription(taskDescription)
}
setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name"))
val prefs = getSharedPreferences("settings", MODE_PRIVATE)
val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
WebView.setWebContentsDebuggingEnabled(prefs.getBoolean("enable_web_debugging", false))
val moduleDir = "/data/adb/modules/${moduleId}"
val webRoot = File("${moduleDir}/webroot")
val webRoot = File("/data/adb/modules/${moduleId}/webroot")
val rootShell = createRootShell(true).also { this.rootShell = it }
val webViewAssetLoader = WebViewAssetLoader.Builder()
.setDomain("mui.kernelsu.org")
@@ -69,20 +49,10 @@ class WebUIActivity : ComponentActivity() {
}
val webView = WebView(this).apply {
ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updateLayoutParams<MarginLayoutParams> {
leftMargin = inset.left
rightMargin = inset.right
topMargin = inset.top
bottomMargin = inset.bottom
}
return@setOnApplyWindowInsetsListener insets
}
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.allowFileAccess = false
webviewInterface = WebViewInterface(this@WebUIActivity, this, moduleDir)
webviewInterface = WebViewInterface(this@WebUIActivity, this)
addJavascriptInterface(webviewInterface, "ksu")
setWebViewClient(webViewClient)
loadUrl("https://mui.kernelsu.org/index.html")

View File

@@ -9,24 +9,18 @@ import android.view.Window
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.widget.Toast
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.internal.UiThreadHandler
import me.weishu.kernelsu.ui.util.createRootShell
import me.weishu.kernelsu.ui.util.listModules
import me.weishu.kernelsu.ui.util.withNewRootShell
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.util.concurrent.CompletableFuture
class WebViewInterface(
val context: Context,
private val webView: WebView,
private val modDir: String
) {
class WebViewInterface(val context: Context, private val webView: WebView) {
@JavascriptInterface
fun exec(cmd: String): String {
@@ -114,13 +108,13 @@ class WebViewInterface(
}
}
val stdout = object : CallbackList<String>(UiThreadHandler::runAndWait) {
val stdout = object : CallbackList<String>() {
override fun onAddElement(s: String) {
emitData("stdout", s)
}
}
val stderr = object : CallbackList<String>(UiThreadHandler::runAndWait) {
val stderr = object : CallbackList<String>() {
override fun onAddElement(s: String) {
emitData("stderr", s)
}
@@ -176,34 +170,21 @@ class WebViewInterface(
}
}
@JavascriptInterface
fun moduleInfo(): String {
val moduleInfos = JSONArray(listModules())
var currentModuleInfo = JSONObject()
currentModuleInfo.put("moduleDir", modDir)
val moduleId = File(modDir).getName()
for (i in 0 until moduleInfos.length()) {
val currentInfo = moduleInfos.getJSONObject(i)
}
if (currentInfo.getString("id") != moduleId) {
continue
}
var keys = currentInfo.keys()
for (key in keys) {
currentModuleInfo.put(key, currentInfo.get(key))
}
break
}
return currentModuleInfo.toString()
fun hideSystemUI(window: Window) {
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
controller.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
}
fun hideSystemUI(window: Window) =
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
fun showSystemUI(window: Window) =
WindowInsetsControllerCompat(window, window.decorView).show(WindowInsetsCompat.Type.systemBars())
fun showSystemUI(window: Window) {
WindowCompat.setDecorFitsSystemWindows(window, true)
WindowInsetsControllerCompat(
window,
window.decorView
).show(WindowInsetsCompat.Type.systemBars())
}

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group
android:scaleX="0.135"
android:scaleY="0.135">
<path
android:fillColor="#ffffff"
android:pathData="M 0 0 H 800 V 800 H 0 V 0 Z" />
</group>
</vector>

View File

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

View File

@@ -1 +0,0 @@
unqualifiedResLocale=en-US

View File

@@ -18,7 +18,7 @@
<string name="selinux_status_permissive">متساهل</string>
<string name="selinux_status_unknown">مجهول</string>
<string name="superuser">مستخدم خارق</string>
<string name="module_failed_to_enable">فشل في تمكين الوحدة %s</string>
<string name="module_failed_to_enable">فشل في تمكين الإضافة: %s</string>
<string name="module_failed_to_disable">فشل تعطيل الإضافة : %s</string>
<string name="module_empty">لا توجد إضافات مثبتة</string>
<string name="module">الإضافات</string>
@@ -35,28 +35,28 @@
<string name="about">من نحن</string>
<string name="module_uninstall_confirm">هل أنت متأكد أنك تريد إلغاء تثبيت الإضافة %s ?</string>
<string name="module_uninstall_success">تم إلغاء تثبيتها %s</string>
<string name="module_uninstall_failed">فشل إلغاء تثبيت %s</string>
<string name="module_uninstall_failed">فشل إلغاء التثبيت: %s</string>
<string name="module_version">الإصدار</string>
<string name="module_author">المطور</string>
<string name="module_overlay_fs_not_available">الوحدات غير متوفرة حيث يتم تعطيل نظام الملفات المتراكب بواسطة النواة!</string>
<string name="module_overlay_fs_not_available">التراكبات غير متوفرة ، لا يمكن للإضافة أن تعمل!</string>
<string name="refresh">إنعاش</string>
<string name="show_system_apps">إظهار تطبيقات النظام</string>
<string name="hide_system_apps">إخفاء تطبيقات النظام</string>
<string name="send_log">إرسال السجلات</string>
<string name="safe_mode">الوضع الآمن</string>
<string name="reboot_to_apply">إعادة التشغيل لتطبيق التغييرات</string>
<string name="module_magisk_conflict">الوحدات غير متاحة بسبب تعارضها مع Magisk!</string>
<string name="module_magisk_conflict">تم تعطيل الإضافات لأنها تتعارض مع Magisk!</string>
<string name="home_learn_kernelsu">تعلم KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">تعرف على كيفية تثبيت KernelSU واستخدام الإضافات</string>
<string name="home_support_title">إدعمنا</string>
<string name="home_support_content">KernelSU سيظل دائماً مجانياً ومفتوح المصدر. مع ذلك، يمكنك متى ما استطعت أن تظهر لنا أنك تهتم بالتبرع.</string>
<string name="home_support_content">KernelSU سيظل دائماً مجانياً ومفتوح المصدر. مع ذلك، يمكنك أن تظهر لنا أنك تهتم بالتبرع.</string>
<string name="about_source_code"><![CDATA[أنظر إلى مصدر البرمجة في %1$s<br/>إنضم إلى قناتنا في %2$s ]]></string>
<string name="profile_capabilities">القدرات</string>
<string name="module_update">تحديث</string>
<string name="module_downloading">تحميل الإضافة: %s</string>
<string name="module_start_downloading">ابدأ التنزيل: %s</string>
<string name="new_version_available">الإصدار الجديد: %s متاح ، انقر للتحديث.</string>
<string name="new_version_available">الإصدار الجديد: %s متاح ، انقر للتحديث</string>
<string name="launch_app">تشغيل</string>
<string name="profile_default">الإفتراضي</string>
<string name="profile_template">نموذج</string>
@@ -76,7 +76,7 @@
<string name="profile_selinux_domain">المجال</string>
<string name="profile_selinux_rules">القواعد</string>
<string name="restart_app">إعادة تشغيل التطبيق</string>
<string name="failed_to_update_sepolicy">فشل تحديث قواعد SELinux لـ %s</string>
<string name="failed_to_update_sepolicy">فشل تحديث قواعد SELinux لما يلي: %s</string>
<string name="profile_name">اسم الملف الشخصي</string>
<string name="require_kernel_version">إصدار KernelSU الحالي %d منخفض جدًا بحيث لا يعمل المدير بشكل صحيح. الرجاء الترقية إلى الإصدار %d أو أعلى!</string>
<string name="module_changelog">سجل التغييرات</string>
@@ -118,26 +118,17 @@
<string name="select_kmi">اختر KMI</string>
<string name="select_file_tip">يوصى باستخدام صورة القسم %1$s</string>
<string name="shrink_sparse_image">تصغير الصورة المتفرقة</string>
<string name="shrink_sparse_image_message">قم بتغيير حجم الصورة المتفرقة حيث توجد الإضافة إلى حجمها الفعلي. لاحظ أن هذا قد يتسبب في عمل الإضافة بشكل غير طبيعي، لذا يرجى استخدامها فقط عند الضرورة (مثل النسخ الاحتياطي).</string>
<string name="shrink_sparse_image_message">قم بتغيير حجم الصورة المتفرقة حيث توجد الإضافة إلى حجمها الفعلي. لاحظ أن هذا قد يتسبب في عمل الإضافة بشكل غير طبيعي، لذا يرجى استخدامها فقط عند الضرورة (مثل النسخ الاحتياطي)</string>
<string name="settings_uninstall">إلغاء التثبيت</string>
<string name="settings_uninstall_temporary">إلغاء التثبيت مؤقتًا</string>
<string name="settings_uninstall_permanent">إلغاء التثبيت بشكل دائم</string>
<string name="settings_restore_stock_image">استعادة الصورة الاصلية</string>
<string name="settings_uninstall_permanent_message">‬إلغاء تثبيت KernelSU .(الجذر وجميع الوحدات) بشكل كامل ودائم.</string>
<string name="settings_uninstall_permanent_message">‬إلغاء تثبيت KernelSU (الجذر وجميع الوحدات) بشكل كامل ودائم.</string>
<string name="flashing">تركيب</string>
<string name="flash_success">نجح التركيب</string>
<string name="flash_failed">فشل التركيب</string>
<string name="selected_lkm">LKM المحددة: %s</string>
<string name="selected_lkm">صورة lkm المحددة: %s</string>
<string name="settings_restore_stock_image_message">استعادة صورة المصنع المخزنة (في حالة وجود نسخة احتياطية)، والتي تُستخدم عادة قبل OTA؛ إذا كنت بحاجة إلى إلغاء تثبيت KernelSU، فيرجى استخدام \"إلغاء التثبيت الدائم\".</string>
<string name="settings_uninstall_temporary_message">قم بإلغاء تثبيت KernelSU مؤقتًا، واستعد إلى حالته الأصلية بعد إعادة التشغيل التالية.</string>
<string name="save_log">حفظ السجلات</string>
<string name="action">إجراء</string>
<string name="log_saved">السجلات محفوظة</string>
<string name="module_sort_enabled_first">فرز (الممكن أولاً)</string>
<string name="module_sort_action_first">فرز (الإجراء أولاً)</string>
<string name="settings_disable_su">تعطيل توافق su</string>
<string name="settings_disable_su_summary">قم بتعطيل قدره التطبيقات مؤقتا من الحصول على امتيازات المسخدم الخارق عبر الأمر su (لن تتأثر عمليات الجذر الحالية).</string>
<string name="module_install_prompt_with_name">الحزم الاتيه سيتم تثبيتها %1$s</string>
<string name="confirm">تأكيد</string>
<string name="su_not_allowed">من الغير ممكن اعطاء صلاحيات (المسخدم الخارق) لـ %s</string>
</resources>
</resources>

View File

@@ -54,7 +54,7 @@
<string name="profile_default">Defolt</string>
<string name="profile_custom">Özəl</string>
<string name="home_support_content">KernelSU pulsuz və açıq mənbəlidir,həmişə belə olacaqdır. Bununla belə, ianə etməklə bizə qayğı göstərdiyinizi göstərə bilərsiniz.</string>
<string name="about_source_code">Mənbə kodlarımıza baxın %1$s<br></br>Kanalımıza %2$s qoşulun</string>
<string name="about_source_code">Mənbə kodlarımıza baxın %1$s<br/>Kanalımıza %2$s qoşulun</string>
<string name="profile_name">Profil adı</string>
<string name="profile_capabilities">Bacarıqlar</string>
<string name="profile_umount_modules">Modulları umount et</string>
@@ -76,27 +76,7 @@
<string name="profile_umount_modules_summary">Bu seçimi aktivləşdirmək KernelSU-ya bu proqram üçün modullar tərəfindən hər hansı dəyişdirilmiş faylları bərpa etməyə imkan verəcək.</string>
<string name="launch_app"></string>
<string name="force_stop_app">Məcburi dayandır</string>
<string name="restart_app">Təkrar başlat</string>
<string name="restart_app">Yenidən başlat</string>
<string name="failed_to_update_sepolicy">%s görə SELinux qaydalarını güncəlləmək mümkün olmadı</string>
<string name="save_log">Girişləri Saxla</string>
<string name="require_kernel_version">Cari KernelSU versiyası %d menecerin düzgün işləməsi üçün çox aşağıdır. Lütfən, %d və ya daha yüksək versiyaya təkmilləşdirin!</string>
<string name="module_install_prompt_with_name">Aşağıdakı modullar quraşdırılacaq: %1$s</string>
<string name="confirm">Təsdiq edin</string>
<string name="module_sort_action_first">Sıralama (ilk hərəkət)</string>
<string name="module_sort_enabled_first">Sıralama (Əvvəlcə aktivdir)</string>
<string name="module_changelog">Dəyişikliklər jurnalı</string>
<string name="settings_profile_template">Tətbiq Profil Şablonu</string>
<string name="settings_profile_template_summary">Tətbiq Profilinə aid yerli və onlayn şablonların idarə olunması</string>
<string name="app_profile_template_create">Şablon yarat</string>
<string name="app_profile_template_edit">Şablonu redaktə et</string>
<string name="app_profile_template_id">ID</string>
<string name="app_profile_template_id_invalid">Etibarsız şablon ID-si</string>
<string name="app_profile_template_name">Ad</string>
<string name="app_profile_template_description">ıqlama</string>
<string name="su_not_allowed">%s üçün Superistifadəçi girişi vermək mümkün olmadı.</string>
<string name="app_profile_template_save">Yadda saxla</string>
<string name="app_profile_template_delete">Sil</string>
<string name="app_profile_template_view">Şablonu göstər</string>
<string name="app_profile_template_readonly">Yalnız oxu</string>
<string name="app_profile_template_id_exist">Şablon ID-si artıq mövcuddur!</string>
</resources>
</resources>

View File

@@ -49,4 +49,4 @@
<string name="module_version">ভার্সন</string>
<string name="module_author">অথার</string>
<string name="save_log">লগ সংরক্ষণ করুন</string>
</resources>
</resources>

View File

@@ -65,4 +65,4 @@
<string name="profile_umount_modules">আনমাউন্ট মোডিউল</string>
<string name="require_kernel_version">ম্যানেজার সঠিকভাবে কাজ করার জন্য বর্তমান KernelSU সংস্করণ %d খুবই কম। অনুগ্রহ করে %d বা উচ্চতর সংস্করণে আপগ্রেড করুন!</string>
<string name="save_log">লগ সংরক্ষণ করুন</string>
</resources>
</resources>

View File

@@ -42,19 +42,19 @@
<string name="hide_system_apps">Sakrijte sistemske aplikacije</string>
<string name="safe_mode">Sigurnosni mod</string>
<string name="reboot_to_apply">Ponovo pokrenite da bi proradilo</string>
<string name="module_magisk_conflict">"Moduli su nedostupni jer su u sukobu sa Magisk-om!"</string>
<string name="module_magisk_conflict">Module su isključene jer je u sukobu sa Magisk-om!</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Naučite kako da instalirate KernelSU i da koristite module</string>
<string name="home_support_title">Podržite Nas</string>
<string name="send_log">Pošaljite Izvještaj</string>
<string name="home_learn_kernelsu">Naučite KernelSU</string>
<string name="about_source_code">Pogledajte izvornu kodu na %1$s<br></br>Pridružite nam se na %2$s kanalu</string>
<string name="about_source_code">Pogledajte izvornu kodu na %1$s<br/>Pridružite nam se na %2$s kanalu</string>
<string name="profile_selinux_domain">Domena</string>
<string name="profile_selinux_rules">Pravila</string>
<string name="failed_to_update_sepolicy">Neuspješno ažuriranje SELinux pravila za: %s</string>
<string name="home_working">Radi</string>
<string name="home_working_version">Verzija: %d</string>
<string name="home_kernel">Kernel verzija</string>
<string name="home_kernel">Kernel</string>
<string name="selinux_status_permissive">Permisivno</string>
<string name="uninstall">Deinstalirajte</string>
<string name="selinux_status_unknown">Nepoznato</string>
@@ -73,14 +73,11 @@
<string name="selinux_status_disabled">Isključeno</string>
<string name="about">O</string>
<string name="module_uninstall_confirm">Jeste li sigurni da želite deinstalirati modulu %s\?</string>
<string name="module_overlay_fs_not_available">overlayFS je onemogućen od strane kernela, modul nije dostupan.</string>
<string name="module_overlay_fs_not_available">overlayfs nije dostupan, modula ne može raditi!</string>
<string name="home_support_content">KernelSU je, i uvijek če biti, besplatan, i otvorenog izvora. Možete nam međutim pokazati da vas je briga s time da napravite donaciju.</string>
<string name="profile_default">Zadano</string>
<string name="profile_template">Šablon</string>
<string name="profile_custom">Prilagođeno</string>
<string name="profile_name">Naziv profila</string>
<string name="save_log">Sačuvaj Dnevnike</string>
<string name="module_install_prompt_with_name">Modul će biti instaliran</string>
<string name="module_sort_action_first">Sortiraj</string>
<string name="confirm">Potvrdi</string>
</resources>
</resources>

View File

@@ -3,9 +3,9 @@
<string name="home_working">Arbejder</string>
<string name="home_module_count">Moduler: %d</string>
<string name="home_unsupported">Ikke understøttet</string>
<string name="home_kernel">Kernel-version</string>
<string name="home_kernel">Kernel</string>
<string name="home_unsupported_reason">KernelSU understøtter kun GKI kernels</string>
<string name="home_manager_version">Manager version</string>
<string name="home_manager_version">Manager Version</string>
<string name="home_selinux_status">SELinux-status</string>
<string name="selinux_status_disabled">Deaktiveret</string>
<string name="selinux_status_permissive">Tilladende</string>
@@ -18,22 +18,22 @@
<string name="install">Installer</string>
<string name="reboot">Genstart</string>
<string name="settings">Indstillinger</string>
<string name="reboot_userspace">Blød renstart</string>
<string name="reboot_userspace">Blød Genstart</string>
<string name="reboot_download">Genstart til Download</string>
<string name="reboot_edl">Genstart til EDL</string>
<string name="about">Om</string>
<string name="module_uninstall_confirm">Er du sikker på, at du vil afinstallere modulet %s\?</string>
<string name="module_uninstall_success">%s afinstalleret</string>
<string name="module_uninstall_failed">Afinstallation af: %s fejlede</string>
<string name="module_overlay_fs_not_available">Moduler utilgængelige - OverlayFS deaktiveret i kern\'en!</string>
<string name="module_overlay_fs_not_available">overlayfs er ikke tilgængeligt, modulet kan ikke fungere!</string>
<string name="refresh">Opdater</string>
<string name="send_log">Send logs</string>
<string name="send_log">Send Log</string>
<string name="safe_mode">Sikker tilstand</string>
<string name="reboot_to_apply">Genstart for at tage effekt</string>
<string name="home_learn_kernelsu">Lær KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Lær hvordan man installerer KernelSU og moduler</string>
<string name="about_source_code"><![CDATA[View source code at %1$s<br/>Join our %2$s channel]]></string>
<string name="about_source_code">Se source koden ved %1$s<br/>Deltage i vores %2$s kanal</string>
<string name="profile_default">Standard</string>
<string name="profile_template">Skabelon</string>
<string name="profile_namespace">Monter navnerum</string>
@@ -44,17 +44,17 @@
<string name="profile_selinux_context">SELinux-kontext</string>
<string name="profile_umount_modules">Afmonteret moduler</string>
<string name="settings_umount_modules_default">Afmontere moduler som standard</string>
<string name="profile_umount_modules_summary">Aktivering af denne indstilling gør det muligt for KernelSU at gendanne alle modificerede filer af dets modul på app-niveau.</string>
<string name="profile_umount_modules_summary">Aktivering af denne indstilling vil tillade KernelSU at gendanne hvilken som helst modificeret filer af modulet for denne applikation.</string>
<string name="module_update">Opdatering</string>
<string name="module_downloading">Downloader modulet: %s</string>
<string name="new_version_available">Ny version %s er tilgængelig, klik for at opgradere.</string>
<string name="new_version_available">Ny version: %s er tilgængelig, kilk for at downloade</string>
<string name="launch_app">Start</string>
<string name="force_stop_app">Tving stop</string>
<string name="failed_to_update_sepolicy">Opdatering af SELinux-regler mislykkedes for %s</string>
<string name="force_stop_app">Tving Stop</string>
<string name="failed_to_update_sepolicy">Opdatering af SELinux-regler for: %s fejlede</string>
<string name="module_start_downloading">Start download: %s</string>
<string name="home_click_to_install">Klik for at installere</string>
<string name="home_working_version">Version: %d</string>
<string name="home">Home</string>
<string name="home">Hjem</string>
<string name="home_not_installed">Ikke installeret</string>
<string name="home_superuser_count">Superbrugere: %d</string>
<string name="home_fingerprint">Fingeraftryk</string>
@@ -67,9 +67,9 @@
<string name="module_version">Version</string>
<string name="hide_system_apps">Gem system-apps</string>
<string name="show_system_apps">Vis system-apps</string>
<string name="module_magisk_conflict">Moduler er utilgængelige på grund af en konflikt med Magisk!</string>
<string name="module_magisk_conflict">Moduler er deaktiveret, fordi der er konflikt med Magiskes!</string>
<string name="home_support_title">Støt Os</string>
<string name="home_support_content">KernelSU er og vil altid være gratis og åben kildekode. Du kan dog vise din støtte ved at donere.</string>
<string name="home_support_content">KernelSU er, og vil altid være gratis og open source. Du kan stadig vise os din støtte ved at donere.</string>
<string name="profile_custom">Brugerdefineret</string>
<string name="profile_name">Profilnavn</string>
<string name="profile_namespace_individual">Individuel</string>
@@ -78,64 +78,6 @@
<string name="profile_selinux_domain">Domæne</string>
<string name="profile_selinux_rules">Regler</string>
<string name="restart_app">Genstart</string>
<string name="require_kernel_version">Den nuværende KernelSU-version %d er for lav til, at manageren fungerer korrekt. Opgrader venligst til version %d eller højere!</string>
<string name="save_log">Gem logs</string>
<string name="module_install_prompt_with_name">Følgende moduler installeres: %1$s</string>
<string name="module_sort_action_first">Sorter (Handling først)</string>
<string name="module_sort_enabled_first">Sorter (Aktiveret først)</string>
<string name="confirm">Bekræft</string>
<string name="su_not_allowed">Kunne ikke tildele superbruger-adgang til %s</string>
<string name="module_changelog">opdateringslog</string>
<string name="settings_profile_template">app-profilskabelon</string>
<string name="settings_profile_template_summary">Administrer lokale og online skabeloner til App-profil</string>
<string name="app_profile_template_create">Opret skabelon</string>
<string name="app_profile_template_edit">Rediger skabelon</string>
<string name="app_profile_template_id">ID</string>
<string name="app_profile_template_id_invalid">ugyldigt skabelon-id</string>
<string name="app_profile_template_name">Navn</string>
<string name="app_profile_template_description">beskrivelse</string>
<string name="app_profile_template_save">Gem</string>
<string name="app_profile_template_delete">Slet</string>
<string name="app_profile_template_view">visningsskabelon</string>
<string name="app_profile_template_readonly">Skrivebeskyttet</string>
<string name="app_profile_template_id_exist">Skabelon-ID findes allerede!</string>
<string name="app_profile_import_export">Import/Eksport</string>
<string name="app_profile_import_from_clipboard">Importér fra udklipsholder</string>
<string name="app_profile_export_to_clipboard">Eksporter til udklipsholder</string>
<string name="app_profile_template_export_empty">Kan ikke finde lokal skabelon til eksport!</string>
<string name="app_profile_template_import_success">Importér med succes</string>
<string name="app_profile_template_sync">Synkroniser online skabeloner</string>
<string name="app_profile_template_save_failed">Kunne ikke gemme skabelon</string>
<string name="app_profile_template_import_empty">Udklipsholderen er tom!</string>
<string name="module_changelog_failed">Hent changelog mislykkedes: %s</string>
<string name="settings_check_update">Check for opdateringer</string>
<string name="settings_check_update_summary">Automatisk tjek for opdateringer, når du åbner appen</string>
<string name="grant_root_failed">Kunne ikke tildelle root!</string>
<string name="action">Handling</string>
<string name="open">Åbn</string>
<string name="enable_web_debugging">Aktiver WebView-fejlsøgning</string>
<string name="enable_web_debugging_summary">Kan bruges til fejlfinde af WebUI. Aktiver kun når det er nødvendigt.</string>
<string name="direct_install">Direkte installation (Anbefalet)</string>
<string name="select_file">Vælg en fil</string>
<string name="install_inactive_slot">Installer på inaktiv slot (efter OTA-opdatering)</string>
<string name="install_inactive_slot_warning">Din enhed vil blive TVINGET til at starte fra det nuværende inaktive slot efter en genstart!\nBrug kun denne mulighed efter OTA-opdatering er fuldført.\nFortsæt?</string>
<string name="install_next">Næste</string>
<string name="select_file_tip">%1$s partitionsimage anbefales</string>
<string name="select_kmi">Vælg KMI</string>
<string name="shrink_sparse_image">Minimér sparse image</string>
<string name="shrink_sparse_image_message">Tilpas den sparse image, hvor modulet er placeret, til dens faktiske størrelse. Bemærk, at dette kan forårsage unormal funktion af modulet, så brug kun når nødvendigt (f.eks. til backup).</string>
<string name="settings_uninstall">Afinstaller</string>
<string name="settings_uninstall_temporary">Afinstaller midlertidigt</string>
<string name="settings_uninstall_permanent">Afinstaller midlertidigt</string>
<string name="settings_restore_stock_image">Gendan systemets standardbillede</string>
<string name="settings_uninstall_temporary_message">Afinstaller KernelSU midlertidigt; gendan til original tilstand efter næste genstart.</string>
<string name="settings_uninstall_permanent_message">Afinstaller KernelSU fuldstændigt og permanent (root-adgang og alle moduler).</string>
<string name="settings_restore_stock_image_message">Gendan systemets standardfabriksbillede (hvis en backup eksisterer), typisk anvendt før OTA-opdatering; hvis du skal afinstallere KernelSU, brug \'Afinstaller permanent\'.</string>
<string name="flashing">Flashing</string>
<string name="flash_success">Flash-succes</string>
<string name="flash_failed">Flash mislykkedes</string>
<string name="selected_lkm">Valgt LKM: %s</string>
<string name="log_saved">Logs gemt</string>
<string name="settings_disable_su">Deaktiver su-kompatibilitet</string>
<string name="settings_disable_su_summary">Deaktiver midlertidigt enhver apps mulighed for at opnå root-privilegier via su-kommandoen (Eksisterende root-processer påvirkes ikke).</string>
</resources>
<string name="require_kernel_version">Den nuværende KernelSU version %d er for lav til manageren for at fungere ordentligt. Opgrader til version %d eller højere!</string>
<string name="save_log">Gem Logfiler</string>
</resources>

View File

@@ -5,134 +5,121 @@
<string name="selinux_status_permissive">Permissiv</string>
<string name="home_working">Funktioniert</string>
<string name="home_working_version">Version: %d</string>
<string name="superuser">Superuser</string>
<string name="home_click_to_install">Tippe zum Installieren</string>
<string name="superuser">SuperUser</string>
<string name="home_click_to_install">Tippen zum Installieren</string>
<string name="home_superuser_count">Superuser: %d</string>
<string name="selinux_status_unknown">Unbekannt</string>
<string name="selinux_status_enforcing">Erzwingen</string>
<string name="reboot_bootloader">In den Bootloader-Modus neustarten</string>
<string name="reboot_download">In den Download-Modus neustarten</string>
<string name="reboot_edl">In den EDL-Modus neustarten</string>
<string name="reboot_bootloader">Neustart in Bootloader</string>
<string name="reboot_download">Neustart in Download-Modus</string>
<string name="reboot_edl">Neustart mit EDL-Modus</string>
<string name="module_author">Autor</string>
<string name="module_overlay_fs_not_available">Module sind nicht verfügbar, da OverlayFS vom Kernel deaktiviert ist.</string>
<string name="about">Über KernelSU</string>
<string name="module_magisk_conflict">Module sind aufgrund eines Konfliktes mit Magisk nicht verfügbar!</string>
<string name="module_overlay_fs_not_available">overlayfs nicht verfügbar, Modul kann nicht funktionieren!</string>
<string name="about">Über</string>
<string name="module_magisk_conflict">Module sind deaktiviert, weil es einen Konflikt mit Magisk gibt!</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Erfahre, wie KernelSU installiert wird und wie Module verwendet werden</string>
<string name="home_click_to_learn_kernelsu">Erfahren, wie KernelSU installiert und Module verwendet werden</string>
<string name="home_support_title">Unterstütze uns</string>
<string name="home_support_content">KernelSU ist und wird immer frei und quelloffen sein. Du kannst uns jedoch deine Unterstützung zeigen, indem du eine Spende tätigst.</string>
<string name="profile_selinux_context">SELinux-Kontext</string>
<string name="settings_umount_modules_default">Module standardmäßig aushängen</string>
<string name="settings_umount_modules_default_summary">Globaler Standardwert für \"Module aushängen\" im App-Profil. Falls er aktiviert ist, werden alle Moduländerungen im System für alle Apps entfernt, für die kein Profil festgelegt ist.</string>
<string name="settings_umount_modules_default_summary">Globaler Standardwert für \'Module aushängen\' in App-Profilen. Falls aktiviert, werden alle Moduländerungen im System für alle Apps entfernt, für die kein Profil festgelegt ist.</string>
<string name="profile_default">Standard</string>
<string name="profile_template">Vorlage</string>
<string name="profile_custom">Benutzerdefiniert</string>
<string name="failed_to_update_app_profile">App-Profilaktualisierung für %s fehlgeschlagen</string>
<string name="profile_namespace_inherited">Geerbt</string>
<string name="profile_namespace_inherited">Vererbt</string>
<string name="profile_namespace_global">Global</string>
<string name="profile_namespace_individual">Individuell</string>
<string name="profile_selinux_domain">Domäne</string>
<string name="module_update">Aktualisieren</string>
<string name="profile_umount_modules_summary">Wenn du diese Option aktivierst, kann KernelSU alle von den Modulen für diese App geänderten Dateien wiederherstellen.</string>
<string name="profile_selinux_rules">Regeln</string>
<string name="module_start_downloading">Starte Download: %s</string>
<string name="failed_to_update_sepolicy">Aktualisieren der SELinux-Regeln schlug fehl für: %s</string>
<string name="module_start_downloading">Herunterladen startet: %s</string>
<string name="failed_to_update_sepolicy">Fehler beim Aktualisieren der SELinux-Regeln für: %s</string>
<string name="launch_app">Starten</string>
<string name="new_version_available">Neue Version %s verfügbar, tippen zum Aktualisieren.</string>
<string name="new_version_available">Neue Version: %s verfügbar, tippen zum Aktualisieren</string>
<string name="force_stop_app">Stopp erzwingen</string>
<string name="restart_app">Neustarten</string>
<string name="restart_app">Neustart</string>
<string name="home_module_count">Module: %d</string>
<string name="home_manager_version">Manager-Version</string>
<string name="home_selinux_status">SELinux Status</string>
<string name="home_selinux_status">SELinux-Status</string>
<string name="selinux_status_disabled">Deaktiviert</string>
<string name="module_failed_to_enable">Modulaktivierung fehlgeschlagen: %s</string>
<string name="module_failed_to_disable">Moduldeaktivierung fehlgeschlagen: %s</string>
<string name="module_empty">Keine Modul installiert</string>
<string name="module_empty">Keine Module installiert</string>
<string name="module">Modul</string>
<string name="uninstall">Deinstallieren</string>
<string name="install">Installieren</string>
<string name="reboot">Neustarten</string>
<string name="settings">Einstellungen</string>
<string name="reboot_recovery">In den Recovery-Modus neustarten</string>
<string name="reboot_recovery">Neustart in Recovery</string>
<string name="module_uninstall_success">%s deinstalliert</string>
<string name="module_version">Version</string>
<string name="refresh">Aktualisieren</string>
<string name="refresh">Neu laden</string>
<string name="show_system_apps">System-Apps anzeigen</string>
<string name="hide_system_apps">System-Apps ausblenden</string>
<string name="send_log">Protokoll senden</string>
<string name="home_learn_kernelsu">KernelSU verstehen</string>
<string name="safe_mode">Sicherer Modus</string>
<string name="reboot_to_apply">Neustarten, damit Änderungen wirksam werden</string>
<string name="about_source_code"><![CDATA[Quellcode einsehen unter %1$s<br/>Unserem %2$s-Kanal beitreten]]></string>
<string name="about_source_code">Quellcode unter %1$s ansehen<br/>Unserem %2$s-Kanal beitreten</string>
<string name="profile_name">Profilname</string>
<string name="profile_namespace">Namespace einhängen</string>
<string name="profile_groups">Gruppen</string>
<string name="profile_capabilities">Fähigkeiten</string>
<string name="profile_umount_modules">Module aushängen</string>
<string name="module_downloading">Lädt Modul %s herunter</string>
<string name="module_downloading">Modul herunterladen: %s</string>
<string name="home_unsupported">Nicht unterstützt</string>
<string name="home_unsupported_reason">KernelSU unterstützt derzeit nur GKI-Kernel</string>
<string name="home_kernel">Kernel</string>
<string name="home_fingerprint">Fingerabdruck</string>
<string name="module_install">Installieren</string>
<string name="reboot_userspace">Soft-Reboot</string>
<string name="module_uninstall_confirm">Möchtest du wirklich Modul %s deinstallieren?</string>
<string name="module_uninstall_confirm">Sicher, dass du das Modul %s deinstallieren möchtest\?</string>
<string name="module_uninstall_failed">Deinstallation fehlgeschlagen: %s</string>
<string name="require_kernel_version">Die aktuelle KernelSU-Version %d ist zu alt für diese Manager-Version. Bitte auf Version %d oder höher aktualisieren!</string>
<string name="require_kernel_version">Die aktuelle Kernel-Version %d ist zu alt für diese Manager-Version. Bitte auf Version %d oder höher upgraden!</string>
<string name="module_changelog">Änderungsprotokoll</string>
<string name="app_profile_template_import_success">Erfolgreich importiert</string>
<string name="app_profile_export_to_clipboard">In Zwischenablage exportieren</string>
<string name="app_profile_template_export_empty">Kann lokale Vorlage nicht finden!</string>
<string name="app_profile_template_id_exist">Vorlagen-ID existiert bereits!</string>
<string name="app_profile_import_from_clipboard">Aus Zwischenablage importieren</string>
<string name="module_changelog_failed">Konnte Veränderungs-Protokoll nicht laden: %s</string>
<string name="module_changelog_failed">Konnte Changelog nicht laden: %s</string>
<string name="app_profile_template_name">Name</string>
<string name="app_profile_template_id_invalid">Ungültige Vorlagen-ID</string>
<string name="app_profile_template_sync">Online-Vorlagen synchronisieren</string>
<string name="app_profile_template_create">Vorlage erstellen</string>
<string name="app_profile_template_readonly">Schreibgeschützt</string>
<string name="app_profile_import_export">Import/Export</string>
<string name="app_profile_template_save_failed">Schlug beim Speichern der Vorlage fehl</string>
<string name="app_profile_template_save_failed">Fehler beim Speichern</string>
<string name="app_profile_template_edit">Vorlage bearbeiten</string>
<string name="app_profile_template_id">ID</string>
<string name="settings_profile_template">App-Profil-Vorlage</string>
<string name="settings_profile_template">App-Profil-Template</string>
<string name="app_profile_template_description">Beschreibung</string>
<string name="app_profile_template_save">Speichern</string>
<string name="settings_profile_template_summary">Verwalte die lokale und online Vorlage des App-Profils</string>
<string name="settings_profile_template_summary">verwalte lokale und online Profil Vorlagen</string>
<string name="app_profile_template_delete">Löschen</string>
<string name="app_profile_template_import_empty">Zwischenablage ist leer!</string>
<string name="app_profile_template_view">Vorlage ansehen</string>
<string name="enable_web_debugging">WebView-Debugging aktivieren</string>
<string name="enable_web_debugging_summary">Kann zum Fehlerbeheben der WebUI verwendet werden, bitte nur im Notfall aktivieren.</string>
<string name="enable_web_debugging_summary">Kann verwendet werden zum Debugging von WebUI, bitte nur falls nötig aktivieren.</string>
<string name="select_file_tip">%1$s Partitionsabbild empfohlen</string>
<string name="select_kmi">KMI auswählen</string>
<string name="install_next">Weiter</string>
<string name="direct_install">Direkte Installation (empfohlen)</string>
<string name="select_file">Datei auswählen</string>
<string name="install_inactive_slot">In inaktiven Slot installieren (nach OTA)</string>
<string name="install_inactive_slot_warning">Nach einem Neustart wird dein Gerät **GEZWUNGEN** in den derzeit inaktiven Slot zu starten!
<string name="install_inactive_slot_warning">Nach einem Neustart wird dein Gerät **GEZWUNGEN** in den derzeit inaktiven Slot zu booten.
\nBenutze dies nur nach Fertigstellung des OTA.
\nFortfahren?</string>
<string name="grant_root_failed">Root-Zugriff konnte nicht gewährt werden!</string>
<string name="open">Öffnen</string>
<string name="settings_check_update">Auf Aktualisierung prüfen</string>
<string name="settings_check_update_summary">Prüfe automatisch auf Aktualisierungen, wenn die App geöffnet wird</string>
<string name="settings_check_update">Updates suchen</string>
<string name="settings_check_update_summary">Automatisch nach Updates suchen beim Öffnen der App</string>
<string name="settings_uninstall_temporary">Temporär deinstallieren</string>
<string name="settings_uninstall">Deinstallieren</string>
<string name="settings_uninstall_permanent_message">KernelSU (Root und alle Module) vollständig und dauerhaft deinstallieren.</string>
<string name="shrink_sparse_image_message">Ändert die Größe des Sparse-Images, in dem sich das Modul befindet, auf seine tatsächliche Größe. Beachten Sie, dass dies dazu führen kann, dass das Modul nicht ordnungsgemäß funktioniert; verwenden Sie es daher nur, wenn es notwendig ist (Wie für ein Backup).</string>
<string name="shrink_sparse_image_message">Ändert die Größe des Sparse-Images, in dem sich das Modul befindet, auf seine tatsächliche Größe. Beachten Sie, dass dies dazu führen kann, dass das Modul nicht ordnungsgemäß funktioniert; verwenden Sie es daher nur, wenn es notwendig ist (z. B. für ein Backup).</string>
<string name="save_log">Protokolle Speichern</string>
<string name="settings_uninstall_permanent">Permanent deinstallieren</string>
<string name="settings_restore_stock_image">Standard-Abbild wiederherstellen</string>
<string name="settings_uninstall_temporary_message">KernelSU temporär deinstallieren, originalen Status nach dem nächsten Neustart wiederherstellen.</string>
<string name="settings_restore_stock_image_message">Das Standard Werksabbild wiederherstellen (falls ein Backup existiert), normalerweise vor einem OTA zu verwenden; falls Sie KernelSU deinstallieren müssen, nutzen Sie bitte \"Permanent deinstallieren\".</string>
<string name="flashing">Schreibt</string>
<string name="flash_success">Schreiben erfolgreich</string>
<string name="flash_failed">Schreiben fehlgeschlagen</string>
<string name="selected_lkm">Wähle LKM: %s</string>
<string name="shrink_sparse_image">Spärliches Bild minimieren</string>
<string name="action">Aktion</string>
<string name="log_saved">Protokolle gespeichert</string>
<string name="module_install_prompt_with_name">Folgende Module werden installiert: %1$s</string>
<string name="confirm">Bestätigen</string>
</resources>
</resources>

View File

@@ -2,57 +2,57 @@
<resources>
<string name="home">Inicio</string>
<string name="home_not_installed">No instalado</string>
<string name="home_click_to_install">Haz clic para instalar</string>
<string name="home_click_to_install">Toca para instalar</string>
<string name="home_working">Funcionando</string>
<string name="home_working_version">Versión: %d</string>
<string name="home_superuser_count">Superusuarios: %d</string>
<string name="home_module_count">Módulos: %d</string>
<string name="home_unsupported">Sin soporte</string>
<string name="home_unsupported_reason">KernelSU solo admite kernels GKI por ahora</string>
<string name="home_unsupported">No soportado</string>
<string name="home_unsupported_reason">Por el momento, KernelSU solo es compatible con kernels genéricos (GKIs)</string>
<string name="home_kernel">Versión del kernel</string>
<string name="home_manager_version">Versión del gestor</string>
<string name="home_fingerprint">Huella del dispositivo</string>
<string name="home_selinux_status">Estado de SELinux</string>
<!-- It may be better to leave SELinux statuses untranslated -->
<string name="selinux_status_disabled">Desactivado</string>
<string name="selinux_status_enforcing">Estricto</string>
<string name="selinux_status_enforcing">Enforcing de SELinux</string>
<string name="selinux_status_permissive">Permisivo</string>
<string name="selinux_status_unknown">Desconocido</string>
<string name="superuser">Superusuario</string>
<string name="module_failed_to_enable">Error al activar el módulo: %s</string>
<string name="module_failed_to_disable">Error al desactivar el módulo: %s</string>
<string name="module_empty">Ningún módulo instalado</string>
<string name="module_failed_to_enable">No se pudo habilitar el módulo \"%s\"</string>
<string name="module_failed_to_disable">No se pudo deshabilitar el módulo \"%s\"</string>
<string name="module_empty">No hay ningún módulo instalado</string>
<string name="module">Módulo</string>
<string name="uninstall">Desinstalar</string>
<string name="module_install">Instalar</string>
<string name="module_install">Instalar módulo</string>
<string name="install">Instalar</string>
<string name="reboot">Reiniciar</string>
<string name="settings">Ajustes</string>
<string name="reboot_userspace">Reinicio suave</string>
<string name="reboot_userspace">Reinicio minimo</string>
<string name="reboot_recovery">Reiniciar en modo de recuperación</string>
<string name="reboot_bootloader">Reiniciar en modo de arranque</string>
<string name="reboot_download">Reiniciar en modo Download</string>
<string name="reboot_edl">Reiniciar en modo EDL</string>
<string name="about">Acerca de</string>
<string name="module_uninstall_confirm">¿Está seguro de que desea desinstalar el módulo %s?</string>
<string name="module_uninstall_success">%s desinstalado</string>
<string name="module_uninstall_failed">Fallo al desinstalar: %s</string>
<string name="module_uninstall_confirm">¿Estás seguro de que quieres desinstalar el módulo \"%s\"?</string>
<string name="module_uninstall_success">\"%s\" esta desinstalado</string>
<string name="module_uninstall_failed">No se pudo desinstalar \"%s\"</string>
<string name="module_version">Versión</string>
<string name="module_author">Autor</string>
<string name="module_overlay_fs_not_available">Los módulos no están disponibles ya que OverlayFS está desactivado por el kernel.</string>
<string name="refresh">Refrescar</string>
<string name="show_system_apps">Mostrar aplicaciones del sistema</string>
<string name="hide_system_apps">Ocultar aplicaciones del sistema</string>
<string name="send_log">Enviar registros</string>
<string name="module_overlay_fs_not_available">El módulo no puede funcionar ya que OverlayFS no está disponible!</string>
<string name="refresh">Recargar</string>
<string name="show_system_apps">Mostrar applicaciones del sistema</string>
<string name="hide_system_apps">Ocultar applicaciones del sistema</string>
<string name="send_log">Enviar registro de informe</string>
<string name="safe_mode">Modo seguro</string>
<string name="reboot_to_apply">Reinicia para aplicar cambios</string>
<string name="module_magisk_conflict">¡Los módulos no están disponibles debido a un conflicto con Magisk!</string>
<string name="module_magisk_conflict">Se deshabilitaron los módulos ya que entran en conflicto con los de Magisk!</string>
<string name="home_learn_kernelsu">Aprende KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Aprende a instalar KernelSU y a utilizar módulos</string>
<string name="home_click_to_learn_kernelsu">Descubre cómo instalar KernelSU y utilizar módulos</string>
<string name="home_support_title">Apóyanos</string>
<string name="home_support_content">KernelSU es, y siempre será, gratuito y de código abierto. Sin embargo, puedes demostrarnos que te importamos haciendo una donación.</string>
<string name="about_source_code">Ver código fuente en %1$s<br></br>Únete a nuestro canal %2$s</string>
<string name="home_support_content">KernelSU es y siempre será, libre y de código abierto. De todas formas, puedes mostrarnos tu apoyo mediante una donación.</string>
<string name="about_source_code">Mirar el código en %1$s<br/>Únete a nuestro canal de %2$s</string>
<string name="profile_default">Predeterminado</string>
<string name="profile_template">Plantilla</string>
<string name="profile_custom">Personalizado</string>
@@ -63,70 +63,45 @@
<string name="profile_namespace_individual">Individual</string>
<string name="profile_groups">Grupos</string>
<string name="profile_capabilities">Capacidades</string>
<string name="profile_selinux_context">Contexto SELinux</string>
<string name="profile_selinux_context">Contexto de SELinux</string>
<string name="profile_umount_modules">Desmontar módulos</string>
<string name="failed_to_update_app_profile">Error al actualizar el perfil de la aplicación para %s</string>
<string name="failed_to_update_app_profile">No se pudo actualizar el perfil de la applicación para %s</string>
<string name="settings_umount_modules_default">Desmontar módulos por defecto</string>
<string name="settings_umount_modules_default_summary">El valor global predeterminado para \"Umount modules\" en App Profile. Si está activado, eliminará todas las modificaciones de módulos del sistema para las apps que no tengan un perfil establecido.</string>
<string name="profile_umount_modules_summary">Activar esta opción permitirá a KernelSU restaurar cualquier archivo modificado por los módulos para esta aplicación.</string>
<string name="settings_umount_modules_default_summary">El valor global predeterminado para \"Desmontar módulos\" en los perfiles de las aplicaciones. Si la habilitas, se desharán todas las modificaciones al sistema hechas por el módulo para las applicaciones que no tengan un perfil establecido.</string>
<string name="profile_umount_modules_summary">Si habilitas esta opción, KernelSU podrá restaurar cualquier archivo modificado por los módulos para esta app.</string>
<string name="profile_selinux_domain">Dominio</string>
<string name="profile_selinux_rules">Reglas</string>
<string name="module_update">Actualizar</string>
<string name="module_downloading">Descargando módulo: %s</string>
<string name="module_downloading">Descargando módulo: \"%s\"</string>
<string name="module_start_downloading">Iniciar descarga: %s</string>
<string name="new_version_available">La nueva versión %s está disponible, haga clic para actualizar.</string>
<string name="launch_app">Iniciar</string>
<string name="force_stop_app">Forzar detención</string>
<string name="restart_app">Reiniciar</string>
<string name="failed_to_update_sepolicy">Error al actualizar las reglas SELinux para: %s</string>
<string name="require_kernel_version">La versión %d actual de KernelSU es demasiado baja para que el gestor funcione correctamente. Por favor, ¡actualice a la versión %d o superior!</string>
<string name="new_version_available">Nueva versión: %s está disponible, toque para actualizar</string>
<string name="launch_app">Abrir Aplicacion</string>
<string name="force_stop_app">Forzar cierre de la aplicacion</string>
<string name="restart_app">Reiniciar aplicacion</string>
<string name="failed_to_update_sepolicy">Falló al actualizar reglas de SEpolicy por: %s</string>
<string name="require_kernel_version">La versión actual de KernelSU %d es demasiado baja para que el gestor funcione correctamente. ¡Por favor actualiza a la versión %d o superior!</string>
<string name="module_changelog">Registro de cambios</string>
<string name="app_profile_template_import_success">Importado con éxito</string>
<string name="app_profile_export_to_clipboard">Exportar al portapapeles</string>
<string name="app_profile_template_export_empty">¡No se encuentra la plantilla local para exportar!</string>
<string name="app_profile_template_id_exist">¡El ID de plantilla ya existe!</string>
<string name="app_profile_import_from_clipboard">Importar desde el portapapeles</string>
<string name="module_changelog_failed">Fallo en la obtención del registro de cambios: %s</string>
<string name="app_profile_template_import_success">Importado con exíto</string>
<string name="app_profile_export_to_clipboard">Exportar a portapapeles</string>
<string name="app_profile_template_export_empty">No se puede encontrar plantilla local para exportar!</string>
<string name="app_profile_template_id_exist">Ya existe un ID de la plantilla!</string>
<string name="app_profile_import_from_clipboard">Importar desde portapapeles</string>
<string name="module_changelog_failed">Error en obtener los registros de cambios: %s</string>
<string name="app_profile_template_name">Nombre</string>
<string name="app_profile_template_id_invalid">ID de plantilla no válida</string>
<string name="app_profile_template_sync">Sincronizar plantillas en línea</string>
<string name="app_profile_template_id_invalid">ID de la plantilla es invalido</string>
<string name="app_profile_template_sync">Sincronizar plantillas en linea</string>
<string name="app_profile_template_create">Crear plantilla</string>
<string name="app_profile_template_readonly">lo lectura</string>
<string name="app_profile_template_readonly">sololectura</string>
<string name="app_profile_import_export">Importar/Exportar</string>
<string name="app_profile_template_save_failed">No se ha podido guardar la plantilla</string>
<string name="app_profile_template_save_failed">Fallo en guardar plantilla</string>
<string name="app_profile_template_edit">Editar plantilla</string>
<string name="app_profile_template_id">ID</string>
<string name="settings_profile_template">Plantilla de perfil de aplicación</string>
<string name="app_profile_template_id">id</string>
<string name="settings_profile_template">Plantilla del perfil de la aplicacion</string>
<string name="app_profile_template_description">Descripción</string>
<string name="app_profile_template_save">Guardar</string>
<string name="settings_profile_template_summary">Gestionar la plantilla local y en línea de App Profile</string>
<string name="settings_profile_template_summary">Administrar las plantillas locales y de en linea del perfil de la aplicacion</string>
<string name="app_profile_template_delete">Eliminar</string>
<string name="app_profile_template_import_empty">¡El portapapeles está vacío!</string>
<string name="app_profile_template_import_empty">El portapapeles esta vacio!</string>
<string name="app_profile_template_view">Ver plantilla</string>
<string name="save_log">Guardar registros</string>
<string name="enable_web_debugging">Activar la depuración de WebView</string>
<string name="select_file_tip">Se recomienda la imagen de partición %1$s</string>
<string name="select_kmi">Selecciona KMI</string>
<string name="install_next">Siguiente</string>
<string name="direct_install">Instalación directa (Recomendada)</string>
<string name="install_inactive_slot_warning">¡Su dispositivo será **FORZADO** a arrancar en la ranura inactiva actual después de un reinicio!\nUtilice esta opción sólo después de que la OTA se haya realizado.\n¿Continuar?</string>
<string name="settings_uninstall">Desinstalar</string>
<string name="settings_restore_stock_image">Restaurar imagen de archivo</string>
<string name="settings_uninstall_temporary_message">Desinstalar temporalmente KernelSU, restaurar al estado original tras el siguiente reinicio.</string>
<string name="selected_lkm">LKM seleccionado: %s</string>
<string name="flash_failed">Flash falló</string>
<string name="flash_success">Éxito de Flash</string>
<string name="grant_root_failed">¡No se ha podido conceder el acceso root!</string>
<string name="open">Abrir</string>
<string name="select_file">Seleccione un archivo</string>
<string name="install_inactive_slot">Instalar en ranura inactiva (Después de OTA)</string>
<string name="settings_uninstall_temporary">Desinstalar temporalmente</string>
<string name="settings_uninstall_permanent">Desinstalar permanentemente</string>
<string name="settings_uninstall_permanent_message">Desinstalar KernelSU (Root y todos los módulos) completa y permanentemente.</string>
<string name="shrink_sparse_image_message">Redimensiona la imagen dispersa donde se encuentra el módulo a su tamaño real. Tenga en cuenta que esto puede hacer que el módulo funcione de forma anormal, por lo que sólo debe utilizarlo cuando sea necesario (por ejemplo, para realizar copias de seguridad).</string>
<string name="settings_check_update">Comprobar actualización</string>
<string name="settings_check_update_summary">Comprobación automática de actualizaciones al abrir la aplicación</string>
<string name="shrink_sparse_image">Minimizar la imagen dispersa</string>
<string name="enable_web_debugging_summary">Puede ser usado para depurar WebUI, por favor habilítalo sólo cuando sea necesario.</string>
<string name="settings_restore_stock_image_message">Restaurar la imagen de fábrica stock (Si existe una copia de seguridad), por lo general se utiliza antes de OTA; si necesita desinstalar KernelSU, por favor, utilice \"Desinstalar permanentemente\".</string>
</resources>
<string name="save_log">Guardar Registros</string>
</resources>

View File

@@ -12,8 +12,8 @@
<string name="reboot">Taaskäivita</string>
<string name="reboot_recovery">Taaskäivita taastusesse</string>
<string name="module_uninstall_confirm">Kas soovid kindlasti eemaldada mooduli %s?</string>
<string name="module_uninstall_success">%s eemaldatud</string>
<string name="send_log">Saada logid</string>
<string name="module_uninstall_success">%s on eemaldatud</string>
<string name="send_log">Raporteeri logi</string>
<string name="safe_mode">Turvarežiim</string>
<string name="reboot_to_apply">Muudatuste rakendamiseks taaskäivita</string>
<string name="home_learn_kernelsu">Õpi KernelSUd</string>
@@ -28,8 +28,8 @@
<string name="app_profile_template_edit">Muuda malli</string>
<string name="settings_profile_template">Rakenduseprofiili mall</string>
<string name="app_profile_template_id">ID</string>
<string name="app_profile_template_readonly">Vaid lugemiseks</string>
<string name="app_profile_template_id_exist">Malli ID juba eksisteerib!</string>
<string name="app_profile_template_readonly">vaid lugemiseks</string>
<string name="app_profile_template_id_exist">malli ID juba eksisteerib!</string>
<string name="app_profile_export_to_clipboard">Ekspordi lõikelauale</string>
<string name="app_profile_template_sync">Sünkrooni võrgumallid</string>
<string name="module_changelog_failed">Muudatuste logi hankimine ebaõnnestus: %s</string>
@@ -59,16 +59,16 @@
<string name="module_author">Autor</string>
<string name="module_uninstall_failed">Eemaldamine ebaõnnestus: %s</string>
<string name="module_version">Versioon</string>
<string name="module_overlay_fs_not_available">Moodulid pole saadaval, kuna OverlayFS on kernelis keelatud.</string>
<string name="module_overlay_fs_not_available">overlayfs pole saadaval, moodul ei saa töötada!</string>
<string name="show_system_apps">Kuva süsteemirakendused</string>
<string name="hide_system_apps">Peida süsteemirakendused</string>
<string name="module_magisk_conflict">Moodulid pole saadaval Magiski konflikti tõttu!</string>
<string name="module_magisk_conflict">Moodulid on keelatud, kuna need lähevad konflikti Magiski omadega!</string>
<string name="home_click_to_learn_kernelsu">Õpi KernelSUd paigaldama ja mooduleid kasutama</string>
<string name="home_support_title">Toeta meid</string>
<string name="profile_groups">Grupid</string>
<string name="home_support_content">KernelSU on, ja alati jääb, tasuta ning avatud lähtekoodiga kättesaadavaks. Sellegipoolest võid sa näidata, et hoolid, ning teha annetuse.</string>
<string name="profile_template">Mall</string>
<string name="about_source_code">Vaata lähtekoodi %1$sis<br></br>Liitu meie %2$si kanaliga</string>
<string name="about_source_code">Vaata lähtekoodi %1$sis<br/>Liitu meie %2$si kanaliga</string>
<string name="profile_name">Profiili nimi</string>
<string name="profile_custom">Kohandatud</string>
<string name="profile_namespace_inherited">Päritud</string>
@@ -77,14 +77,14 @@
<string name="profile_capabilities">Võimekused</string>
<string name="app_profile_template_id_invalid">Sobimatu malli ID</string>
<string name="profile_selinux_context">SELinux kontekst</string>
<string name="require_kernel_version">Praegune KernelSU versioon %d on liiga madal, haldur ei saa korrektselt töötada. Palun täienda versioonile %d või kõrgem!</string>
<string name="require_kernel_version">Praegune KernelSU versioon %d on liiga madal, haldur ei saa konkreetselt toimida. Palun täienda versioonile %d või kõrgem!</string>
<string name="profile_selinux_domain">Domeen</string>
<string name="launch_app">Käivita</string>
<string name="force_stop_app">Sundpeata</string>
<string name="profile_selinux_rules">Reeglid</string>
<string name="module_update">Uuenda</string>
<string name="module_downloading">Mooduli allalaadimine: %s</string>
<string name="new_version_available">Uus versioon %s on saadaval, klõpsa täiendamiseks.</string>
<string name="new_version_available">Uus versioon: %s on saadaval, klõpsa täiendamiseks</string>
<string name="restart_app">Taaskäivita</string>
<string name="module_changelog">Muudatuste logi</string>
<string name="app_profile_template_name">Nimi</string>
@@ -100,8 +100,8 @@
<string name="app_profile_template_create">Loo mall</string>
<string name="settings_profile_template_summary">Halda kohalikke ja võrgusolevaid rakenduseprofiili malle</string>
<string name="profile_umount_modules_summary">Selle valiku lubamine lubab KernelSU-l taastada selle rakenduse moodulite poolt mistahes muudetud faile.</string>
<string name="app_profile_template_export_empty">Ei saa eksportida, kohalikku malli ei leitud!</string>
<string name="settings_umount_modules_default_summary">Globaalne vaikeväärtus \"Lahtihaagitud moodulitele\" rakenduseprofiilis. Lubamisel eemaldab see kõik moodulite süsteemimuudatused rakendustele, millel ei ole profiili määratud.</string>
<string name="app_profile_template_export_empty">Eksportimiseks kohalikku malli ei leitud!</string>
<string name="settings_umount_modules_default_summary">Globaalne vaikeväärtus \"Lahtihaagitud moodulitele\" rakenduseprofiilides. Lubamisel eemaldab see kõik moodulite süsteemimuudatused rakendustele, millel ei ole profiili määratud.</string>
<string name="enable_web_debugging_summary">Saab kasutada WebUI silumiseks, palun luba ainult vajadusel.</string>
<string name="grant_root_failed">Juurkasutaja andmine ebaõnnestus!</string>
<string name="settings_check_update">Kontrolli uuendusi</string>
@@ -109,22 +109,4 @@
<string name="open">Ava</string>
<string name="enable_web_debugging">Luba WebView silumine</string>
<string name="save_log">Salvesta Logid</string>
<string name="select_kmi">Vali KMI</string>
<string name="select_file_tip">%1$s partitsioonitõmmis on soovitatud</string>
<string name="install_next">Edasi</string>
<string name="install_inactive_slot_warning">Sinu seade **SUNNITAKSE** pärast taaskäivitust ebaaktiivsesse lahtrisse käivituma!\nKasuta seda valikut vaid siis, kui tegid üle-õhu uuenduse.\nJätkad?</string>
<string name="settings_uninstall">Eemalda</string>
<string name="settings_uninstall_temporary_message">Eemalda KernelSU ajutiselt, taasta pärast taaskäivitust algseisu.</string>
<string name="settings_uninstall_permanent_message">KernelSU eemaldamine (juurkasutaja ja kõik moodulid) täielikult ja püsivalt.</string>
<string name="settings_restore_stock_image_message">Taasta tehase-vaiketõmmis (kui varundus eksisteerib), tavaliselt kasutatakse enne üle-õhu uuendust; kui soovid KernelSU-d eemaldada, palun kasuta \"Eemalda püsivalt\".</string>
<string name="flashing">Välgutamine</string>
<string name="flash_success">Välgutamine õnnestus</string>
<string name="flash_failed">Välgutamine ebaõnnestus</string>
<string name="selected_lkm">Valitud LKM: %s</string>
<string name="direct_install">Otsene paigaldus (soovitatud)</string>
<string name="select_file">Vali fail</string>
<string name="install_inactive_slot">Paigalda ebaaktiivsesse lahtrisse (pärast üle-õhu uuendust)</string>
<string name="settings_uninstall_temporary">Eemalda ajutiselt</string>
<string name="settings_uninstall_permanent">Eemalda püsivalt</string>
<string name="settings_restore_stock_image">Taasta vaikimisi tõmmis</string>
</resources>
</resources>

View File

@@ -1,68 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home">خانه</string>
<string name="home_not_installed">نصب نشده است</string>
<string name="home_click_to_install">برای نصب ضربه بزنید</string>
<string name="home_working">به درستی کار می‌کند</string>
<string name="home_working_version">نسخه: %d</string>
<string name="home_superuser_count">برنامه های با دسترسی روت: %d</string>
<string name="home_module_count">ماژول‌ها: %d</string>
<string name="home_unsupported">پشتیبانی نشده</string>
<string name="home_unsupported_reason">کرنل اس یو فقط هسته های gki را پشتیبانی میکند</string>
<string name="home">خانه</string>
<string name="home_not_installed">نصب نشده است</string>
<string name="home_click_to_install">برای نصب ضربه بزنید</string>
<string name="home_working">به درستی کار می‌کند</string>
<string name="home_working_version">نسخه: %d</string>
<string name="home_superuser_count">برنامه های با دسترسی روت: %d</string>
<string name="home_module_count">ماژول‌ها: %d</string>
<string name="home_unsupported">پشتیبانی نشده</string>
<string name="home_unsupported_reason">کرنل اس یو فقط هسته های gki را پشتیبانی میکند</string>
<string name="home_kernel">هسته</string>
<string name="home_manager_version">نسخه برنامه</string>
<string name="home_fingerprint">اثرانگشت</string>
<string name="home_selinux_status">وضعیت SELinux</string>
<string name="selinux_status_disabled">غیرفعال</string>
<string name="selinux_status_enforcing">قانونمند</string>
<string name="selinux_status_permissive">آزاد</string>
<string name="selinux_status_unknown">ناشناخته</string>
<string name="superuser">دسترسی روت</string>
<string name="selinux_status_disabled">غیرفعال</string>
<string name="selinux_status_enforcing">قانونمند</string>
<string name="selinux_status_permissive">آزاد</string>
<string name="selinux_status_unknown">ناشناخته</string>
<string name="superuser">دسترسی روت</string>
<string name="module_failed_to_enable">فعال کردن ماژول ناموفق بود: %s</string>
<string name="module_failed_to_disable">غیرفعال کردن ماژول ناموفق بود: %s</string>
<string name="module_empty">هیچ ماژولی نصب نشده است</string>
<string name="module">ماژول</string>
<string name="uninstall">لغو نصب</string>
<string name="module_install">نصب</string>
<string name="install">نصب</string>
<string name="reboot">راه اندازی دوباره</string>
<string name="settings">تنظیمات</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="about">درباره</string>
<string name="module_failed_to_disable">غیرفعال کردن ماژول ناموفق بود: %s</string>
<string name="module_empty">هیچ ماژولی نصب نشده است</string>
<string name="module">ماژول</string>
<string name="uninstall">لغو نصب</string>
<string name="module_install">نصب</string>
<string name="install">نصب</string>
<string name="reboot">راه اندازی دوباره</string>
<string name="settings">تنظیمات</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="about">درباره</string>
<string name="module_uninstall_confirm">آیا مطمئنید که میخواهید ماژول %s را پاک کنید؟</string>
<string name="module_uninstall_success">%s پاک شد</string>
<string name="module_uninstall_failed">پاک کردن ناموفق بود: %s</string>
<string name="module_version">نسخه</string>
<string name="module_author">سازنده</string>
<string name="module_overlay_fs_not_available">overlayfs موجود نیست. مازول کار نمیکند!!</string>
<string name="refresh">تازه‌سازی</string>
<string name="show_system_apps">نمایش برنامه های سیستمی</string>
<string name="hide_system_apps">مخفی کردن برنامه های سیستمی</string>
<string name="send_log">ارسال وقایع</string>
<string name="safe_mode">حالت امن</string>
<string name="reboot_to_apply">راه‌اندازی مجدد برای تاثیرگذاری</string>
<string name="module_magisk_conflict">مازول به دلیل تعارض با مجیسک غیرفعال شده اند\'s!</string>
<string name="home_learn_kernelsu">یادگیری کرنل اس یو</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">یاد بگیرید چگونه از کرنل اس یو و ماژول ها استفاده کنید</string>
<string name="home_support_title">از ما حمایت کنید</string>
<string name="home_support_content">KernelSU رایگان است و همیشه خواهد بود و منبع باز است. با این حال، می توانید با اهدای کمک مالی به ما نشان دهید که برایتان مهم است.</string>
<string name="about_source_code">
<string name="module_uninstall_success">%s پاک شد</string>
<string name="module_uninstall_failed">پاک کردن ناموفق بود: %s</string>
<string name="module_version">نسخه</string>
<string name="module_author">سازنده</string>
<string name="module_overlay_fs_not_available">overlayfs موجود نیست. مازول کار نمیکند!!</string>
<string name="refresh">تازه‌سازی</string>
<string name="show_system_apps">نمایش برنامه های سیستمی</string>
<string name="hide_system_apps">مخفی کردن برنامه های سیستمی</string>
<string name="send_log">ارسال وقایع</string>
<string name="safe_mode">حالت امن</string>
<string name="reboot_to_apply">راه‌اندازی مجدد برای تاثیرگذاری</string>
<string name="module_magisk_conflict">مازول به دلیل تعارض با مجیسک غیرفعال شده اند\'s!</string>
<string name="home_learn_kernelsu">یادگیری کرنل اس یو</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">یاد بگیرید چگونه از کرنل اس یو و ماژول ها استفاده کنید</string>
<string name="home_support_title">از ما حمایت کنید</string>
<string name="home_support_content">KernelSU رایگان است و همیشه خواهد بود و منبع باز است. با این حال، می توانید با اهدای کمک مالی به ما نشان دهید که برایتان مهم است.</string>
<string name="about_source_code">
<![CDATA[ View source code at %1$s<br/>Join our %2$s channel ]]>
</string>
<string name="profile">پروفایل برنامه</string>
<string name="profile_default">پیش‌فرض</string>
<string name="profile_template">قالب</string>
<string name="profile_custom">شخصی سازی شده</string>
<string name="profile_name">اسم پروفایل</string>
<string name="profile_namespace">Mount namespace</string>
<string name="profile_namespace_inherited">اثر گرفته</string>
<string name="profile_namespace_global">گلوبال</string>
<string name="profile_namespace_individual">تکی</string>
<string name="profile_umount_modules">جداکردن ماژول ها</string>
<string name="profile">پروفایل برنامه</string>
<string name="profile_default">پیش‌فرض</string>
<string name="profile_template">قالب</string>
<string name="profile_custom">شخصی سازی شده</string>
<string name="profile_name">اسم پروفایل</string>
<string name="profile_namespace">Mount namespace</string>
<string name="profile_namespace_inherited">اثر گرفته</string>
<string name="profile_namespace_global">گلوبال</string>
<string name="profile_namespace_individual">تکی</string>
<string name="profile_umount_modules">جداکردن ماژول ها</string>
<string name="save_log">ذخیره گزارش‌ها</string>
</resources>

View File

@@ -1,62 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home_selinux_status">Katayuan ng SELinux</string>
<string name="selinux_status_disabled">Naka-disable</string>
<string name="selinux_status_disabled">Hindi pinagana</string>
<string name="selinux_status_enforcing">Enforcing</string>
<string name="selinux_status_permissive">Permissive</string>
<string name="home_not_installed">Hindi naka-install</string>
<string name="home">Panimula</string>
<string name="home_click_to_install">I-click para i-install</string>
<string name="home">Home</string>
<string name="home_click_to_install">Pindutin para mag-install</string>
<string name="home_working">Gumagana</string>
<string name="home_working_version">Bersyon: %d</string>
<string name="selinux_status_unknown">Hindi matukoy</string>
<string name="home_module_count">Mga Modyul: %d</string>
<string name="home_unsupported">Hindi Suportado</string>
<string name="home_unsupported_reason">Sinusuportahan lamang ng KernelSU ang mga GKI na kernel</string>
<string name="module_failed_to_enable">Nabigong paganahin ang module: %s</string>
<string name="module_failed_to_disable">Nabigong i-disable ang module: %s</string>
<string name="home_unsupported_reason">Sinusuportahan lang ng KernelSU ang mga kernel ng GKI ngayon</string>
<string name="module_failed_to_enable">Nabigong paganahin ang modyul: %s</string>
<string name="module_failed_to_disable">Nabigong i-disable ang modyul: %s</string>
<string name="module_empty">Walang naka-install na modyul</string>
<string name="module">Modyul</string>
<string name="module_install">I-install</string>
<string name="install">I-install</string>
<string name="reboot">I-reboot</string>
<string name="reboot_userspace">I-soft reboot</string>
<string name="reboot_userspace">I-soft Reboot</string>
<string name="reboot_download">I-reboot sa Download</string>
<string name="reboot_edl">I-reboot sa EDL</string>
<string name="about">Tungkol</string>
<string name="module_uninstall_confirm">Sigurado ka bang gusto mong i-uninstall ang module na %s?</string>
<string name="module_uninstall_confirm">Sigurado ka bang gusto mong i-uninstall ang modyul %s\?</string>
<string name="module_uninstall_success">Na-uninstall ang %s</string>
<string name="module_uninstall_failed">Nabigong i-uninstall: %s</string>
<string name="module_author">May-akda</string>
<string name="module_overlay_fs_not_available">Hindi available ang mga module dahil na-disable ng kernel ang OverlayFS!</string>
<string name="module_overlay_fs_not_available">Ang overlayfs ay hindi magagamit, ang modyul ay hindi gagana!</string>
<string name="refresh">I-refresh</string>
<string name="show_system_apps">Ipakita ang mga application ng system</string>
<string name="send_log">Ipadala ang mga log</string>
<string name="send_log">Magpadala ng Log</string>
<string name="reboot_to_apply">I-reboot para umepekto</string>
<string name="module_magisk_conflict">Hindi magagamit ang mga module dahil sa isang salungatan sa Magisk!</string>
<string name="module_magisk_conflict">Hindi pinagana ang mga modyul dahil salungat ito sa Magisk!</string>
<string name="home_learn_kernelsu">Alamin ang KernelSU</string>
<string name="home_click_to_learn_kernelsu">Matuto kung paano i-install ang KernelSU at gumamit ng mga module</string>
<string name="home_click_to_learn_kernelsu">Matutunan kung paano mag-install ng KernelSU at gumamit ng mga modyul</string>
<string name="home_support_title">Suportahan Kami</string>
<string name="home_support_content">Ang KernelSU ay, at palaging magiging, libre, at open source. Gayunpaman, maaari mong ipakita sa amin na nagmamalasakit ka sa pamamagitan ng pagbibigay ng donasyon.</string>
<string name="about_source_code"><![CDATA[Tignan ang source code sa %1$s<br/>Sumali sa aming %2$s channel]]></string>
<string name="about_source_code">Tingnan ang source code sa %1$s<br/>Sumali sa aming %2$s channel</string>
<string name="profile_namespace">I-mount ang namespace</string>
<string name="profile_namespace_individual">Indibidwal</string>
<string name="profile_groups">Mga Grupo</string>
<string name="profile_capabilities">Mga Kakayanan</string>
<string name="profile_selinux_context">Konteksto ng SELinux</string>
<string name="profile_umount_modules">I-unmount ang mga module</string>
<string name="profile_umount_modules">I-unmount ang mga modyul</string>
<string name="failed_to_update_app_profile">Nabigong i-update ang App Profile para sa %s</string>
<string name="require_kernel_version">Ang kasalukuyang bersyon ng KernelSU %d ay masyadong mababa para gumana nang maayos ang manager. Mangyaring mag-upgrade sa bersyon %d o mas mataas!</string>
<string name="profile_umount_modules_summary">Ang pag-enable sa opsyong ito ay magbibigay-daan sa KernelSU na ibalik ang anumang binagong file ng mga module para sa app na ito.</string>
<string name="profile_umount_modules_summary">Ang pagpapagana sa opsyong ito ay magbibigay-daan sa KernelSU na ibalik ang anumang binagong file ng mga modyul para sa aplikasyon na ito.</string>
<string name="profile_selinux_rules">Mga Tuntunin</string>
<string name="module_downloading">Nagda-download ng modyul: %s</string>
<string name="module_start_downloading">Simulan ang pag-download: %s</string>
<string name="new_version_available">Bagong bersyon: Available ang %s, i-click para mag-upgrade.</string>
<string name="new_version_available">Bagong bersyon: Available ang %s, i-click upang i-download</string>
<string name="launch_app">Ilunsad</string>
<string name="force_stop_app">Sapilitang itigil</string>
<string name="force_stop_app">Pilit na I-hinto</string>
<string name="restart_app">I-restart</string>
<string name="failed_to_update_sepolicy">Nabigong i-update ang mga panuntunan ng SELinux para sa: %s</string>
<string name="home_manager_version">Bersyon ng manager</string>
<string name="home_manager_version">Bersyon ng Manager</string>
<string name="settings">Mga setting</string>
<string name="reboot_recovery">I-reboot sa Recovery</string>
<string name="reboot_bootloader">I-reboot sa Bootloader</string>
@@ -67,75 +67,4 @@
<string name="profile_namespace_inherited">Minana</string>
<string name="settings_umount_modules_default_summary">Ang pangkalahatang default na halaga para sa \"Umount modules\" sa Mga Profile ng App. Kung pinagana, aalisin nito ang lahat ng mga pagbabago sa modyul sa system para sa mga aplikasyon na walang hanay ng Profile.</string>
<string name="save_log">I-save ang mga Log</string>
<string name="home_superuser_count">Mga Superuser: %d</string>
<string name="home_kernel">Bersyon ng kernel</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="superuser">Superuser</string>
<string name="module_install_prompt_with_name">Ii-install ang mga sumusunod na module: %1$s</string>
<string name="module_sort_action_first">Isaayos (Aksyon muna)</string>
<string name="module_sort_enabled_first">Isaayos (Pinagana muna)</string>
<string name="confirm">Kumpirmahin</string>
<string name="safe_mode">Safe mode</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="profile_default">Default</string>
<string name="profile_template">Template</string>
<string name="profile_custom">Pasadya</string>
<string name="profile_namespace_global">Global</string>
<string name="settings_umount_modules_default">I-unmount ang mga module bilang default</string>
<string name="profile_selinux_domain">Domain</string>
<string name="module_update">I-update</string>
<string name="su_not_allowed">Hindi mabigay ang Superuser access sa %s</string>
<string name="module_changelog">Mga pagbabago</string>
<string name="settings_profile_template">Template ng App Profile</string>
<string name="settings_profile_template_summary">Ipamahala ang lokal at online na template ng App Profile</string>
<string name="app_profile_template_create">Gumawa ng template</string>
<string name="app_profile_template_edit">I-edit ang template</string>
<string name="app_profile_template_id">ID</string>
<string name="app_profile_template_id_invalid">Hindi wastong template ID</string>
<string name="app_profile_template_name">Pangalan</string>
<string name="app_profile_template_description">Paksa</string>
<string name="app_profile_template_save">I-save</string>
<string name="app_profile_template_delete">Burahin</string>
<string name="app_profile_template_view">Tignan ang template</string>
<string name="app_profile_template_readonly">Read only</string>
<string name="app_profile_template_id_exist">Umiiral na ang Template ID!</string>
<string name="app_profile_import_export">I-import/I-export</string>
<string name="app_profile_import_from_clipboard">Mag-import mula sa clipboard</string>
<string name="app_profile_export_to_clipboard">I-export sa clipboard</string>
<string name="app_profile_template_export_empty">Hindi makahanap ng lokal na template na ie-export!</string>
<string name="app_profile_template_import_success">Matagumpay na na-import</string>
<string name="app_profile_template_sync">I-sync ang mga online template</string>
<string name="app_profile_template_save_failed">Nabigong i-save ang template</string>
<string name="app_profile_template_import_empty">Walang laman ang clipboard!</string>
<string name="module_changelog_failed">Nabigong kunin ang mga pagbabago: %s</string>
<string name="settings_check_update">Tumingin para sa mga update</string>
<string name="settings_check_update_summary">Awtomatikong tumingin para sa mga update kapag binubuksan ang app</string>
<string name="grant_root_failed">Nabigong ibigay ang root!</string>
<string name="action">Aksyon</string>
<string name="open">Buksan</string>
<string name="enable_web_debugging">I-enable ang pag-debug ng WebView</string>
<string name="enable_web_debugging_summary">Maaaring gamitin para i-debug ang WebUI. Mangyaring paganahin kung kinakailangan lang.</string>
<string name="direct_install">Direktang pag-install (Inirerekomenda)</string>
<string name="select_file">Pumili ng file</string>
<string name="install_inactive_slot">I-install sa hindi aktibong slot (Pagkatapos ng OTA)</string>
<string name="install_inactive_slot_warning">Ang iyong device ay **PIPILITIN** na i-boot sa kasalukuyang hindi aktibong slot pagkatapos ng reboot!\nGamitin lamang ang opsyon na ito kung tapos na ang OTA.\nMagpatuloy?</string>
<string name="install_next">Susunod</string>
<string name="select_file_tip">Inirerekomenda ang %1$s partition image</string>
<string name="select_kmi">Pumili ng KMI</string>
<string name="shrink_sparse_image">Paliitin ang sparse image</string>
<string name="shrink_sparse_image_message">Baguhin ang laki ng sparse image kung saan matatagpuan ang module sa aktwal na laki nito. Tandaan na ito ay maaaring maging sanhi ng hindi normal na paggana ng module, kaya mangyaring gamitin lamang kung kinakailangan (Gaya ng para sa backup).</string>
<string name="settings_uninstall">I-uninstall</string>
<string name="settings_uninstall_temporary">Pansamantalang i-uninstall</string>
<string name="settings_uninstall_permanent">Permanenteng i-uninstall</string>
<string name="settings_restore_stock_image">Ibalik ang stock image</string>
<string name="settings_uninstall_temporary_message">Pansamantalang i-uninstall ang KernelSU, ibabalik sa orihinal na kalagayan pagkatapos ng susunod na reboot.</string>
<string name="settings_uninstall_permanent_message">Ina-uninstall ang KernelSU (Root at lahat ng mga module) nang tuluyan at permanente.</string>
<string name="settings_restore_stock_image_message">Ibalik ang stock factory image (kung may umiiral na backup), kadalasan na ginagamit bago ng OTA; kung kailangan mong i-uninstall ang KernelSU, mangyaring gamitin ang \"Permanenteng i-uninstall\".</string>
<string name="flashing">Nagfa-flash</string>
<string name="flash_success">Matagumpay ang pag-flash</string>
<string name="flash_failed">Nabigo ang pag-flash</string>
<string name="selected_lkm">Piniling LKM: %s</string>
<string name="log_saved">Nai-save ang mga log</string>
<string name="settings_disable_su">I-disable ang su compatibility</string>
<string name="settings_disable_su_summary">Pansamantalang i-disable ang kakayahan ng anumang app na makakuha ng pribilehiyong root sa pamamagitan ng su command (Hindi maaapektuhan ang mga umiiral na root process).</string>
</resources>
</resources>

View File

@@ -5,8 +5,8 @@
<string name="home_working_version">Version : %d</string>
<string name="home_superuser_count">Super-utilisateurs : %d</string>
<string name="home_module_count">Modules: %d</string>
<string name="home_unsupported_reason">KernelSU ne prend désormais en charge que les noyaux GKI</string>
<string name="home_kernel">Version du noyau</string>
<string name="home_unsupported_reason">Actuellement, KernelSU ne supporte que les noyaux GKI</string>
<string name="home_kernel">Noyau</string>
<string name="home_fingerprint">Empreinte digitale</string>
<string name="home_selinux_status">Mode SELinux</string>
<string name="selinux_status_disabled">Désactivé</string>
@@ -16,21 +16,21 @@
<string name="module_empty">Aucun module installé</string>
<string name="home">Accueil</string>
<string name="home_click_to_install">Appuyez ici pour installer</string>
<string name="home_unsupported">Non pris en charge</string>
<string name="module_uninstall_failed">Échec de la désinstallation : %s</string>
<string name="home_unsupported">Non supporté</string>
<string name="module_uninstall_failed">Échec de la désinstallation : %s</string>
<string name="module_version">Version</string>
<string name="home_manager_version">Version du gestionnaire</string>
<string name="selinux_status_enforcing">Enforcing</string>
<string name="module_failed_to_enable">Échec de l\'activation du module : %s</string>
<string name="module_failed_to_enable">Échec de l\'activation du module : %s</string>
<string name="module">Modules</string>
<string name="uninstall">Désinstaller</string>
<string name="module_install">Installer</string>
<string name="module_failed_to_disable">Échec de la désactivation du module : %s</string>
<string name="module_failed_to_disable">Échec de la désactivation du module: %s</string>
<string name="reboot">Redémarrer</string>
<string name="install">Installer</string>
<string name="settings">Paramètres</string>
<string name="reboot_bootloader">Redémarrer en mode bootloader</string>
<string name="reboot_userspace">Redémarrage logiciel</string>
<string name="reboot_userspace">Redémarrage progressif</string>
<string name="reboot_recovery">Redémarrer en mode de récupération</string>
<string name="reboot_edl">Redémarrer en mode EDL</string>
<string name="about">À propos</string>
@@ -39,19 +39,20 @@
<string name="module_author">Auteur</string>
<string name="module_uninstall_confirm">Êtes-vous sûr(e) de vouloir désinstaller le module %s\?</string>
<string name="home_learn_kernelsu">Découvrir KernelSU</string>
<string name="module_overlay_fs_not_available">Les modules sont indisponibles car OverlayFS est désactivé par le noyau!</string>
<string name="module_overlay_fs_not_available">OverlayFS est indisponible, impossible de faire fonctionner les modules!</string>
<string name="refresh">Rafraîchir</string>
<string name="show_system_apps">Afficher les applications système</string>
<string name="hide_system_apps">Masquer les applications système</string>
<string name="safe_mode">Mode sans échec</string>
<string name="send_log">Envoyer les journaux</string>
<string name="send_log">Rapport de journal</string>
<string name="reboot_to_apply">Redémarrez pour appliquer les modifications</string>
<string name="module_magisk_conflict">Les modules sont indisponibles en raison d\'un conflit avec Magisk!</string>
<string name="module_magisk_conflict">Les modules sont désactivés car ils sont en conflit avec ceux de Magisk !</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_support_title">Soutenez-nous</string>
<string name="home_click_to_learn_kernelsu">Découvrez comment installer KernelSU et utiliser les modules</string>
<string name="home_support_content">KernelSU est, et restera toujours, gratuit et open source. Vous pouvez cependant nous témoigner de votre soutien en nous faisant un don.</string>
<string name="about_source_code"><![CDATA[Voir le code source à %1$s<br/>Rejoignez notre canal %2$s]]></string>
<string name="about_source_code">Voir le code source sur %1$s<br/>
\nRejoindre notre canal %2$s</string>
<string name="profile_template">Modèle</string>
<string name="profile_default">Par défaut</string>
<string name="profile_custom">Personnalisé</string>
@@ -65,36 +66,36 @@
<string name="profile_capabilities">Capacités</string>
<string name="profile_umount_modules">Démonter les modules</string>
<string name="failed_to_update_app_profile">Échec de la modification du profil d\'application de %s</string>
<string name="profile_umount_modules_summary">L\'activation de cette option permettra à KernelSU de restaurer tous les fichiers modifiés par les modules pour cette application.</string>
<string name="profile_umount_modules_summary">L\'activation de cette option permettra à KernelSU de restaurer tous les fichiers modifiés par les modules de cette application.</string>
<string name="settings_umount_modules_default">Démonter les modules par défaut</string>
<string name="settings_umount_modules_default_summary">Valeur globale par défaut pour l\'option \"Démonter les modules\" dans les profils d\'application. Lorsque l\'option est activée, les modifications apportées au système par les modules sont supprimées pour les applications qui n\'ont pas de profil défini.</string>
<string name="settings_umount_modules_default_summary">Valeur globale par défaut pour l\'option « Démonter les modules » dans les profils d\'application. Lorsqu\'elle est activée, les modifications apportées au système par les modules seront supprimées pour les applications qui n\'ont pas de profil défini.</string>
<string name="profile_selinux_domain">Domaine</string>
<string name="profile_selinux_rules">Règles</string>
<string name="module_update">Mettre à jour</string>
<string name="module_downloading">Téléchargement du module : %s</string>
<string name="launch_app">Lancer</string>
<string name="new_version_available">La nouvelle version %s est disponible, appuyez ici pour mettre à jour.</string>
<string name="new_version_available">La version %s est disponible, appuyez ici pour mettre à jour</string>
<string name="module_start_downloading">Début du téléchargement de : %s</string>
<string name="force_stop_app">Forcer l\'arrêt</string>
<string name="restart_app">Relancer l\'application</string>
<string name="failed_to_update_sepolicy">Échec de la mise à jour des règles SELinux pour %s</string>
<string name="failed_to_update_sepolicy">Échec de la mise à jour des règles SELinux pour: %s</string>
<string name="require_kernel_version">La version actuelle de KernelSU (%d) est trop ancienne pour que le gestionnaire fonctionne correctement. Veuillez passer à la version %d ou à une version supérieure!</string>
<string name="app_profile_template_import_success">Importation réussie</string>
<string name="app_profile_export_to_clipboard">Exporter vers le presse-papiers</string>
<string name="app_profile_template_export_empty">Impossible de trouver un modèle local à exporter!</string>
<string name="app_profile_template_id_exist">L\'ID du modèle existe déjà!</string>
<string name="app_profile_template_export_empty">Impossible de trouver un modèle local à exporter !</string>
<string name="app_profile_template_id_exist">L\'id du modèle existe déjà !</string>
<string name="module_changelog">Journal des modifications</string>
<string name="app_profile_import_from_clipboard">Importer à partir du presse-papiers</string>
<string name="module_changelog_failed">Échec de récupération du journal des modifications : %s</string>
<string name="app_profile_template_name">Nom</string>
<string name="app_profile_template_id_invalid">ID de modèle invalide</string>
<string name="app_profile_template_id_invalid">id de modèle invalide</string>
<string name="app_profile_template_sync">Synchroniser les modèles en ligne</string>
<string name="app_profile_template_create">Créer un modèle</string>
<string name="app_profile_template_readonly">Lecture seule</string>
<string name="app_profile_template_readonly">lecture seule</string>
<string name="app_profile_import_export">Importer/exporter</string>
<string name="app_profile_template_save_failed">Échec de l\'enregistrement du modèle</string>
<string name="app_profile_template_edit">Modifier le modèle</string>
<string name="app_profile_template_id">ID</string>
<string name="app_profile_template_id">id</string>
<string name="settings_profile_template">Modèles de profils d\'application</string>
<string name="app_profile_template_description">Description</string>
<string name="app_profile_template_save">Enregistrer</string>
@@ -103,9 +104,9 @@
<string name="app_profile_template_import_empty">Le presse-papiers est vide !</string>
<string name="app_profile_template_view">Voir le modèle</string>
<string name="settings_check_update_summary">Vérifier automatiquement les mises à jour à l\'ouverture de l\'application</string>
<string name="settings_check_update">Rechercher des mises à jour</string>
<string name="enable_web_debugging">Activer le débogage WebView</string>
<string name="enable_web_debugging_summary">Peut être utilisé pour déboguer WebUI. Activez uniquement cette option si nécessaire.</string>
<string name="settings_check_update">Vérifier les mises à jour</string>
<string name="enable_web_debugging">Activer le débogage de WebView</string>
<string name="enable_web_debugging_summary">Peut être utilisé pour déboguer WebUI, n\'activez cette option que si nécessaire.</string>
<string name="grant_root_failed">Échec de l\'octroi des privilèges root!</string>
<string name="open">Ouvrir</string>
<string name="direct_install">Installation directe (recommandé)</string>
@@ -118,26 +119,17 @@
<string name="select_file_tip">L\'image de la partition %1$s est recommandée</string>
<string name="select_kmi">Sélectionner une KMI</string>
<string name="shrink_sparse_image">Minimiser la taille de l\'image partiellement allouée</string>
<string name="shrink_sparse_image_message">Redimensionner à sa taille réelle l\'image partiellement allouée où se trouve le module. Notez que cela peut entraîner un dysfonctionnement du module ; utilisez donc cette fonctionnalité uniquement quand c\'est nécessaire (par exemple pour sauvegarder l\'appareil).</string>
<string name="shrink_sparse_image_message">Redimensionner à sa taille réelle l\'image partiellement allouée où se trouve le module. Notez que cela peut entraîner un dysfonctionnement du module, utilisez donc cette fonctionnalité uniquement lorsque c\'est nécessaire (par exemple pour la sauvegarde de l\'appareil).</string>
<string name="settings_uninstall">Désinstaller</string>
<string name="settings_uninstall_temporary">Désinstaller temporairement</string>
<string name="settings_uninstall_permanent">Désinstaller définitivement</string>
<string name="settings_restore_stock_image">Restaurer l\'image d\'origine</string>
<string name="settings_restore_stock_image_message">Restaurer l\'image d\'origine d\'usine (s\'il en existe une sauvegarde). Utilisé généralement avant une mise à jour OTA ; si vous devez désinstaller KernelSU, utilisez plutôt l\'option \"Désinstaller définitivement\".</string>
<string name="settings_restore_stock_image">Restaurer l\'image stock</string>
<string name="settings_restore_stock_image_message">Restaurer l\'image stock d\'usine (s\'il en existe une sauvegarde), option généralement utilisée avant une mise à jour OTA; si vous avez besoin de désinstaller KernelSU, utilisez plutôt l\'option « Désinstaller définitivement ».</string>
<string name="flashing">Flash en cours</string>
<string name="flash_success">Flash réussi</string>
<string name="flash_failed">Échec du flash</string>
<string name="selected_lkm">LKM sélectionné: %s</string>
<string name="selected_lkm">lkm sélectionné: %s</string>
<string name="settings_uninstall_permanent_message">Désinstallation complète et permanente de KernelSU (root et tous les modules).</string>
<string name="settings_uninstall_temporary_message">Désinstaller KernelSU temporairement et rétablir l\'état original au redémarrage suivant.</string>
<string name="save_log">Enregistrer les journaux</string>
<string name="module_sort_action_first">Trier par action</string>
<string name="module_sort_enabled_first">Trier par activé</string>
<string name="action">Action</string>
<string name="log_saved">Journaux enregistrés</string>
<string name="settings_disable_su">Désactiver la compatibilité avec su</string>
<string name="settings_disable_su_summary">Désactivez temporairement la possibilité de toute application d\'obtenir les privilèges root via la commande su (les processus root existants ne seront pas affectés).</string>
<string name="module_install_prompt_with_name">Les modules suivants vont être installés : %1$s</string>
<string name="su_not_allowed">Impossible d\'octroyer les autorisations superutilisateur à %s</string>
<string name="confirm">Confirmer</string>
</resources>
<string name="save_log">Enregistrer les Journaux</string>
</resources>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home">Inicio</string>
</resources>

View File

@@ -77,8 +77,8 @@
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="failed_to_update_sepolicy">%s के लिए SELinux नियमों को अपटेड करने में विफल</string>
<string name="reboot_bootloader">बुटलोडर में रिबूट करें</string>
<string name="about_source_code">%1$s पर स्रोत कोड देखें<br></br>हमारे %2$s चैनल से जुड़ें</string>
<string name="about_source_code">%1$s पर स्रोत कोड देखें<br/>हमारे %2$s चैनल से जुड़ें</string>
<string name="home_manager_version">मैनेजर वर्जन</string>
<string name="new_version_available">नया वर्जन: %s उपलब्ध है,अपग्रेड के लिए क्लिक करें</string>
<string name="save_log">लॉग सहेजें</string>
</resources>
</resources>

View File

@@ -52,7 +52,7 @@
<string name="home_click_to_learn_kernelsu">Naučite kako da instalirate KernelSU i da koristite module</string>
<string name="home_support_title">Podržite Nas</string>
<string name="home_support_content">KernelSU je, i uvijek če biti, besplatan, i otvorenog izvora. Možete nam međutim pokazati da vas je briga s time da napravite donaciju.</string>
<string name="about_source_code">Pogledajte izvornu kodu na %1$s<br></br>Pridružite nam se na %2$s kanalu</string>
<string name="about_source_code">Pogledajte izvornu kodu na %1$s<br/>Pridružite nam se na %2$s kanalu</string>
<string name="profile_default">Zadano</string>
<string name="profile_template">Šablon</string>
<string name="profile_custom">Prilagođeno</string>
@@ -80,4 +80,4 @@
<string name="force_stop_app">Prisilno Zaustavite</string>
<string name="restart_app">Resetujte</string>
<string name="save_log">Spremi Zapise</string>
</resources>
</resources>

View File

@@ -3,132 +3,104 @@
<string name="home_working">Működik</string>
<string name="home_working_version">Verzió: %d</string>
<string name="home_module_count">Modulok: %d</string>
<string name="home_unsupported_reason">A KernelSU jelenleg csak GKI kerneleket támogat</string>
<string name="home_unsupported_reason">KernelSU csak GKI kerneleket támogat jelenleg</string>
<string name="home_kernel">Kernel</string>
<string name="home_manager_version">Alkalmazás verziója</string>
<string name="home_fingerprint">Ujjlenyomat</string>
<string name="selinux_status_disabled">Letiltva</string>
<string name="home_manager_version">App verziója</string>
<string name="home_fingerprint">Build Fingerprint</string>
<string name="selinux_status_disabled">Kikapcsolt</string>
<string name="reboot_download">Újraindítás letöltő módba</string>
<string name="reboot_edl">Újraindítás EDL-be</string>
<string name="about">Névjegy</string>
<string name="module_uninstall_confirm">Biztos benne hogy eltávolítja a következő modult: %s?</string>
<string name="module_uninstall_confirm">Biztos vagy benne hogy eltávolítod a következő modult: %s\?</string>
<string name="module_uninstall_failed">Nem sikerült eltávolítani: %s</string>
<string name="module_author">Készítő</string>
<string name="module_overlay_fs_not_available">A modulok nem érhetők el, mivel az OverlayFS-t a kernel letiltotta.</string>
<string name="refresh">Frissítés</string>
<string name="show_system_apps">Rendszeralkalmazások megjelenítése</string>
<string name="hide_system_apps">Rendszeralkalmazások elrejtése</string>
<string name="module_overlay_fs_not_available">Overlayfs nem elérhető, a modul nem tud enélkül működni!</string>
<string name="refresh">Újratöltés</string>
<string name="show_system_apps">Mutasd a rendszer alkalmazásokat</string>
<string name="hide_system_apps">Rejtsd el a rendszer alkalmazásokat</string>
<string name="safe_mode">Biztonságos mód</string>
<string name="module_magisk_conflict">A modulok nem érhetők el a Magiskkel való ütközés miatt!</string>
<string name="home_learn_kernelsu">Tudjon meg többet a KernelSU-ról</string>
<string name="home_click_to_learn_kernelsu">Ismerje meg a KernelSU telepítését és a modulok használatát</string>
<string name="home_support_title">Támogasson minket</string>
<string name="about_source_code">Tekintse meg a forráskódot a %1$s-on<br></br>Csatlakozzon a %2$s csatornánkhoz</string>
<string name="module_magisk_conflict">A modul letiltva mert ütközik a Magisk verziójával!</string>
<string name="home_learn_kernelsu">Tudj meg többet a KernelSU-ról</string>
<string name="home_click_to_learn_kernelsu">Tudd meg hogyan telepítsd a KernelSU-t és használd moduljait</string>
<string name="home_support_title">Támogass minket</string>
<string name="about_source_code">Tekintsd meg a forráskódot a %1$s-n<br/>Csatlakozz a %2$s csatornánkhoz</string>
<string name="profile_default">Alapértelmezett</string>
<string name="profile_template">Sablon</string>
<string name="profile_custom">Egyedi</string>
<string name="profile_name">Profil neve</string>
<string name="profile_namespace">Névtér csatlakoztatása</string>
<string name="profile_namespace">Mountold a névteret</string>
<string name="profile_namespace_inherited">Örökölt</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="profile_namespace_individual">Különálló</string>
<string name="profile_groups">Csoportok</string>
<string name="profile_capabilities">Jogosultságok</string>
<string name="profile_selinux_context">SELinux kontextus</string>
<string name="settings_umount_modules_default">Modulok leválasztása alapértelmezetten</string>
<string name="profile_umount_modules_summary">Ha engedélyezi ezt az opciót, a KernelSU visszaállíthatja az alkalmazás moduljai által módosított fájlokat.</string>
<string name="profile_selinux_context">SElinux kontextus</string>
<string name="settings_umount_modules_default">Umountold a modulokat alpértelmezés szerint</string>
<string name="profile_umount_modules_summary">Ennek az opciónak az engedélyezése lehetővé teszi, hogy a KernelSU visszaállítsa az alkalmazás moduljai által módosított fájlokat.</string>
<string name="profile_selinux_domain">Tartomány</string>
<string name="profile_selinux_rules">Szabályok</string>
<string name="module_update">Frissítés</string>
<string name="module_downloading">Modul letöltése: %s</string>
<string name="module_start_downloading">Letöltés indítása: %s</string>
<string name="module_downloading">A %s modul letöltése folyamatban</string>
<string name="module_start_downloading">Indítsd el a letöltést: %s</string>
<string name="launch_app">Indítás</string>
<string name="force_stop_app">Kényszerített leállítás</string>
<string name="restart_app">újraindítás</string>
<string name="home">Kezdőlap</string>
<string name="home_not_installed">Nincs telepítve</string>
<string name="home_click_to_install">Kattintson a telepítéshez</string>
<string name="home_click_to_install">Kattints a telepítéshez</string>
<string name="home_superuser_count">Engedélyezett alkalmazások: %d</string>
<string name="home_unsupported">Nem támogatott</string>
<string name="home_selinux_status">SELinux állapot</string>
<string name="selinux_status_enforcing">Kényszerített</string>
<string name="selinux_status_permissive">Engedélyezett</string>
<string name="home_selinux_status">SELinux státusz</string>
<string name="selinux_status_enforcing">Érvényesítés</string>
<string name="selinux_status_permissive">Megengedő</string>
<string name="selinux_status_unknown">Ismeretlen</string>
<string name="superuser">Superuser</string>
<string name="superuser">Super user</string>
<string name="module_failed_to_enable">Nem sikerült engedélyezni a következő modult: %s</string>
<string name="module_failed_to_disable">Nem sikerült letiltani a következő modult: %s</string>
<string name="module_empty">Nincs telepített modul</string>
<string name="module_failed_to_disable">Nem sikerült letiltani a következő modulokat: %s</string>
<string name="module_empty">Nincs modul telepítve</string>
<string name="module">Modulok</string>
<string name="uninstall">Eltávolítás</string>
<string name="module_install">Telepítés</string>
<string name="install">Telepítés</string>
<string name="reboot">Újraindítás</string>
<string name="settings">Beállítások</string>
<string name="reboot_userspace">Rendszerfelület újraindítása</string>
<string name="reboot_userspace">Android felület újraindítása</string>
<string name="reboot_recovery">Újraindítás recovery-módba</string>
<string name="reboot_bootloader">Újraindítás bootloader-módba</string>
<string name="module_uninstall_success">%s eltávolítva</string>
<string name="module_uninstall_success">%s törölve</string>
<string name="module_version">Verzió</string>
<string name="send_log">Naplók küldése</string>
<string name="reboot_to_apply">Indítsa újra a készüléket a változások érvényesítéséhez</string>
<string name="home_support_content">A KernelSU ingyenes, nyílt forráskódú és mindig is az lesz. Ön azonban adományozással megmutathatja, hogy törődik a projekttel.</string>
<string name="send_log">Napló küldése</string>
<string name="reboot_to_apply">Indítsd újra a készüléket hogy érvényesítsd a változást</string>
<string name="home_support_content">A KernelSU ingyenes és nyílt forráskódú és mindig is az lesz. Te viszont meg tudod mutatni azt, hogy törődsz ennek a projektnek a sorsával egy adomány formájában.</string>
<string name="profile_namespace_global">Globális</string>
<string name="profile_umount_modules">Modulok leválasztása</string>
<string name="failed_to_update_app_profile">Nem sikerült frissíteni az App Profilt ehhez: %s</string>
<string name="settings_umount_modules_default_summary">A \"Modulok leválasztása\" globális alapértelmezett értéke az App Profile-ban. Ha engedélyezve van, eltávolít minden modulmódosítást a rendszerből azon alkalmazások esetében, amelyeknek nincs profilja beállítva.</string>
<string name="new_version_available">Elérhető az új, %s verzió, kattintson a frissítéshez.</string>
<string name="failed_to_update_sepolicy">Nem sikerült frissíteni az SELinux szabályokat a következőhöz: %s</string>
<string name="require_kernel_version">A jelenlegi KernelSU verzió %d túlságosan elavult a megfelelő működéshez. Kérk frissítsen a %d verzióra vagy újabbra!</string>
<string name="profile_umount_modules">Unmountold a modulokat</string>
<string name="failed_to_update_app_profile">Nem sikerült frissíteni az App Profilt ehhez %s</string>
<string name="settings_umount_modules_default_summary">A Modulok csatlakoztatása globális alapértelmezett értéke az alkalmazásprofilokban. Ha engedélyezve van, eltávolítja a rendszer összes modul-módosítását azoknál az alkalmazásoknál, amelyeknek nincs beállított profilja.</string>
<string name="new_version_available">Új verzió: %s elérhető, kattints a frissítéshez</string>
<string name="failed_to_update_sepolicy">Nem sikerült frissíteni a SELinux szabályait a következőhöz: %s</string>
<string name="require_kernel_version">A jelenlegi KernelSU verzió %d túlságosan elavult. Kérlek frissíts a %d verzióra vagy újabbra!</string>
<string name="app_profile_template_import_success">Sikeresen importálva</string>
<string name="app_profile_export_to_clipboard">Exportálás a vágólapról</string>
<string name="app_profile_template_export_empty">Nem található helyi sablon az exportáláshoz!</string>
<string name="app_profile_export_to_clipboard">Exportálás a vágólapból</string>
<string name="app_profile_template_export_empty">A helyi sablon nem található az exportáláshoz!</string>
<string name="app_profile_template_id_exist">A sablon ID már létezik!</string>
<string name="module_changelog">Változások</string>
<string name="app_profile_import_from_clipboard">Importálás a vágólapról</string>
<string name="app_profile_import_from_clipboard">Importálás a vágólapból</string>
<string name="module_changelog_failed">A változásnapló lekérése nem sikerült: %s</string>
<string name="app_profile_template_name">Név</string>
<string name="app_profile_template_id_invalid">Hibás sablon ID</string>
<string name="app_profile_template_sync">Online sablonok szinkronizálása</string>
<string name="app_profile_template_create">Sablon készítése</string>
<string name="app_profile_template_readonly">Csak olvasható</string>
<string name="app_profile_template_readonly">csak olvasható</string>
<string name="app_profile_import_export">Import/Export</string>
<string name="app_profile_template_save_failed">A sablon mentése sikertelen</string>
<string name="app_profile_template_edit">Sablon szerkesztése</string>
<string name="app_profile_template_id">ID</string>
<string name="settings_profile_template">App Profile sablon</string>
<string name="app_profile_template_id">id</string>
<string name="settings_profile_template">Alkalmazásprofil sablon</string>
<string name="app_profile_template_description">Leírás</string>
<string name="app_profile_template_save">Mentés</string>
<string name="settings_profile_template_summary">Az App Profile helyi és online sablonjának kezelése</string>
<string name="settings_profile_template_summary">Az alkalmazásprofil helyi és online sablon kezelése</string>
<string name="app_profile_template_delete">Törlés</string>
<string name="app_profile_template_import_empty">A vágólap üres!</string>
<string name="app_profile_template_view">Sablon megtekintése</string>
<string name="save_log">Naplók mentése</string>
<string name="enable_web_debugging_summary">A WebUI hibakeresésére használható, csak szükség esetén engedélyezze.</string>
<string name="enable_web_debugging">WebView hibakeresés engedélyezése</string>
<string name="open">Megnyitás</string>
<string name="settings_uninstall_permanent">Végleges eltávolítás</string>
<string name="select_file_tip">%1$s partíció képfájl ajánlott</string>
<string name="select_kmi">KMI kiválasztása</string>
<string name="install_next">Következő</string>
<string name="settings_uninstall_temporary">Ideiglenes eltávolítás</string>
<string name="settings_uninstall_temporary_message">A KernelSU ideiglenes eltávolítása, az eredeti állapot visszaállítása a következő újraindítás után.</string>
<string name="settings_uninstall">Eltávolítás</string>
<string name="flashing">Telepítés</string>
<string name="flash_success">Sikeres telepítés</string>
<string name="selected_lkm">Kiválasztott LKM: %s</string>
<string name="flash_failed">Sikertelen telepítés</string>
<string name="grant_root_failed">A root jog megadása sikertelen!</string>
<string name="install_inactive_slot">Telepítés inaktív helyre (OTA után)</string>
<string name="select_file">Fájl kiválasztása</string>
<string name="settings_uninstall_permanent_message">A KernelSU eltávolítása (root és az összes modul) teljesen és véglegesen.</string>
<string name="settings_restore_stock_image">Eredeti képfájl visszaállítása</string>
<string name="action">Művelet</string>
<string name="direct_install">Közvetlen telepítés (Ajánlott)</string>
<string name="install_inactive_slot_warning">Az eszköze **KÉNYSZERÍTETTEN** a jelenleg inaktív helyről fog indulni újraindítás után!\nCsak az OTA befejezése után használja.\nFolytatja?</string>
<string name="shrink_sparse_image_message">Átméretezi a sparse képfájlt, ahol a modul található, a tényleges méretére. Vegye figyelembe, hogy ez a modul rendellenes működését okozhatja, ezért kérjük, hogy csak akkor használja, ha szükséges (például biztonsági mentéshez).</string>
<string name="settings_restore_stock_image_message">Állítsa vissza a gyári képfájlt (ha létezik biztonsági mentés). Általában OTA előtt használják. Ha a KernelSU-t szeretné eltávolítani, használja a végleges eltávolítás opciót.</string>
<string name="settings_check_update">Frissítés ellenőrzése</string>
<string name="settings_check_update_summary">Automatikusan keressen frissítéseket az alkalmazás megnyitásakor</string>
<string name="log_saved">Mentett naplók</string>
<string name="shrink_sparse_image">Sparse képfájl minimalizálása</string>
</resources>
<string name="app_profile_template_view">Sablon megnézése</string>
<string name="save_log">Naplók Mentése</string>
</resources>

View File

@@ -10,39 +10,39 @@
<string name="home_unsupported">Tidak didukung</string>
<string name="home_unsupported_reason">KernelSU saat ini hanya mendukung kernel GKI</string>
<string name="home_kernel">Kernel</string>
<string name="home_manager_version">Versi manajer</string>
<string name="home_manager_version">Versi Manager</string>
<string name="home_fingerprint">Identitas</string>
<string name="home_selinux_status">Status SELinux</string>
<string name="selinux_status_disabled">Dinonaktifkan</string>
<string name="selinux_status_disabled">Nonaktif</string>
<string name="selinux_status_enforcing">Enforcing</string>
<string name="selinux_status_permissive">Permisif</string>
<string name="selinux_status_unknown">Tidak diketahui</string>
<string name="selinux_status_permissive">Permissive</string>
<string name="selinux_status_unknown">Unknown</string>
<string name="superuser">SuperUser</string>
<string name="module_failed_to_enable">Gagal mengaktifkan modul: %s</string>
<string name="module_failed_to_disable">Gagal menonaktifkan modul: %s</string>
<string name="module_empty">Tidak ada modul yang terpasang</string>
<string name="module_empty">Tidak ada modul</string>
<string name="module">Modul</string>
<string name="uninstall">Hapus</string>
<string name="module_install">Instal</string>
<string name="install">Instal</string>
<string name="reboot">Reboot</string>
<string name="settings">Setelan</string>
<string name="reboot_userspace">Soft Reboot</string>
<string name="reboot_recovery">Reboot ke Recovery</string>
<string name="reboot_bootloader">Reboot ke Bootloader</string>
<string name="reboot_download">Reboot ke Download</string>
<string name="reboot_edl">Reboot ke EDL</string>
<string name="settings">Pengaturan</string>
<string name="reboot_userspace">SoftReboot</string>
<string name="reboot_recovery">But ke Recovery</string>
<string name="reboot_bootloader">But ke Bootloader</string>
<string name="reboot_download">But ke Download</string>
<string name="reboot_edl">But ke EDL</string>
<string name="about">Tentang</string>
<string name="module_uninstall_confirm">Yakin menghapus modul %s?</string>
<string name="module_uninstall_success">%s berhasil dihapus</string>
<string name="module_uninstall_failed">Gagal menghapus: %s</string>
<string name="module_version">Versi</string>
<string name="module_author">Oleh</string>
<string name="module_overlay_fs_not_available">Modul tidak tersedia karena kernel tidak mendukung OverlayFS!</string>
<string name="module_overlay_fs_not_available">OverlayFS tidak tersedia, modul tidak berfungsi!</string>
<string name="refresh">Muat ulang</string>
<string name="show_system_apps">Tampilkan aplikasi sistem</string>
<string name="hide_system_apps">Sembunyikan aplikasi sistem</string>
<string name="send_log">Kirim Log</string>
<string name="send_log">Laporkan Log</string>
<string name="safe_mode">Mode aman</string>
<string name="reboot_to_apply">Reboot agar berfungsi</string>
<string name="module_magisk_conflict">Konflik dengan Magisk, fungsi modul ditiadakan!</string>
@@ -51,13 +51,13 @@
<string name="home_click_to_learn_kernelsu">Pelajari cara instal KernelSU dan menggunakan modul</string>
<string name="home_support_title">Dukung Kami</string>
<string name="home_support_content">KernelSU akan selalu menjadi aplikasi gratis dan terbuka. Anda dapat memberikan donasi sebagai bentuk dukungan.</string>
<string name="about_source_code"><![CDATA[Lihat kode sumber di %1$s<br/>Gabung kanal %2$s kami]]></string>
<string name="about_source_code">Lihat kode sumber di %1$s<br/>Gabung kanal %2$s kami</string>
<string name="profile">Profil Apl</string>
<string name="profile_default">Bawaan</string>
<string name="profile_template">Templat</string>
<string name="profile_custom">Khusus</string>
<string name="profile_name">Nama profil</string>
<string name="profile_namespace">Gunakan Namespace</string>
<string name="profile_namespace">Mount Namespace</string>
<string name="profile_namespace_inherited">Diwariskan</string>
<string name="profile_namespace_global">Universal</string>
<string name="profile_namespace_individual">Individual</string>
@@ -67,16 +67,16 @@
<string name="profile_umount_modules">Umount Modul</string>
<string name="failed_to_update_app_profile">Gagal membarui Profil pada %s</string>
<string name="settings_umount_modules_default">Melepas Modul secara bawaan</string>
<string name="settings_umount_modules_default_summary">Menggunakan \"Umount Modul\" secara universal pada Profil Aplikasi. Jika diaktifkan, akan menghapus semua modifikasi sistem untuk aplikasi yang tidak memiliki set profil.</string>
<string name="settings_umount_modules_default_summary">Menggunakan \"Umount Modul\" secara universal pada Profil aplikasi. Jika diaktifkan, akan menghapus semua modifikasi sistem untuk aplikasi yang tidak memiliki set Profil.</string>
<string name="profile_umount_modules_summary">Aktifkan opsi ini agar KernelSU dapat memulihkan kembali berkas termodifikasi oleh modul pada aplikasi ini.</string>
<string name="profile_selinux_domain">Domain</string>
<string name="profile_selinux_rules">Aturan</string>
<string name="module_update">Membarui</string>
<string name="module_downloading">Mengunduh modul: %s</string>
<string name="module_start_downloading">Mulai mengunduh: %s</string>
<string name="new_version_available">Tersedia versi terbaru %s, Klik untuk membarui.</string>
<string name="new_version_available">Tersedia versi terbaru: %s, Klik untuk membarui</string>
<string name="launch_app">Jalankan</string>
<string name="force_stop_app">Paksa berhenti</string>
<string name="force_stop_app">Paksa Berhenti</string>
<string name="restart_app">Mulai ulang</string>
<string name="failed_to_update_sepolicy">Gagal membarui aturan SELinux pada: %s</string>
<string name="require_kernel_version">Versi KernelSU %d terlalu rendah agar manajer berfungsi normal. Harap membarui ke versi %d atau di atasnya!</string>
@@ -84,25 +84,25 @@
<string name="app_profile_template_import_success">Berhasil diimpor</string>
<string name="app_profile_export_to_clipboard">Ekspor ke papan klip</string>
<string name="app_profile_template_export_empty">Tidak ditemukan templat lokal untuk diekspor!</string>
<string name="app_profile_template_id_exist">ID templat sudah ada!</string>
<string name="app_profile_template_id_exist">Id templat sudah ada!</string>
<string name="app_profile_import_from_clipboard">Impor dari papan klip</string>
<string name="module_changelog_failed">Gagal mengambil Changelog: %s</string>
<string name="app_profile_template_name">Nama</string>
<string name="app_profile_template_id_invalid">ID templat tidak valid</string>
<string name="app_profile_template_id_invalid">Id templat tidak valid</string>
<string name="app_profile_template_sync">Sinkronkan templat daring</string>
<string name="app_profile_template_create">Buat templat</string>
<string name="app_profile_template_create">Buat Templat</string>
<string name="app_profile_import_export">Impor/Ekspor</string>
<string name="app_profile_template_save_failed">Gagal menyimpan templat</string>
<string name="app_profile_template_edit">Edit templat</string>
<string name="app_profile_template_id">ID</string>
<string name="app_profile_template_edit">Edit Templat</string>
<string name="app_profile_template_id">id</string>
<string name="settings_profile_template">Templat Profil Aplikasi</string>
<string name="app_profile_template_description">Deskripsi</string>
<string name="app_profile_template_save">Simpan</string>
<string name="settings_profile_template_summary">Atur templat Profil yang lokal dan daring</string>
<string name="app_profile_template_delete">Hapus</string>
<string name="app_profile_template_import_empty">Papan klip kosong!</string>
<string name="app_profile_template_view">Lihat templat</string>
<string name="app_profile_template_readonly">readonly</string>
<string name="app_profile_template_view">Lihat Templat</string>
<string name="app_profile_template_readonly">ReadOnly</string>
<string name="enable_web_debugging">Pengawakutuan WebView</string>
<string name="enable_web_debugging_summary">Dapat mengawakutu WebView, hanya aktifkan jika butuh.</string>
<string name="select_file_tip">%1$s image partisi terekomendasi</string>
@@ -111,34 +111,25 @@
<string name="install_inactive_slot_warning">Gawai akan **DIPAKSA** untuk but ke slot nonaktif!
\nHANYA gunakan setelah proses OTA selesai.
\nLanjutkan?</string>
<string name="direct_install">Instal langsung (rekomendasi)</string>
<string name="direct_install">Instal Langsung (rekomendasi)</string>
<string name="select_file">Pilih berkas</string>
<string name="install_inactive_slot">Instal ke slot nonaktif (setelah OTA)</string>
<string name="grant_root_failed">Gagal memberikan akses root!</string>
<string name="open">Buka</string>
<string name="settings_check_update">Cek terbaru</string>
<string name="settings_check_update_summary">Cek terbaru setiap membuka aplikasi</string>
<string name="shrink_sparse_image">Minimalkan ukuran sparse image</string>
<string name="shrink_sparse_image_message">Mengembalikan ukuran sparse image, lokasi modul disimpan, ke ukuran sebenarnya. Dapat menyebabkan modul bekerja abnormal, gunakan saat dibutuhkan saja (mis. untuk pencadangan).</string>
<string name="shrink_sparse_image">Meminimalkan sparse image</string>
<string name="shrink_sparse_image_message">Mengembalikan sparse image, lokasi modul disimpan, ke ukuran sebenarnya. Dapat menyebabkan modul bekerja abnormal, maka gunakan saat dibutuhkan saja (mis. untuk pencadangan)</string>
<string name="settings_uninstall_permanent_message">Hapus permanen KernelSU (root dan modul).</string>
<string name="settings_uninstall_temporary">Hapus sementara</string>
<string name="settings_restore_stock_image">Pulihkan image bawaan</string>
<string name="settings_uninstall_temporary">Hapus Temporer</string>
<string name="settings_restore_stock_image">Pulihkan Image Asal</string>
<string name="settings_uninstall">Hapus</string>
<string name="settings_uninstall_temporary_message">Sementara menghapus KernelSU, memulihkan ke kondisi asal setelah reboot berikutnya.</string>
<string name="settings_uninstall_permanent">Hapus permanen</string>
<string name="settings_restore_stock_image_message">Pulihkan image bawaan ROM (jika cadangan tersedia), umumnya dilakukan sebelum OTA; jika ingin menghapus KernelSU, gunakan fungsi \"Hapus permanen\".</string>
<string name="settings_uninstall_temporary_message">Hapus Temporer KernelSU, pulihkan ke kondisi asali setelah but berikutnya.</string>
<string name="settings_uninstall_permanent">Hapus Permanen</string>
<string name="settings_restore_stock_image_message">Pulihkan image bawaan ROM (jika cadangan tersedia), umumnya dilakukan sebelum OTA; jika ingin menghapus KernelSU, gunakan fungsi \"Hapus Permanen\".</string>
<string name="flash_success">Pemasangan Berhasil</string>
<string name="selected_lkm">LKM dipilih: %s</string>
<string name="flashing">Pasang</string>
<string name="flash_failed">Pemasangan Gagal</string>
<string name="save_log">Simpan Log</string>
<string name="action">Aksi</string>
<string name="log_saved">Log disimpan</string>
<string name="module_sort_enabled_first">Urut (Aktif pertama)</string>
<string name="module_sort_action_first">Urut (Tindakan pertama)</string>
<string name="module_install_prompt_with_name">Modul yg akan diinstal: %1$s</string>
<string name="confirm">Oke</string>
<string name="su_not_allowed">Akses SU tidak dapat diberikan ke %s</string>
<string name="settings_disable_su">Nonaktifkan kompatibilats SU</string>
<string name="settings_disable_su_summary">Nonaktifkan sementara kemampuan aplikasi memperoleh hak akses root via perintah SU (tidak mempengaruhi proses root yg sudah ada).</string>
</resources>
</resources>

View File

@@ -45,7 +45,7 @@
<string name="send_log">Invia log</string>
<string name="safe_mode">Modalità provvisoria</string>
<string name="reboot_to_apply">Riavvia per applicare la modifica</string>
<string name="module_magisk_conflict">I moduli sono disabilitati perché in conflitto con Magisk!</string>
<string name="module_magisk_conflict">I moduli sono disabilitati perché in conflitto con quelli di Magisk!</string>
<string name="home_learn_kernelsu">Scopri KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Scopri come installare KernelSU e utilizzare i moduli</string>
@@ -82,16 +82,16 @@
<string name="module_changelog">Registro aggiornamenti</string>
<string name="app_profile_template_create">Crea modello</string>
<string name="app_profile_template_edit">Modifica modello</string>
<string name="app_profile_template_id">identificatore</string>
<string name="app_profile_template_id">identificativo</string>
<string name="app_profile_template_id_invalid">Identificativo modello non valido</string>
<string name="app_profile_template_name">Nome</string>
<string name="app_profile_template_view">Visualizza modello</string>
<string name="app_profile_template_readonly">Sola lettura</string>
<string name="app_profile_template_id_exist">L\'identificatore del modello è già in uso!</string>
<string name="app_profile_template_id_exist">L\'identificativo del modello esiste già!</string>
<string name="app_profile_import_export">Importa/Esporta</string>
<string name="app_profile_import_from_clipboard">Importa dagli appunti</string>
<string name="app_profile_export_to_clipboard">Esporta negli appunti</string>
<string name="app_profile_template_export_empty">Impossibile trovare un modello locale da esportare!</string>
<string name="app_profile_template_export_empty">Impossibile trovare modello locale da esportare!</string>
<string name="app_profile_template_import_success">Importato con successo</string>
<string name="app_profile_template_sync">Sincronizza i modelli remoti</string>
<string name="app_profile_template_import_empty">Gli appunti sono vuoti!</string>
@@ -106,29 +106,29 @@
<string name="module_changelog_failed">Impossibile reperire il changelog: %s</string>
<string name="settings_check_update">Controlla aggiornamenti</string>
<string name="settings_check_update_summary">Controlla automaticamente la disponibilità di aggiornamenti all\'apertura dell\'applicazione</string>
<string name="enable_web_debugging">Abilita il debug di WebView</string>
<string name="enable_web_debugging">Abilita il Debug di WebView</string>
<string name="enable_web_debugging_summary">Può essere usato per svolgere il debug di WebUI, è consigliato attivarlo solo quando necessario.</string>
<string name="select_file_tip">È consigliato usare immagine della partizione %1$s</string>
<string name="select_kmi">Scegli il KMI</string>
<string name="install_next">Avanti</string>
<string name="direct_install">Installazione diretta (Raccomandata)</string>
<string name="select_file">Scegli un file</string>
<string name="install_inactive_slot">Installa nello slot inattivo (dopo OTA)</string>
<string name="select_file">Scegli un File</string>
<string name="install_inactive_slot">Installa nello Slot Inattivo (Dopo OTA)</string>
<string name="install_inactive_slot_warning">Il tuo dispositivo sarà **FORZATO** ad avviarsi nello slot inattivo dopo il riavvio!
\nUsa questa opzione solo quando l\'applicazione dell\'aggiornamento OTA è terminata.
\nProcedere?</string>
<string name="shrink_sparse_image">Riduci la dimensione dell\'immagine moduli sparse al minimo</string>
<string name="shrink_sparse_image_message">Riduci la dimensione dell\'immagine sparse dei moduli alla sua reale dimensione. Nota che questo potrebbe causare malfunzionamenti dei moduli quindi utilizzala solo quando necessario (ad esempio in caso di backup)</string>
<string name="shrink_sparse_image_message">Riduci la dimensione dell\'immagine sparse dei moduli alla sua reale dimenzione. Nota che questo potrebbe causare malfunzionamenti dei moduli quindi utilizzala solo quando necessario (ad esempio in caso di backup)</string>
<string name="settings_uninstall">Disinstalla</string>
<string name="settings_uninstall_temporary">Disinstalla temporaneamente</string>
<string name="settings_uninstall_permanent">Disinstalla permanentemente</string>
<string name="settings_uninstall_temporary">Disinstalla Temporaneamente</string>
<string name="settings_uninstall_permanent">Disinstalla Permanentemente</string>
<string name="settings_restore_stock_image">Ripristina immagine originale del produttore</string>
<string name="settings_uninstall_temporary_message">Disinstalla temporaneamente KernelSU, ripristina lo stato originale dopo il prossimo riavvio.</string>
<string name="settings_uninstall_permanent_message">Disinstalla KernelSU (root e tutti i moduli) completamente e permanentemente.</string>
<string name="settings_uninstall_permanent_message">Disinstalla KernelSU (Root e tutti i moduli) completamente e permanentemente.</string>
<string name="flashing">Installazione</string>
<string name="flash_success">Installazione completata</string>
<string name="flash_failed">Installazione fallita</string>
<string name="selected_lkm">LKM selezionato: %s</string>
<string name="settings_restore_stock_image_message">Ripristina l\'immagine di fabbrica del produttore (se il backup è presente), solitamente usato prima di applicare l\'OTA; se devi disinstallare KernelSU, utilizza invece \"Disinstalla permanentemente\".</string>
<string name="settings_restore_stock_image_message">Ripristina l\'immagine di fabbrica del produttore (se il backup è presente), solitamente usato prima di applicare l\'OTA; se devi disinstallare KernelSU, utilizza invece \"Disinstalla Permanentemente\".</string>
<string name="save_log">Salva Registri</string>
</resources>
</resources>

View File

@@ -77,8 +77,8 @@
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="failed_to_update_sepolicy">נכשל עדכון כללי SELinux עבור: %s</string>
<string name="reboot_bootloader">הפעלה מחדש לבוטלאודר</string>
<string name="about_source_code">ראה את קוד המקור ב%1$s<br></br>הצטרף אלינו %2$s בערוץ</string>
<string name="about_source_code">ראה את קוד המקור ב%1$s<br/>הצטרף אלינו %2$s בערוץ</string>
<string name="home_manager_version">גרסת מנהל</string>
<string name="new_version_available">גרסה חדשה עבור: %s זמינה, לחץ כדי לשדרג</string>
<string name="save_log">שמור יומנים</string>
</resources>
</resources>

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