From dd41e36a30ef5880d3fe242f16dc14f5f7f8f4fd Mon Sep 17 00:00:00 2001
From: Rudxain <76864299+Rudxain@users.noreply.github.com>
Date: Thu, 22 May 2025 21:15:43 -0400
Subject: [PATCH 001/111] tmp
---
resources/assets/uad_lists.json | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 7976a0b..5035c28 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -37245,7 +37245,7 @@
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.kmsjp": {
"list": "Carrier",
@@ -37649,11 +37649,11 @@
},
"com.iflytek.inputmethod.miui": {
"list": "Oem",
- "description": "Chinese Keyboard to Miui China, replace Keyboard before remove.",
+ "description": "Chinese Keyboard to Miui China",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.xiaomi.ugd": {
"list": "Oem",
@@ -39209,11 +39209,11 @@
},
"com.onyx.latinime": {
"list": "Oem",
- "description": "The Onyx Keyboard. Removing it will leave withe google STT keyboard.",
+ "description": "The Onyx Keyboard. The Google STT keyboard might be available to replace it.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.onyx.mail": {
"list": "Oem",
@@ -39241,7 +39241,7 @@
},
"com.preff.kb.xm": {
"list": "Oem",
- "description": "'Emoji & Font Keyboard' on Xiaomi.\nXiaomi won't let me uninstall it. If it's same for you, consider disabling it instead.\nMake sure to install an alternate keyboard app before doing so.",
+ "description": "'Emoji & Font Keyboard' on Xiaomi",
"dependencies": [],
"neededBy": [],
"labels": [],
From dfe9921aa0d77da4162835f5f3b5446d6fcd22b0 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Sat, 24 Jan 2026 13:20:49 +0100
Subject: [PATCH 002/111] pkg(oneplus/oppo/realme): add new AI-related packages
fixes #1146
---
resources/assets/uad_lists.json | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 7976a0b..4a34ee1 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -35762,6 +35762,30 @@
"neededBy": [],
"labels": [],
"removal": "Advanced"
+ },
+ "com.oplus.aicall": {
+ "list": "Oem",
+ "description": "Provides AI summaries in the ODialer app",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.oplus.aimemory": {
+ "list": "Oem",
+ "description": "Saves and summarizes content using AI",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.oplus.aiwriter": {
+ "list": "Oem",
+ "description": "Pop-up for AI text generation, often appears in places that are not text input fields",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
},
"com.oplus.apprecover": {
"list": "Oem",
From 540a123e77497969af88514f91437ae8be77a9f1 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Sat, 24 Jan 2026 13:26:25 +0100
Subject: [PATCH 003/111] pkg(com.oplus.cosa): change description and removal
Expanded the description for com.oplus.cosa to clarify its role in managing refresh rates for gaming and streaming apps, and changed its removal recommendation from 'Recommended' to 'Advanced'.
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 4a34ee1..ea7de6f 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -31503,13 +31503,13 @@
},
"com.oplus.cosa": {
"list": "Oem",
- "description": "APP Enhancement Services\nIf enabled, connects to OPPO servers (icosa-service-eu.allawnos.com) every time a new app is installed. Seems to be mostly focused on gaming performance optimisation according to the settings description:\n'[...] a service that optimises phone performance for specific apps and game scenarios. [...] frame rates, battery usage, touch sensitivity, network connection, vibration and gameplay assistance features.'\n\nCan be disabled via hidden setting (Settings -> Search 'App Enhancement Services' -> App Enhancement Services).\nNote: removing this package prevents the OnePlus Game Center to detect games.\nCannot be uninstalled but it can be disabled. Note: removing this package prevents the OnePlus Game Center to detect games.\nPithus analysis: https://beta.pithus.org/report/f55e935357865f4647e59c98afb5a3a46aba22a48844d80d2819d122781e3fde.",
+ "description": "APP Enhancement Services\nIf enabled, connects to OPPO servers (icosa-service-eu.allawnos.com) every time a new app is installed. Seems to be mostly focused on gaming performance optimisation according to the settings description:\n'[...] a service that optimises phone performance for specific apps and game scenarios. [...] frame rates, battery usage, touch sensitivity, network connection, vibration and gameplay assistance features.'\nCan be disabled via hidden setting (Settings -> Search 'App Enhancement Services' -> App Enhancement Services).\nNote: removing this package prevents the OnePlus Game Center to detect games.\nCannot be uninstalled but it can be disabled. Note: removing this package prevents the OnePlus Game Center to detect games.\nPithus analysis: https://beta.pithus.org/report/f55e935357865f4647e59c98afb5a3a46aba22a48844d80d2819d122781e3fde.\nAnother note: the process is necessary for the GameEventServiceService which ensures that apps recognized as games have a fixed refresh rate, not an adaptive refresh rate; without it, refresh rates may be reduced from 120hz to 60hz. When there is not much going on on screen, there can even be drops in the refresh rate to 30hz and 1hz. There is no option to turn off adaptive refresh rate, so one is reliant on this OS service to undo its own damage. Without this, there also seems to be no way to display 120fps cloud gaming at 120hz (tested with Moonlight/Artemsi), as the OS does not exempt the streaming app from the adaptive refresh rate rule.",
"dependencies": [],
"neededBy": [
"com.oneplus.gamespace"
],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.oplus.blur": {
"list": "Oem",
From a0813db1657b1f2c9689992085e030e83dffa1e7 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Sat, 24 Jan 2026 13:28:19 +0100
Subject: [PATCH 004/111] pkg(com.oppo.usercenter): add package
fixes #1071
---
resources/assets/uad_lists.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index ea7de6f..d69c1eb 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -27907,6 +27907,14 @@
"neededBy": [],
"labels": []
},
+ "com.oppo.usercenter": {
+ "description": "Just bloatware for account details and marketing of OPPO. Cannot log into OPPO/HeyTap account after disabling. Safe to disable if OPPO account is not used.",
+ "removal": "Advanced",
+ "list": "Oem",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": []
+ },
"com.coloros.findmyphone": {
"description": "Find phone\nFind phone, logout from oppo account before",
"removal": "Recommended",
From 2f105307014c8297e46a6ec518122cf77affd7a9 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Sat, 24 Jan 2026 13:36:22 +0100
Subject: [PATCH 005/111] pkg(com.oplus.audio.effectcenter): change description
and removal
I don't really see why "it's so bloated" if it's just an equalizer for Dolby.
Fixes #900
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index d69c1eb..9ff58ef 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -23458,8 +23458,8 @@
"labels": []
},
"com.oplus.audio.effectcenter": {
- "description": "AudioEffectCenter\nDolby support for Chinese apps and some Google. It's so bloated.",
- "removal": "Recommended",
+ "description": "Sound effects and EQ settings, Dolby support for Chinese apps and some Google. Remove if you aren't planning to use sound effects or EQ.",
+ "removal": "Advanced",
"list": "Oem",
"dependencies": [],
"neededBy": [],
From ea86289346d98afea38f4a826b347e807c38e920 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Sat, 24 Jan 2026 13:46:33 +0100
Subject: [PATCH 006/111] pkg(oneplus/oppo/realme): change descriptions and
removal
Fixes #839
---
resources/assets/uad_lists.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 9ff58ef..424271d 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -27561,8 +27561,8 @@
"labels": []
},
"com.oplus.linker": {
- "description": "OPSynergy\nUsed for the Synergy app to link your phone to your PC (It doesn't work well beyond controlling your phone from your PC).",
- "removal": "Recommended",
+ "description": "OPSynergy\nUsed for the Synergy app to link your phone to your PC (it doesn't work well beyond controlling your phone from your PC). This app is a dependency of screencast. Disabling will cause the screencast app to break.",
+ "removal": "Advanced",
"list": "Oem",
"dependencies": [],
"neededBy": [],
@@ -28036,7 +28036,7 @@
"labels": []
},
"com.oplus.trafficmonitor": {
- "description": "OnePlus Data usage\nOneplus traffic monitor (monthly data usage, etc). If removed, the 'Data Usage' option under 'Mobile network' will not work. Also App Info screen's 'Data usage' option will disappear",
+ "description": "Oneplus traffic monitor (monthly data usage, etc). Required to restrict an app from accessing the network via settings > app info.",
"removal": "Advanced",
"list": "Oem",
"dependencies": [],
From 7a1ca4f4c26a95f7afd32c25194202a589a6601f Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Sat, 24 Jan 2026 16:11:06 +0100
Subject: [PATCH 007/111] docs(readme): add friends section
---
README.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/README.md b/README.md
index 2b00680..50a0708 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,12 @@ UAD-ng does not collect or transmit any user data. The only external connections
[
](https://matrix.to/#/#uad-ng:matrix.org)
+## Friends
+
+Several projects integrate with or depend on UAD-ng's data and tools:
+
+- **[Canta](https://github.com/samolego/Canta)** — A mobile Android debloater that uses Shizuku for rootless privilege escalation. It integrates with UAD-ng's Universal Debloat List to provide safe package recommendations without requiring a PC.
+
## Special thanks
- [@0x192](https://github.com/0x192) who created the original UAD project.
From 77f5c30410a9b287877cf5bfdca3a2db790a766c Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Sat, 24 Jan 2026 23:29:23 +0100
Subject: [PATCH 008/111] chore(issue-templates): add link to removal
definitions
---
.github/ISSUE_TEMPLATE/3-add-new-packages.yml | 7 +------
.../5-update-apps-description-or-recommendation.yml | 7 +------
2 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/.github/ISSUE_TEMPLATE/3-add-new-packages.yml b/.github/ISSUE_TEMPLATE/3-add-new-packages.yml
index d817be8..f7295b8 100644
--- a/.github/ISSUE_TEMPLATE/3-add-new-packages.yml
+++ b/.github/ISSUE_TEMPLATE/3-add-new-packages.yml
@@ -16,12 +16,7 @@ body:
**List**: `Google`|`Misc`|`OEM` (manufacturer) |`AOSP`|`Pending`|`Carrier` (ISP).
- **Removal**:
-
- - Recommended: Pointless, outright negative, or apps available through Google Play. Packages with the word "overlay" must be Advanced or of higher priority because they're likely dangerous, meanwhile they may seem useless or empty to your device, they could bootloop someone else's.
- - Advanced: Breaks obscure or minor parts of functionality, overlays, or apps that aren't easily enabled/installed through Settings/Google Play. This category is also used for apps that are useful (default keyboard/gallery/launcher/music app.) but that can easily be replaced by a better alternative.
- - Expert: Breaks widespread and/or important functionality, but nothing important to the basic operation of the operating system. Removing an Expert package should not bootloop the device (unless mentioned in the description) but we can't guarantee it 100%.
- - Unsafe: Can break vital parts of the operating system. Removing an Unsafe package have an extremely high risk of bootlooping your device or is illegal in your country (e.g. emergency alerts provider (illegal to remove in some EU countries), or SAR certification law in EU).
+ **Removal**: See the [Removal Definitions](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Debloat-Lists#removal-definitions) on the wiki for details. **Please ensure you follow these definitions when proposing changes.**
- type: textarea
id: package-listing
diff --git a/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml b/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml
index bdc637e..1872202 100644
--- a/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml
+++ b/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml
@@ -16,12 +16,7 @@ body:
**List**: `Google`|`Misc`|`OEM` (manufacturer) |`AOSP`|`Pending`|`Carrier` (ISP).
- **Removal**:
-
- - Recommended: Pointless or outright negative packages, and/or apps available through Google Play.
- - Advanced: Breaks obscure or minor parts of functionality, or apps that aren't easily enabled/installed through Settings/Google Play. This category is also used for apps that are useful (default keyboard/gallery/launcher/music app.) but that can easily be replaced by a better alternative.
- - Expert: Breaks widespread and/or important functionality, but nothing important to the basic operation of the operating system. Removing an Expert package should not bootloop the device (unless mentioned in the description) but we can't guarantee it 100%.
- - Unsafe: Can break vital parts of the operating system. Removing an Unsafe package have an extremely high risk of bootlooping your device.
+ **Removal**: See the [Removal Definitions](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Debloat-Lists#removal-definitions) on the wiki for details. **Please ensure you follow these definitions when proposing changes.**
- type: textarea
id: package-listing
From 7b6182722cb7d24203a78489297e06655448f211 Mon Sep 17 00:00:00 2001
From: Ivy <78825510+Lost-Entrepreneur439@users.noreply.github.com>
Date: Sat, 24 Jan 2026 23:44:29 -0330
Subject: [PATCH 009/111] pkg(rogers): add packages from Samsung Galaxy S5 Neo
---
resources/assets/uad_lists.json | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 7976a0b..058a4d9 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -41340,5 +41340,29 @@
"neededBy": [],
"labels": [],
"removal": "Expert"
+ },
+ "com.fivemobile.myaccount": {
+ "list": "Carrier",
+ "description": "App for managing your Rogers account.\nRogers violates section F.1 of Canada's Wireless Code, they refuse to unlock devices sold before December 1, 2017, even if it doesn't affect you, don't support practices like this! Switch to another carrier (such as Telus) if possible.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nhl.gcl.canada": {
+ "list": "Carrier",
+ "description": "Rogers NHL app. Just opens a 404 page in the web browser. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.rogers.npd.appzone": {
+ "list": "Carrier",
+ "description": "An app store just for Rogers bloat. Why the hell would you want this?",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
}
}
From c6b1f44bc945c3ce3eb1d66bf73cfad072766dec Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Sun, 25 Jan 2026 15:27:32 +0100
Subject: [PATCH 010/111] pkg(oneplus/oppo/realme): change descriptions and
removal
---
resources/assets/uad_lists.json | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 424271d..4bcecac 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -9266,7 +9266,7 @@
},
"com.oneplus.soundrecorder": {
"list": "Oem",
- "description": "Recorder\nOnePlus sound recording app.\nRequires turning on\"Allow modifying system settings\" to use for some reason? Probably tied to recording phone-calls.",
+ "description": "Recorder\nOnePlus sound recording app. Requires turning on\"Allow modifying system settings\" to use for some reason? Probably tied to recording phone-calls.",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -22528,7 +22528,7 @@
"labels": []
},
"com.coloros.assistantscreen": {
- "description": "HeyTap Shelf. ColorOS 'At a Glance'.\nShelf provides a variety of widgets that let you access important information or services from apps with ease. Removing will also be unable to access third-party widgets in ColorOS 16\nSwipe down on the Home screen to enter Shelf.\nhttps://play.google.com/store/apps/details?id=com.coloros.assistantscreen",
+ "description": "Shelf. ColorOS/OnePlus 'At a Glance'.\nShelf provides a variety of widgets that let you access important information or services from apps with ease. Removing will also be unable to access third-party widgets (these are different from the 'normal' widgets in any launcher) in ColorOS 16/OxygenOS 16\nSwipe down on the Home screen to enter Shelf.\nhttps://play.google.com/store/apps/details?id=com.coloros.assistantscreen",
"removal": "Advanced",
"list": "Oem",
"dependencies": [],
@@ -22593,7 +22593,7 @@
"labels": []
},
"com.coloros.accessibilityassistant": {
- "description": "Another thing for smart assistant",
+ "description": "AI VoiceScribe.\nIt's used to convert speech to text in real-time for accessibility purposes. Can be safely deleted if you don't use AI services.",
"removal": "Recommended",
"list": "Oem",
"dependencies": [],
@@ -23018,8 +23018,8 @@
"labels": []
},
"com.coloros.weather.service": {
- "description": "Name indicates it's for the weather, but removing this causes the screen to flash and the phone will eventually become unresponsive.\nhttps://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/issues/585",
- "removal": "Unsafe",
+ "description": "Name indicates it's for the weather, but removing this causes the screen to flash and the phone will eventually become unresponsive.\nhttps://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/issues/585. Disabling instead does not seem to cause this problem, see \nhttps://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/issues/585#issuecomment-3796739025",
+ "removal": "Expert",
"list": "Oem",
"dependencies": [],
"neededBy": [],
@@ -23074,7 +23074,7 @@
"labels": []
},
"com.oplus.postmanservice": {
- "description": "Calibration, scan QR code test",
+ "description": "Diagnostics\nFor calibration of hardware",
"removal": "Recommended",
"list": "Oem",
"dependencies": [],
@@ -31754,7 +31754,7 @@
},
"com.coloros.compass2": {
"list": "Oem",
- "description": "ColorOS default compass app\nKeep in mind that by using this app you give your location to the weather Oppo servers.\nPithus analysis: https://beta.pithus.org/report/9a965f5587fa6ee21c526612f3d72c50ef3cc53679b741260298387c44f5a3dc",
+ "description": "ColorOS and OxygenOS 16's default compass app\nKeep in mind that by using this app you give your location to the weather Oppo/OnePlus servers.\nPithus analysis: https://beta.pithus.org/report/9a965f5587fa6ee21c526612f3d72c50ef3cc53679b741260298387c44f5a3dc",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -31820,7 +31820,7 @@
},
"com.coloros.video": {
"list": "Oem",
- "description": "Video Player\nDefault Oppo video player with too much permissions (21) for a video player!\nNote: using inbuilt screen recorder you won't be able to open the recorded video from the notification view.\n\nPithus analysis: https://beta.pithus.org/report/4ceb96c23ad0e26ee8eceab293d251f8b1bddaf4a901741ee467e0bb867db6e9",
+ "description": "Video Player\nDefault Oppo and OnePlus video player with too much permissions (21) for a video player!\nNote: using inbuilt screen recorder you won't be able to open the recorded video from the notification view.\n\nPithus analysis: https://beta.pithus.org/report/4ceb96c23ad0e26ee8eceab293d251f8b1bddaf4a901741ee467e0bb867db6e9",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -31828,7 +31828,7 @@
},
"com.heytap.browser": {
"list": "Oem",
- "description": "Oppo Browser\nRebranded HeyTap browser for Oppo. Full of ads and spams you in notifications. You should never use this browser\nHeyTap's terrible privacy policy: https://brand.heytap.com/eu/privacy.html",
+ "description": "Oppo Browser\nRebranded HeyTap browser for Oppo and OnePlus devices. Full of ads and spams you in notifications. You should never use this browser\nHeyTap's terrible privacy policy: https://brand.heytap.com/eu/privacy.html",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -35781,7 +35781,7 @@
},
"com.oplus.aimemory": {
"list": "Oem",
- "description": "Saves and summarizes content using AI",
+ "description": "Mind Space (also called 'Breeno Memory')\nSaves and summarizes content using AI. Runs on the background, even though when you're not using it.",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -35789,7 +35789,7 @@
},
"com.oplus.aiwriter": {
"list": "Oem",
- "description": "Pop-up for AI text generation, often appears in places that are not text input fields",
+ "description": "AI Writer\nPop-up for AI text generation, often appears in places that are not text input fields.",
"dependencies": [],
"neededBy": [],
"labels": [],
From b47f81b641636c04a0d5bc3117f8be0f701ef107 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Sun, 25 Jan 2026 15:31:43 +0100
Subject: [PATCH 011/111] pkg(com.oplus.trafficmonitor): revert partially
removed description
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 4bcecac..010a764 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -28036,7 +28036,7 @@
"labels": []
},
"com.oplus.trafficmonitor": {
- "description": "Oneplus traffic monitor (monthly data usage, etc). Required to restrict an app from accessing the network via settings > app info.",
+ "description": "OnePlus Data usage / OnePlus traffic monitor (monthly data usage, etc). If removed, the 'Data Usage' option under 'Mobile network' will not work. Also App Info screen's 'Data usage' option will disappear. Required to restrict an app from accessing the network via settings > app info.",
"removal": "Advanced",
"list": "Oem",
"dependencies": [],
From 8b7fe2b98a515dc73bb195f2930e374742725e5b Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Mon, 26 Jan 2026 17:06:55 +0100
Subject: [PATCH 012/111] pkg(oneplus/oppo/realme): change descriptions for OTA
packages
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 010a764..91ff629 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -27225,7 +27225,7 @@
"labels": []
},
"com.oplus.romupdate": {
- "description": "Update Service\nIf you wanna remove it to keep ram, it's a bad idea. Better remove com.oplus.ota too if you don't plan to update system.",
+ "description": "Update Service\nResponsible for installing updates.",
"removal": "Expert",
"list": "Oem",
"dependencies": [],
@@ -35701,7 +35701,7 @@
},
"com.oplus.cota": {
"list": "Oem",
- "description": "Carrier software updater?\nLooks like software updater for carrier phones.",
+ "description": "Configuration Update Over The Air\nNeeded for OTA updates. Likely needed to download and install system updates, device configuration, and carrier/enterprise customizations on OnePlus devices. It ensures your device stays up-to-date and compliant with carrier or company requirements, and interacts with the user only when necessary (e.g., update dialogs, legal statements).",
"dependencies": [],
"neededBy": [],
"labels": [],
From 3acd2301e7696180aa8b802dde9c172723af034a Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Mon, 26 Jan 2026 17:25:39 +0100
Subject: [PATCH 013/111] docs(readme): add projects of Muntashir Akon to
'Friends' section
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 50a0708..6e0f111 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,10 @@ Several projects integrate with or depend on UAD-ng's data and tools:
- **[Canta](https://github.com/samolego/Canta)** — A mobile Android debloater that uses Shizuku for rootless privilege escalation. It integrates with UAD-ng's Universal Debloat List to provide safe package recommendations without requiring a PC.
+- **Projects by [Muntashir Akon](https://github.com/MuntashirAkon):**
+ - **[AppManager](https://github.com/MuntashirAkon/AppManager)** — An advanced Android app manager with powerful debloating features.
+ - **[android-debloat-list](https://github.com/MuntashirAkon/android-debloat-list)** — A comprehensive, community-driven list of Android packages to debloat, based on UAD-ng's list.
+
## Special thanks
- [@0x192](https://github.com/0x192) who created the original UAD project.
From 93a71719b0f0265059373ae232db7acd1f21370f Mon Sep 17 00:00:00 2001
From: Evelyn Torres
Date: Thu, 29 Jan 2026 00:27:24 -0330
Subject: [PATCH 014/111] pkg(samsung, bell, hp): add packages from Samsung
Galaxy Core LTE
---
resources/assets/uad_lists.json | 496 ++++++++++++++++++++++++++++++++
1 file changed, 496 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 058a4d9..bea3456 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -41364,5 +41364,501 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
+ },
+ "com.communitake.remotecontrolservice": {
+ "list": "Carrier",
+ "description": "Remote management app installed by Bell on some devices. Has access to almost every permission so probably best to remove this.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.epson.mobilephone.samsungprintservice": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.fixmo.isa": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.fmm.dm": {
+ "list": "Oem",
+ "description": "Samsung's Find My Mobile service for tracking your phone if you lost it. Unsure of the difference(s) between this and com.fmm.ds. Can lead to logcat spam in some cases.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.fmm.ds": {
+ "list": "Oem",
+ "description": "Samsung's Find My Mobile service for tracking your phone if you lost it. Unsure of the difference(s) between this and com.fmm.dm, however this one doesn't logcat spam unlike com.fmm.dm.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hp.android.printservice": {
+ "list": "Misc",
+ "description": "Print to your HP printer using your Android phone. Most reviews on Google Play say it doesn't work very well. https://play.google.com/store/apps/details?id=com.hp.android.printservice",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.infraware.polarisviewer5": {
+ "list": "Oem",
+ "description": "A dumbed down version of Polaris Office Editor 5 (which is a Microsoft Office like app).",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.lifevibes.trimapp": {
+ "list": "Oem",
+ "description": "Video trimmer used by the default Samsung Gallery app on some older Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.LocalFota": {
+ "list": "Oem",
+ "description": "Required to install OTA updates on older Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.qualcomm.interfacepermissions": {
+ "list": "Misc",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.app.headlines": {
+ "list": "Oem",
+ "description": "Flipboard app for Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.app.shareaccessibilitysettings": {
+ "list": "Oem",
+ "description": "Seems to be like a package for saving your accessibility settings, likely to transfer them to another phone.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.samsung.android.intelligenceservice": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.scloud.proxy.calendar": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.scloud.proxy.contacts": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.scloud.proxy.memo": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.scloud.proxy.sbrowser": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.scloud.proxy.snote3": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.scloud.quota": {
+ "list": "Oem",
+ "description": "Literally all this app does is tell you when you're out of storage on your Samsung Cloud. Why this isn't part of the main Samsung Cloud app? I have no idea.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.app.video": {
+ "list": "Oem",
+ "description": "Can't figure out what this package does, but no adverse effects to removing it.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.everglades.video": {
+ "list": "Oem",
+ "description": "Part of the TouchWiz video player.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.samsung.pickuptutorial": {
+ "list": "Oem",
+ "description": "A guide to some gestures on Samsung devices, however it doesn't seem to be accessable anywhere. Maybe intended for demo units?",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.allshare.service.controlshare": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.allshare.service.fileshare": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.allshare.service.mediashare": {
+ "list": "Oem",
+ "description": "Share media to your other Samsung devices with Allshare. Allshare is discontinued and no longer present on modern Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.app.FileShareClient": {
+ "list": "Oem",
+ "description": "Receive files from Samsung devices with Allshare. Allshare is discontinued and no longer present on modern Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.app.FileShareServer": {
+ "list": "Oem",
+ "description": "Send files to Samsung devices with Allshare. Allshare is discontinued and no longer present on modern Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.app.filtermanager": {
+ "list": "Oem",
+ "description": "Manage camera filters on your Samsung device.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.sec.android.app.interactivekeyguardtutorial": {
+ "list": "Oem",
+ "description": "A guide on how to unlock your phones screen, however it doesn't seem to be present anywhere on the phone. Maybe intended for demo units?",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.app.mediasync": {
+ "list": "Oem",
+ "description": "Share music for group play.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.app.mobileprint": {
+ "list": "Oem",
+ "description": "Samsung print service for supported printers.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.sec.android.app.mv.player": {
+ "list": "Oem",
+ "description": "Share videos to other devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.app.rakein": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.app.sbrowsertry": {
+ "list": "Oem",
+ "description": "Samsung Internet browser, there are much better browsers available and Samsung Internet has a really sketchy privacy policy.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.app.SmartClipService": {
+ "list": "Oem",
+ "description": "Default image editor on older Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.sec.android.app.videoplayer": {
+ "list": "Oem",
+ "description": "TouchWiz video player.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.sec.android.app.wluc": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.cloudagent": {
+ "list": "Oem",
+ "description": "Part of Dropbox integration on TouchWiz",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.cloudagent.dropboxoobe": {
+ "list": "Oem",
+ "description": "Get a free 50GB Dropbox account with your Samsung device! Would be useful, but Dropbox ended this offer about 10 years ago.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.directshare": {
+ "list": "Oem",
+ "description": "Part of Samsung's SBeam service. SBeam has known security vulnerabilities (https://labs.withsecure.com/advisories/samsung-s5-arbitary-file-retrieval-during-sbeam-transfer), so you should really uninstall this.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.easysettings": {
+ "list": "Oem",
+ "description": "Settings app if you're using the Easy Mode feature on Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.fotaclient": {
+ "list": "Oem",
+ "description": "OTA for legacy Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.sec.android.fwupgrade": {
+ "list": "Oem",
+ "description": "Updates AllShare components. Since Samsung AllShare is discontinued, this is now useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.Kies": {
+ "list": "Oem",
+ "description": "Required for connecting your device to Samsung Kies, Samsung's long discontinued iTunes competitor. Everything that can be done with Kies can be done with ADB or Heimdall, so there isn't really a point to keeping this.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.mmapp": {
+ "list": "Oem",
+ "description": "Required for Samsung's proprietary music app to work.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.nearby.mediaserver": {
+ "list": "Oem",
+ "description": "Samsung nearby share, part of AllShare. Discontinued.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.SamsungDrmProvider": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless. Content with DRM still works without this package.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.service.bezel": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.service.cm": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.voltesettings": {
+ "list": "Oem",
+ "description": "Needed for VoLTE to function properly, which is a feature a lot of carriers now require.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.sec.android.wfds.printplugin": {
+ "list": "Oem",
+ "description": "Needed for Wi-Fi direct printing on Samsung devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.sec.android.widget.samsungapps": {
+ "list": "Oem",
+ "description": "Widget for Galaxy Apps, showing app suggestions on your home screen.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.widgetapp.activeapplicationwidget": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.dsm.phone": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.dsm.system": {
+ "list": "Oem",
+ "description": "Part of Samsung's Find my Mobile service, appears this app is so you can ring your phone if you lost it.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.knox.seandroid": {
+ "list": "Oem",
+ "description": "Samsung Knox security features. Can't be disabled or uninstalled without root.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.sec.pcw.device": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.providers.settingsearch": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.setdefaultlauncher": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless. You can still change launchers without this package.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.siso.app.generic": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.siso.app.genericprintservice": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.telenav.app.android.bell": {
+ "list": "Carrier",
+ "description": "Bell Navigator app. It works, but there are much better Maps apps available. https://play.google.com/store/apps/details?id=com.telenav.app.android.bell",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
}
}
From d8441bda83c9f407323659eec02c41a189771ed0 Mon Sep 17 00:00:00 2001
From: MintJapan <103297262+MintJapan@users.noreply.github.com>
Date: Sun, 1 Feb 2026 16:10:23 +0900
Subject: [PATCH 015/111] pkg(docomo, samsung, felica): add docomo pkg, update
FeliCa pkg
- add lots of docomo package (Only confirmed on SC-53E, more can be found on older devices)
- some fixes to FeliCa pkg
---
resources/assets/uad_lists.json | 291 ++++++++++++++++++++++++++------
1 file changed, 243 insertions(+), 48 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 058a4d9..a5794f1 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -13628,38 +13628,6 @@
"labels": [],
"removal": "Recommended"
},
- "com.nttdocomo.android.applicationmanager": {
- "list": "Carrier",
- "description": "Docomo Application Manager",
- "dependencies": [],
- "neededBy": [],
- "labels": [],
- "removal": "Recommended"
- },
- "com.nttdocomo.android.store": {
- "list": "Carrier",
- "description": "Docomo App Market",
- "dependencies": [],
- "neededBy": [],
- "labels": [],
- "removal": "Recommended"
- },
- "com.nttdocomo.android.dhome": {
- "list": "Carrier",
- "description": "Docomo Launcher",
- "dependencies": [],
- "neededBy": [],
- "labels": [],
- "removal": "Advanced"
- },
- "com.nttdocomo.android.initialization": {
- "list": "Carrier",
- "description": "Docomo Initialization app",
- "dependencies": [],
- "neededBy": [],
- "labels": [],
- "removal": "Recommended"
- },
"com.oppo.fingerprints.fingerprintsensortest": {
"list": "Oem",
"description": "Fingerprint sensort test\n",
@@ -33485,19 +33453,19 @@
},
"com.felicanetworks.mfc": {
"list": "Oem",
- "description": "[Mobile FeliCa Client](https://play.google.com/store/apps/details?id=com.felicanetworks.mfm.main) is an essential app for using FeliCa.\nUninstalling this may occur errors to install this in apps which uses FeliCa. You can uninstall this if you don't use FeliCa-related services. Uninstalling this does not remove the data saved in FeliCa.",
+ "description": "Mobile FeliCa Client (https://play.google.com/store/apps/details?id=com.felicanetworks.mfm.main)\nEssential app for using FeliCa.\nUninstalling this may occur errors to install this in apps which uses FeliCa. You can uninstall this if you don't use FeliCa-related services.\nNOTE: Uninstalling this does not remove the data saved in FeliCa.",
"dependencies": [],
"neededBy": ["com.felicanetworks.mfw.a.boot", "com.felicanetworks.mfm.main"],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.felicanetworks.mfm.main": {
"list": "Oem",
- "description": "[Osaifu-Keitai App](https://play.google.com/store/apps/details?id=com.felicanetworks.mfm.main) is a digital wallet app for Osaifu-Keitai brand.\nIt does not appear to be related to the FeliCa core functionality, but is required for services under the Osaifu-Keitai brand, such as iD and Mobile Suica.\nFor details, please [check the app description](https://play.google.com/store/apps/details?id=com.felicanetworks.mfm.main) on Play Store.",
+ "description": "Osaifu-Keitai App (https://play.google.com/store/apps/details?id=com.felicanetworks.mfm.main)\nA digital wallet app for Osaifu-Keitai brand.\nIt does not appear to be related to the FeliCa core functionality, but is required for services under the Osaifu-Keitai brand, such as iD and Mobile Suica.\nFor details, please check the app description (https://play.google.com/store/apps/details?id=com.felicanetworks.mfm.main) on Play Store.",
"dependencies": ["com.felicanetworks.mfc"],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.felicanetworks.mfs": {
"list": "Oem",
@@ -33509,20 +33477,247 @@
},
"com.felicanetworks.mfw.a.boot": {
"list": "Oem",
- "description": "[Osaifu-Keitai Web Plugin](https://play.google.com/store/apps/details?id=com.felicanetworks.mfw.a.boot) is used by websites on your browser to get payment information and process payments with FeliCa. Safe to remove if you don't use Osaifu-Keitai online.",
+ "description": "Osaifu-Keitai Web Plugin (https://play.google.com/store/apps/details?id=com.felicanetworks.mfw.a.boot)\nUsed by websites on your browser to get payment information and process payments with FeliCa.\nSafe to remove if you don't use Osaifu-Keitai online.",
"dependencies": ["com.felicanetworks.mfc"],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.sec.nfc.felicalocktest": {
- "list": "Carrier",
+ "list": "Oem",
"description": "Testing FeliCa carrier remote lock. Common to Softbank, au, and docomo.",
"dependencies": [],
"neededBy": [],
"labels": [],
"removal": "Recommended"
},
+ "com.nttdocomo.android.anmane2": {
+ "list": "Carrier",
+ "description": "Likely a placeholder for docomo's corporate MDM service. Empty package and disabled by default on consumer devices.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.anshinsecurity": {
+ "list": "Carrier",
+ "description": "Anshin-security (https://www.docomo.ne.jp/service/anshin_security/)\ndocomo's security suite providing virus scanning, spam call/email prevention and so on.\nSafe to remove, but you may want to check https://mydocomo.docomo.ne.jp for subscriptions. Frequently bundled with device insurance service.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.apnsw": {
+ "list": "Carrier",
+ "description": "APN switching control\nResource-only stub. Safe to remove.\nMay potentially cause tethering issues on legacy (pre-2016) models due to docomo's APN-switching requirements?",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.applicationmanager": {
+ "list": "Carrier",
+ "description": "docomo Application Manager\nManages installation and updates of docomo-specific app.\nSafe to remove if you don't use any docomo service.\nNOTE: After reinstall, reboot needed to launch in some cases.",
+ "dependencies": [],
+ "neededBy": [
+ "com.nttdocomo.android.homezozo",
+ "com.nttdocomo.android.dhome"
+ ],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.nttdocomo.android.databackup": {
+ "list": "Carrier",
+ "description": "Backup feature for application of docomo's service, mainly provides schedule/memo's cloud sync function.",
+ "dependencies": [],
+ "neededBy": ["com.nttdocomo.android.schedulememo"],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.devicehelp": {
+ "list": "Carrier",
+ "description": "Recommended usage tips\nIntrusive. Provide \"helpful hints\" based on user activity, but behaving like adware by showing frequent pop-ups.\nRequires high-level permissions such as Accessibility and \"Draw over other apps\" (overlay) to monitor user actions.\nIt's not enabled by default, but uninstalling recommended for a cleaner, more private experience.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.dmenu2": {
+ "list": "Carrier",
+ "description": "d-menu\nWeb page shortcut and notification receiver.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.docomoset": {
+ "list": "Carrier",
+ "description": "docomo service/cloud Settings\nAdds a \"docomo service/cloud\" entry to the system Settings app. Simple navigation screen providing entry points to docomo-specific app settings, such as d-account and docomo application manager.\nEssential for launching d-account settings.\nSafe to remove if you don't use any docomo service.",
+ "dependencies": [],
+ "neededBy": ["com.nttdocomo.android.idmanager"],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.nttdocomo.android.homezozo": {
+ "list": "Carrier",
+ "description": "docomo LIVE UX\ndocomo's default home screen (launcher).\nSafe to remove ONLY IF another launcher is installed. Certain devices such as dtab may not have any other home screen apps preinstalled.\ndocomo application manager (com.nttdocomo.android.applicationmanager) must be installed to use this.",
+ "dependencies": ["com.nttdocomo.android.applicationmanager"],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.nttdocomo.android.dhome": {
+ "list": "Carrier",
+ "description": "Legacy docomo LIVE UX\ndocomo's default home screen (launcher).\nSafe to remove ONLY IF another launcher is installed. Certain devices such as dtab may not have any other home screen apps preinstalled.\ndocomo application manager (com.nttdocomo.android.applicationmanager) must be installed to use this.",
+ "dependencies": ["com.nttdocomo.android.applicationmanager"],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.nttdocomo.android.idmanager": {
+ "list": "Carrier",
+ "description": "d ACCOUNT Settings\nAccount Settings for d-account, includes an authentication component for other docomo apps.\nSafe to remove if you don't use any docomo services, but ensure you check your login method as you may need this app for two-step authentication when logging in from other devices.",
+ "dependencies": ["com.nttdocomo.android.docomoset"],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.nttdocomo.android.initialization": {
+ "list": "Carrier",
+ "description": "DOCOMO initialization\nOOBE (Initial setup) component for docomo devices. Safe to remove.\nTips: Apps deleted here will be restored when you factory reset the device!",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.nttdocomo.android.mascot": {
+ "list": "Carrier",
+ "description": "my daiz (https://www.docomo.ne.jp/service/mydaiz/)\ndocomo's information (e.g. weather, news) app. Also displays a mascot (looks like tofu) on docomo LIVE UX. Requires lots of permissions.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.msg": {
+ "list": "Carrier",
+ "description": "+Message\nA messaging app using a carrier-customized RCS implementation by Softbank, au, and docomo. It adds LINE-like features to the standard SMS/RCS.\nSafe to remove, but recommended to have an alternative SMS app for OTPs.\nGoogle Messages is a simpler and more standard alternative.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.mymagazine": {
+ "list": "Carrier",
+ "description": "SmartNews for docomo\nNews app. Special version of SmartNews for docomo user.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.networkservice": {
+ "list": "Carrier",
+ "description": "Office Link Settings\nProvides \"Office Link\" service (docomo's enterprise internal line service). Typically accessed through the settings menu of the OEM Phone app.\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.pf.dcmippushaggregator": {
+ "list": "Carrier",
+ "description": "A background platform service that manages docomo's proprietary IP push notification system.\nSafe to remove if you don't need to receive docomo's service notifications.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.remotelock": {
+ "list": "Carrier",
+ "description": "Omakase-lock (https://www.docomo.ne.jp/service/lock/)\nRemote device lock service. Allows docomo customer support to lock your device upon request.\nSafe to remove. Google's \"Find Hub\" are better-integrated alternatives including NFC (=FeliCa) remote lock.\nNOTE: To uninstall this, open settings > App permission > Special app access > Device admin apps and disable this app (May vary depending on your device).\nFor FeliCa remote lock, a separate package (com.nttdocomo.android.felicaremotelock) is used.",
+ "dependencies": ["com.nttdocomo.android.felicaremotelock"],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.schedulememo": {
+ "list": "Carrier",
+ "description": "Schedule & Memo\n2 different apps in one package; docomo's schedule and memo apps.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.store": {
+ "list": "Carrier",
+ "description": "d-Point Market\nWeb page shortcut and notification receiver.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.wipe": {
+ "list": "Carrier",
+ "description": "Remote Wipe (https://www.docomo.ne.jp/service/initialization/)\nAllows docomo customer support to wipe your device upon request. This does NOT clear data inside the FeliCa chip.\nSafe to remove. Google's \"Find Hub\" or oem provided services are better-integrated alternatives.\nNOTE: To uninstall this, open settings > App permission > Special app access > Device admin apps and disable this app (May vary depending on your device).",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "jp.co.nttdocomo.anshinmode": {
+ "list": "Carrier",
+ "description": "Anshin-Filter for docomo (https://www.docomo.ne.jp/service/anshin_filter/0)\nCarrier-provided parental controls. Terrible.\nCauses excessive battery drain on both parent and child devices due to heavy background polling, and a ton of other issues.\nIf you care about your child's better well-being, digital experience and parent-child relationships, consider using alternative services such as Google Family link.\nStrongly recommended to uninstall.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "jp.co.nttdocomo.carriermail": {
+ "list": "Carrier",
+ "description": "docomo mail\nCarrier mail app. Safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "jp.co.nttdocomo.lcsapp": {
+ "list": "Carrier",
+ "description": "docomo location information\nProvides \"Keitai-Osagashi Service\" (Mobile Phone Finder Service) and \"imadoco search\" (parental tracking) by docomo.\ncom.nttdocomo.android.docomoset is needed to launch settings screen.\nSafe to remove, but you may want to check https://mydocomo.docomo.ne.jp for subscriptions and \"imadoco search\" Opt-Out at https://spf.spmode.ne.jp/location/posinfo_sp (spf.spmode.ne.jp is only accessible via mobile network).\nGoogle's \"Find Hub\" and \"Family Link\" are free and better alternatives integrated with Android.",
+ "dependencies": ["com.nttdocomo.android.docomoset"],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "jp.co.nttdocomo.saigaiban": {
+ "list": "Carrier",
+ "description": "Disaster kit (https://www.docomo.ne.jp/info/disaster/disaster_kit/)\nA dedicated app for docomo's safety registration service used during major emergencies. It allows users to post and search for safety status.\nNOTE: This is not related to the core functionality of Area Mail (early warning). For checking Area Mail history, you can find it in system settings.\nSafe to remove; use web171.jp, Disaster Message Dial (171) or LINE's safety status feature instead for about safety status.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.nttdocomo.android.felicaremotelock": {
+ "list": "Oem",
+ "description": "This is used to lock the Osaifu-Keitai (FeliCa), works with Omakase-lock (com.nttdocomo.android.remotelock).\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.sec.android.overlay.dcmconfig": {
+ "list": "Oem",
+ "description": "Static overlay that sets \"config_systemContacts\" to \"docomo phonebook\" (customized com.android.contacts).\nNOTE: Safe to remove, reboot needed after uninstalling.\n\"docomo phonebook\" itself is safe to remove whether this overlay is installed.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.sec.android.overlay.dcmconfig.sms": {
+ "list": "Oem",
+ "description": "Static overlay that sets \"config_defaultSms\" to \"+Message\" (com.nttdocomo.android.msg).\nNOTE: Safe to remove, reboot needed after uninstalling.\n\"+Message\" itself is safe to remove whether this overlay is installed.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
"com.samsung.android.nfc.resources.japan": {
"list": "Oem",
"description": "Overlay for com.android.nfc",
@@ -33875,14 +34070,6 @@
"labels": [],
"removal": "Recommended"
},
- "com.nttdocomo.android.felicaremotelock": {
- "list": "Oem",
- "description": "FeliCa Remote security things, not needed",
- "dependencies": [],
- "neededBy": [],
- "labels": [],
- "removal": "Recommended"
- },
"com.samsung.felicalock": {
"list": "Oem",
"description": "FeliCa Password NFC things, not needed",
@@ -34381,7 +34568,15 @@
},
"jp.co.omronsoft.mushroom.CommonPhrase": {
"list": "Oem",
- "description": "Japanese Phrases app",
+ "description": "Provides a feature called \"Mushroom\" that is a phrase table shared between Japanese keyboards.\nJapanese keyboards still work without this.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "jp.co.omronsoft.mushroom.commonphrase": {
+ "list": "Oem",
+ "description": "Provides a feature called \"Mushroom\" that is a phrase table shared between Japanese keyboards.\nJapanese keyboards still work without this.",
"dependencies": [],
"neededBy": [],
"labels": [],
From f60c8982a784d1a5d99e79d2f3feb044433e2659 Mon Sep 17 00:00:00 2001
From: MintJapan <103297262+MintJapan@users.noreply.github.com>
Date: Sun, 1 Feb 2026 16:28:00 +0900
Subject: [PATCH 016/111] pkg(docomo): fix a mistake
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index a5794f1..a492b17 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -33588,7 +33588,7 @@
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Advanced"
+ "removal": "Recommended"
},
"com.nttdocomo.android.mascot": {
"list": "Carrier",
From 70fd5be601170b108b72e431dbb39e78e98eefe8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 3 Feb 2026 19:42:49 +0000
Subject: [PATCH 017/111] chore(deps): bump bytes from 1.11.0 to 1.11.1
Bumps [bytes](https://github.com/tokio-rs/bytes) from 1.11.0 to 1.11.1.
- [Release notes](https://github.com/tokio-rs/bytes/releases)
- [Changelog](https://github.com/tokio-rs/bytes/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/bytes/compare/v1.11.0...v1.11.1)
---
updated-dependencies:
- dependency-name: bytes
dependency-version: 1.11.1
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index df790f1..fb38610 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -562,9 +562,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "bytes"
-version = "1.11.0"
+version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "calloop"
From 8e7f9e21076d76c040885425d83652954430e92f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 5 Feb 2026 18:58:49 +0000
Subject: [PATCH 018/111] chore(deps): bump time from 0.3.44 to 0.3.47
Bumps [time](https://github.com/time-rs/time) from 0.3.44 to 0.3.47.
- [Release notes](https://github.com/time-rs/time/releases)
- [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md)
- [Commits](https://github.com/time-rs/time/compare/v0.3.44...v0.3.47)
---
updated-dependencies:
- dependency-name: time
dependency-version: 0.3.47
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
Cargo.lock | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index fb38610..0043035 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2515,9 +2515,9 @@ dependencies = [
[[package]]
name = "num-conv"
-version = "0.1.0"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
[[package]]
name = "num-derive"
@@ -4062,30 +4062,30 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.44"
+version = "0.3.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
+checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
- "serde",
+ "serde_core",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
-version = "0.1.6"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
+checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
[[package]]
name = "time-macros"
-version = "0.2.24"
+version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
+checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
dependencies = [
"num-conv",
"time-core",
From 1c2d5ded76b0113ab7da96243b9c2ddd40764296 Mon Sep 17 00:00:00 2001
From: MiguVT <71216796+MiguVT@users.noreply.github.com>
Date: Thu, 5 Feb 2026 23:47:46 +0100
Subject: [PATCH 019/111] Add LineageOS Browser App details to uad_lists.json
Added details for LineageOS Browser App
---
resources/assets/uad_lists.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 5cd09ca..5caa418 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -1,4 +1,12 @@
{
+ "org.lineageos.jelly": {
+ "list": "Oem",
+ "description": "LineageOS Browser App, based on chromium.\nSafe to remove if you don't need it or have replaced it with another app.\nOtherwise there will be no browser app on your device.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
"org.lineageos.recorder": {
"list": "Oem",
"description": "LineageOS Voice Recorder App.\nSafe to remove if you don't need it or have replaced it with another app.",
From 33f15cb6dfa19e6a57e4dadaf6c7e580478010b8 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Wed, 4 Feb 2026 17:25:38 +0100
Subject: [PATCH 020/111] chore(issue-templates): add checkbox for reading
about removals
---
.github/ISSUE_TEMPLATE/3-add-new-packages.yml | 9 +++++++++
.../5-update-apps-description-or-recommendation.yml | 9 +++++++++
2 files changed, 18 insertions(+)
diff --git a/.github/ISSUE_TEMPLATE/3-add-new-packages.yml b/.github/ISSUE_TEMPLATE/3-add-new-packages.yml
index f7295b8..661b5eb 100644
--- a/.github/ISSUE_TEMPLATE/3-add-new-packages.yml
+++ b/.github/ISSUE_TEMPLATE/3-add-new-packages.yml
@@ -31,6 +31,15 @@ body:
validations:
required: true
+- type: checkboxes
+ id: removal-definitions
+ attributes:
+ label: Removal Definitions
+ description: Please ensure you follow the removal definitions when proposing changes.
+ options:
+ - label: I've read the [Removal Definitions](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Debloat-Lists#removal-definitions)
+ required: true
+
- type: checkboxes
id: acknowledgements
attributes:
diff --git a/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml b/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml
index 1872202..0a19695 100644
--- a/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml
+++ b/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml
@@ -34,6 +34,15 @@ body:
validations:
required: true
+- type: checkboxes
+ id: removal-definitions
+ attributes:
+ label: Removal Definitions
+ description: Please ensure you follow the removal definitions when proposing changes.
+ options:
+ - label: I've read the [Removal Definitions](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Debloat-Lists#removal-definitions)
+ required: true
+
- type: checkboxes
id: acknowledgements
attributes:
From e6d44912a72c5f5a7d7843a8c293455513164746 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Thu, 5 Feb 2026 15:52:14 +0100
Subject: [PATCH 021/111] chore(issue-templates): add removal level options to
issue templates
Clarify allowed Removal levels in issue templates by adding explicit options (`Recommended`|`Advanced`|`Expert`|`Unsafe`) to the Removal field. Updates .github/ISSUE_TEMPLATE/3-add-new-packages.yml and .github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml to prompt contributors to use the defined removal categories from the wiki.
---
.github/ISSUE_TEMPLATE/3-add-new-packages.yml | 2 +-
.../5-update-apps-description-or-recommendation.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/ISSUE_TEMPLATE/3-add-new-packages.yml b/.github/ISSUE_TEMPLATE/3-add-new-packages.yml
index 661b5eb..b44df06 100644
--- a/.github/ISSUE_TEMPLATE/3-add-new-packages.yml
+++ b/.github/ISSUE_TEMPLATE/3-add-new-packages.yml
@@ -16,7 +16,7 @@ body:
**List**: `Google`|`Misc`|`OEM` (manufacturer) |`AOSP`|`Pending`|`Carrier` (ISP).
- **Removal**: See the [Removal Definitions](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Debloat-Lists#removal-definitions) on the wiki for details. **Please ensure you follow these definitions when proposing changes.**
+ **Removal**: `Recommended`|`Advanced`|`Expert`|`Unsafe`. See the [Removal Definitions](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Debloat-Lists#removal-definitions) on the wiki for details. **Please ensure you follow these definitions when proposing changes.**
- type: textarea
id: package-listing
diff --git a/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml b/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml
index 0a19695..945e302 100644
--- a/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml
+++ b/.github/ISSUE_TEMPLATE/5-update-apps-description-or-recommendation.yml
@@ -16,7 +16,7 @@ body:
**List**: `Google`|`Misc`|`OEM` (manufacturer) |`AOSP`|`Pending`|`Carrier` (ISP).
- **Removal**: See the [Removal Definitions](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Debloat-Lists#removal-definitions) on the wiki for details. **Please ensure you follow these definitions when proposing changes.**
+ **Removal**: `Recommended`|`Advanced`|`Expert`|`Unsafe`. See the [Removal Definitions](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Debloat-Lists#removal-definitions) on the wiki for details. **Please ensure you follow these definitions when proposing changes.**
- type: textarea
id: package-listing
From 22e5afdfce0c414dac037147644a1276f2cd1655 Mon Sep 17 00:00:00 2001
From: toboil-features <160222185+toboil-features@users.noreply.github.com>
Date: Fri, 6 Feb 2026 12:23:24 +0000
Subject: [PATCH 022/111] Add notice about functionality loss
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 5cd09ca..f06b3d5 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -31295,7 +31295,7 @@
},
"com.transsnet.store": {
"list": "Oem",
- "description": "Palm Store. App store with unsecure apps and probably malware. Has ads trackers and lot of intrusives permissions. Shows intrusive ads and popups.\nPithus analysis: https://beta.pithus.org/report/35d762b27c9e16703adf1731b74bef2c53a753b6a7475c425bced53b553758e5",
+ "description": "Palm Store. App store with unsecure apps and probably malware. Has ads trackers and lot of intrusives permissions. Shows intrusive ads and popups.\nRequired for one-time removal of \"Hot Apps\" folder in XOS Launcher (via long press and \"Properties\").\nPithus analysis: https://beta.pithus.org/report/35d762b27c9e16703adf1731b74bef2c53a753b6a7475c425bced53b553758e5",
"dependencies": [],
"neededBy": [],
"labels": [],
From 07687314252adfa17b1e9392aa37ecddd21069dc Mon Sep 17 00:00:00 2001
From: "N.Oroz" <54943216+NikolaOroz@users.noreply.github.com>
Date: Sun, 8 Feb 2026 12:20:02 +0000
Subject: [PATCH 023/111] pkg(com.apple.atve.androidtv.appletv): add package
---
resources/assets/uad_lists.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 5cd09ca..3cd7e6f 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -42055,5 +42055,13 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
+ },
+ "com.apple.atve.androidtv.appletv": {
+ "list": "Oem",
+ "description": "Apple TV\nFactory-installed Apple TV app. Reverts to factory-version when uninstalled by normal means.\n(Shipped with Philips Android TVs, but may be present on other devices as well.)\nhttps://play.google.com/store/apps/details?id=com.apple.atve.androidtv.appletv",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
}
}
From 0084a70da5c48eaad27ead2c350daf5674254c81 Mon Sep 17 00:00:00 2001
From: Evelyn Torres
Date: Mon, 9 Feb 2026 18:22:38 -0330
Subject: [PATCH 024/111] pkg(samsung): add packages from Samsung Galaxy A20
---
resources/assets/uad_lists.json | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 852a790..ac80e4a 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -42071,5 +42071,29 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
+ },
+ "com.android.networkstack.tethering.inprocess": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.a20.d01.wallpapermulti": {
+ "list": "Oem",
+ "description": "Seems like a completely useless empty package, but the default lock screen wallpaper slideshow stops working if you uninstall this. Wallpapers can still be set fine, so it's still pretty useless.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.timezone.data_R": {
+ "list": "Oem",
+ "description": "Completely empty package. Useless. No issues with the clock after uninstalling",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
}
}
From eb3ba6b5a1d754933b819140fb494fbcebdb036d Mon Sep 17 00:00:00 2001
From: Alek Evans
Date: Mon, 9 Feb 2026 17:32:11 -0900
Subject: [PATCH 025/111] pkg(samsung): Update package description for Samsung
Keyboard
Added warning for Edge panel clipboard component breaking when removing the com.samsung.android.honeyboard package.
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 852a790..0176215 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -7594,7 +7594,7 @@
},
"com.samsung.android.honeyboard": {
"list": "Oem",
- "description": "Samsung keyboard\nWARNING: do NOT disable if you don't have another keyboard with direct boot mode support, or you'll be stuck at boot (no keyboard to unlock the phone).\nhttps://developer.android.com/training/articles/direct-boot\nWARNING: Do NOT remove this package with root if it wasn't first uninstalled with the non-root method.\nWARNING: Removing this packages breaks the Accessibility settings on Android 11.",
+ "description": "Samsung keyboard\nWARNING: do NOT disable if you don't have another keyboard with direct boot mode support, or you'll be stuck at boot (no keyboard to unlock the phone).\nhttps://developer.android.com/training/articles/direct-boot\nWARNING: Do NOT remove this package with root if it wasn't first uninstalled with the non-root method.\nWARNING: Removing this packages breaks the Accessibility settings on Android 11.\nWARNING: Removing this packages breaks the edge panel clipboard.",
"dependencies": [],
"neededBy": [],
"labels": [],
From a1f29f1f71f5a38baa897ec540627bf4a6ef058f Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Tue, 10 Feb 2026 13:16:59 +0100
Subject: [PATCH 026/111] pkg(com.oplus.aipaint): add package
---
resources/assets/uad_lists.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 91ff629..114b7b4 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -35794,6 +35794,14 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
+ },
+ "com.oplus.aipaint": {
+ "list": "Oem",
+ "description": "AI Paint\nUnsure what it's used for but probably has to do with editing images.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
},
"com.oplus.apprecover": {
"list": "Oem",
From 79f48b76dcfdf3367971370639cd9cac1c039ee1 Mon Sep 17 00:00:00 2001
From: Spyder <85440857+Spyder-0@users.noreply.github.com>
Date: Sun, 15 Feb 2026 14:54:49 +0400
Subject: [PATCH 027/111] Add/Update packages from Samsung Galaxy S7 Edge
Added new package: com.samsung.widgetapp.yahooedge.news
Updated existing package: com.microsoft.office.powerpoint
---
resources/assets/uad_lists.json | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index ac80e4a..00a20c0 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -5928,6 +5928,14 @@
"labels": [],
"removal": "Recommended"
},
+ "com.samsung.android.widgetapp.yahooedge.news": {
+ "list": "Oem",
+ "description": "Special edge panel widget for Yahoo News\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
"com.samsung.android.widget.pictureframe": {
"list": "Oem",
"description": "Samsung gallery widget, shows your selected photos as widget",
@@ -13950,7 +13958,7 @@
},
"com.microsoft.office.powerpoint": {
"list": "Misc",
- "description": "",
+ "description": "PowerPoint\n",
"dependencies": [],
"neededBy": [],
"labels": [],
From a5136a6674058053de13341f5643e56575624579 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Wed, 18 Feb 2026 15:52:31 +0100
Subject: [PATCH 028/111] chore(pull-request-templates): add templates (#1283)
* chore(pull-request-template): add templates
Introduce two pull request templates to standardize contributions: .github/pull_request_template/app.md for app-related changes (description, related issues, testing matrix, checklist) and .github/pull_request_template/packages.md for package updates (description, testing, acknowledgements, package validation checklist). These templates help ensure consistent PR metadata and verification steps for maintainers and contributors.
* chore(pull-request-templates): add documentation template
Add .github/pull_request_template/documentation.md to provide a standardized pull request template for documentation updates. The template includes a Description section, Documentation Changes section, and a checklist (link to CONTRIBUTING, clarity, grammar/spelling, link verification, code example testing, and markdown formatting) to improve consistency and quality of doc PRs.
* chore(pull-request-templates): add desktop/window manager fields
Add 'Desktop Environment' and 'Window System/Manager' checklist items to the app PR template to capture more detailed testing environment information. Also adjust the ADB version line indentation to align with the checklist structure.
* chore(pull-request-templates): use absolute URL for contributing guidelines
* chore(pull-request-templates): move files to dedicated folder
* chore(pull-request-template): reword checkbox
Co-authored-by: Angel J <78835633+iamanaws@users.noreply.github.com>
---------
Co-authored-by: Angel J <78835633+iamanaws@users.noreply.github.com>
---
.github/PULL_REQUEST_TEMPLATE/app.md | 31 +++++++++++++++++++
.../PULL_REQUEST_TEMPLATE/documentation.md | 18 +++++++++++
.github/PULL_REQUEST_TEMPLATE/packages.md | 21 +++++++++++++
.github/pull_request_template.md | 21 +++++++++++++
4 files changed, 91 insertions(+)
create mode 100644 .github/PULL_REQUEST_TEMPLATE/app.md
create mode 100644 .github/PULL_REQUEST_TEMPLATE/documentation.md
create mode 100644 .github/PULL_REQUEST_TEMPLATE/packages.md
create mode 100644 .github/pull_request_template.md
diff --git a/.github/PULL_REQUEST_TEMPLATE/app.md b/.github/PULL_REQUEST_TEMPLATE/app.md
new file mode 100644
index 0000000..41e92ae
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/app.md
@@ -0,0 +1,31 @@
+## Description
+
+
+
+### Related issues
+
+
+
+
+## How has this been tested?
+
+
+
+- [ ] Unit tests added/updated
+- [ ] Manual testing performed
+- [ ] Tested on the following environment(s):
+ - OS:
+ - Desktop Environment:
+ - Window System/Manager:
+ - ADB version:
+ - Rust version:
+
+## Checklist
+
+- [ ] I have read the [CONTRIBUTING guidelines](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/CONTRIBUTING.md)
+- [ ] My code follows the project's code style
+- [ ] I have performed a self-review of my own code
+- [ ] I have commented my code, particularly in hard-to-understand areas
+- [ ] My changes generate no new warnings
+- [ ] I have tested the application with these changes
+- [ ] The CI/CD pipeline passes
diff --git a/.github/PULL_REQUEST_TEMPLATE/documentation.md b/.github/PULL_REQUEST_TEMPLATE/documentation.md
new file mode 100644
index 0000000..530277e
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/documentation.md
@@ -0,0 +1,18 @@
+## Description
+
+
+
+
+
+## Documentation Changes
+
+
+
+## Checklist
+
+- [ ] I have read the [CONTRIBUTING guidelines](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/CONTRIBUTING.md)
+- [ ] My changes are clear and easy to understand
+- [ ] I have checked for grammar and spelling errors
+- [ ] I have verified all links are correct
+- [ ] I have tested any code examples provided
+- [ ] The documentation is properly formatted with markdown
diff --git a/.github/PULL_REQUEST_TEMPLATE/packages.md b/.github/PULL_REQUEST_TEMPLATE/packages.md
new file mode 100644
index 0000000..38cc9b2
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/packages.md
@@ -0,0 +1,21 @@
+## Description
+
+
+
+
+
+## Testing
+
+- [ ] I have tested these packages on a real device or emulator
+- [ ] Package names follow correct naming conventions (e.g., `com.example.app`)
+- [ ] Package names have been verified against device/ADB output
+- [ ] Descriptions are accurate and helpful
+- [ ] No duplicate packages added
+
+## Acknowledgements
+
+- [ ] I have read the [CONTRIBUTING guidelines](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/CONTRIBUTING.md)
+- [ ] I have followed the package addition guidelines
+- [ ] I have reviewed the [Removal Definitions](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Debloat-Lists#removal-definitions) in the wiki
+- [ ] All package information is accurate and tested
+- [ ] I understand my PR may be modified before merging
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..523bbb6
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,21 @@
+## Description
+
+
+
+## Related issues
+
+
+
+
+## Checklist
+
+- [ ] I have read the [CONTRIBUTING guidelines](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/CONTRIBUTING.md)
+- [ ] I have performed a self-review of my changes
+- [ ] My changes generate no new warnings
+- [ ] The CI/CD pipeline passes (or is expected to pass)
+
+
From 718a7d32deebfe905b04fad59636efb0d012e983 Mon Sep 17 00:00:00 2001
From: AstroMeYT <115592092+AstroMeYT@users.noreply.github.com>
Date: Sun, 22 Feb 2026 08:42:04 -0600
Subject: [PATCH 029/111] feat(app-description): added
com.sec.android.app.tfunlock app description
---
resources/assets/uad_lists.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 1573fe5..7b98b17 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -34869,6 +34869,14 @@
"neededBy": [],
"labels": [],
"removal": "Expert"
+ },
+ "com.sec.android.app.tfunlock": {
+ "list": "Carrier",
+ "description": "The unlocking interface and process when unlocking a Tracfone-based phone. Probably needed for unlocking your carrier status. probably needed if you want to unlock your phone from a Tracfone service.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
},
"com.sec.android.app.tourviewer": {
"list": "Oem",
From 4fddde5cc950c3b95ae3e3096a1b11f630cbcd8a Mon Sep 17 00:00:00 2001
From: pm-alonso <84645599+pm-alonso@users.noreply.github.com>
Date: Mon, 23 Feb 2026 23:47:20 -0300
Subject: [PATCH 030/111] Please Update uad_lists.json
This updated description will help someone like me to identify the one missing package that breaks Fast Flashlight Gesture (a very useful feature of Motorola phones indeed)
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 7b98b17..314f57f 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -4529,7 +4529,7 @@
},
"com.motorola.systemserver": {
"list": "Oem",
- "description": "Moto Service Experience, debugging app.",
+ "description": "Moto Service Experience, debugging app.\nKeep this package for consistent Moto Fast Flashlight Gesture Functionality.",
"dependencies": [],
"neededBy": [],
"labels": [],
From 3e4b8d65e919c0fbc8e7fe2bfbe914ab0ea41222 Mon Sep 17 00:00:00 2001
From: Alperen Poyraz
Date: Wed, 25 Feb 2026 15:21:06 +0300
Subject: [PATCH 031/111] Uad list update - uninstalling smartmirroring package
breaks edge panels feature
Uninstalling this breaks edge panels feature; edge panels won't work and will also crash OneUI Home when trying to switch edge panels on from settings > display. The edge panels package (com.samsung.android.app.cocktailbarservice and com.samsung.android.app.appsedge) doesn't exist on my phone so maybe on newer devices Samsung moved that functionality to this package instead. Tested on Galaxy S25 FE Android 16.
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 7b98b17..e9477bb 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -5715,7 +5715,7 @@
},
"com.samsung.android.smartmirroring": {
"list": "Oem",
- "description": "Samsung Smart View\nEnable you to mirror screen your phone to a TV (https://www.samsung.com/us/apps/smart-view-2/)\nDependency for com.samsung.android.video",
+ "description": "Samsung Smart View\nEnable you to mirror screen your phone to a TV (https://www.samsung.com/us/apps/smart-view-2/)\nDependency for com.samsung.android.video\nUninstalling this breaks edge panels feature; edge panel won't work and will also crash OneUI Home when trying to switch edge panels on from settings > display.\nThe edge panels package (com.samsung.android.app.cocktailbarservice and com.samsung.android.app.appsedge) doesn't exist on my phone so maybe on newer devices Samsung moved that functionality to this package instead. Tested on Galaxy S25 FE Android 16",
"dependencies": [],
"neededBy": [
"com.samsung.android.video"
From af50b48c68df407d0ce4ccd58f4cfa6a08def677 Mon Sep 17 00:00:00 2001
From: Rudxain <76864299+Rudxain@users.noreply.github.com>
Date: Sun, 1 Mar 2026 00:38:44 -0400
Subject: [PATCH 032/111] pkg(xiaomi): Camera Ring dependency
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index c2588de..9548ab9 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -26761,7 +26761,7 @@
"labels": []
},
"com.android.inputsettings.overlay.miui": {
- "description": "Keyboard demo found. It's something to miinput unused Chinese!",
+ "description": "Keyboard demo found. It's something to miinput unused Chinese! On HyperOS 3, it's a dependency of Camera Ring",
"removal": "Recommended",
"list": "Oem",
"dependencies": [],
From 17e5d07a8481aaf67eda61119e583277e1533671 Mon Sep 17 00:00:00 2001
From: flojo007 <83416975+flojo007@users.noreply.github.com>
Date: Sun, 8 Mar 2026 22:02:02 +0100
Subject: [PATCH 033/111] Enhance app descriptions in uad_lists.json
Updated descriptions for Samsung Cloud Platform Manager and SoundAlive apps to include additional notes on uninstallation and potential issues.
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 9548ab9..5ef4b39 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -5643,7 +5643,7 @@
},
"com.samsung.android.scpm": {
"list": "Oem",
- "description": "Samsung Cloud Platform Manager\nRelated to Samsung Cloud. Safe to remove if you don't use it.",
+ "description": "Samsung Cloud Platform Manager\nRelated to Samsung Cloud.\nNOTE: Uninstalling it causes the \"Sound Quality and Effects\" app (com.sec.android.app.soundalive) to crash regularly, resulting in a crash dialog that might become annoying. (However, the sound seems to work fine. Disabling scpm does not seem to cause errors.)",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -7248,7 +7248,7 @@
},
"com.sec.android.app.soundalive": {
"list": "Oem",
- "description": "Responsible for Dolby Atmos and other equalizer stuff (accessible from the Settings app).\nNeeded by Adapt Sound (com.sec.hearingadjust) which is a pretty useful feature.",
+ "description": "Responsible for Dolby Atmos and other equalizer stuff (accessible from the Settings app).\nNeeded by Adapt Sound (com.sec.hearingadjust) which is a pretty useful feature.\nNOTE: If the app crashes regularly, even when you don't use Dolby or other features, check to see if you have \"com.samsung.android.scpm\" installed. If not, try installing it. (Disabling scpm seems to be okay)",
"dependencies": [],
"neededBy": [],
"labels": [],
From 5590b2f8095c81d08567b65a51f2afb389872a53 Mon Sep 17 00:00:00 2001
From: flojo007 <83416975+flojo007@users.noreply.github.com>
Date: Tue, 10 Mar 2026 19:45:22 +0100
Subject: [PATCH 034/111] Update descriptions and removal recommendations
---
resources/assets/uad_lists.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 5ef4b39..0c5c083 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -5643,11 +5643,11 @@
},
"com.samsung.android.scpm": {
"list": "Oem",
- "description": "Samsung Cloud Platform Manager\nRelated to Samsung Cloud.\nNOTE: Uninstalling it causes the \"Sound Quality and Effects\" app (com.sec.android.app.soundalive) to crash regularly, resulting in a crash dialog that might become annoying. (However, the sound seems to work fine. Disabling scpm does not seem to cause errors.)",
+ "description": "Samsung Cloud Platform Manager\nRelated to Samsung Cloud.\nNOTE: Uninstalling or disabling this app causes the \"Sound Quality and Effects\" app (com.sec.android.app.soundalive) to crash regularly, resulting in a crash dialog that might become annoying. (However, the sound seems to work fine)",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.samsung.android.sconnect": {
"list": "Oem",
@@ -7248,7 +7248,7 @@
},
"com.sec.android.app.soundalive": {
"list": "Oem",
- "description": "Responsible for Dolby Atmos and other equalizer stuff (accessible from the Settings app).\nNeeded by Adapt Sound (com.sec.hearingadjust) which is a pretty useful feature.\nNOTE: If the app crashes regularly, even when you don't use Dolby or other features, check to see if you have \"com.samsung.android.scpm\" installed. If not, try installing it. (Disabling scpm seems to be okay)",
+ "description": "Responsible for Dolby Atmos and other equalizer stuff (accessible from the Settings app).\nNeeded by Adapt Sound (com.sec.hearingadjust) which is a pretty useful feature.\nNOTE: If the app crashes regularly, even when you don't use Dolby or other features, check to see if you have \"com.samsung.android.scpm\" installed & enabled. If not, try installing/enabling it.",
"dependencies": [],
"neededBy": [],
"labels": [],
From a4f03d1b43da8c43db8402602ff9a0b34e71d71a Mon Sep 17 00:00:00 2001
From: Cian Ormond
Date: Sun, 15 Mar 2026 19:09:14 -0700
Subject: [PATCH 035/111] pkg(jp.co.omronsoft.iwnnime.ml): change to unsafe
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 0c5c083..00d7fc2 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -37500,11 +37500,11 @@
},
"jp.co.omronsoft.iwnnime.ml": {
"list": "Carrier",
- "description": "iWnn IME\nJapanese keyboard pre-installed on some Huawei phone's.",
+ "description": "iWnn IME\nJapanese keyboard pre-installed on some Huawei and Kyocera phones. Some phones cannot be unlocked without it.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Unsafe"
},
"com.kmsjp": {
"list": "Carrier",
From 513688c091075318aa58108f42123a9bc1b642b7 Mon Sep 17 00:00:00 2001
From: Forero-0
Date: Wed, 18 Mar 2026 22:09:07 -0500
Subject: [PATCH 036/111] Update uad_lists.json
---
resources/assets/uad_lists.json | 80 +++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 00d7fc2..68de48e 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -42151,5 +42151,85 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
+ },
+ "com.sec.android.usermanual": {
+ "list": "Oem",
+ "description": "Opens the device’s built‑in user manual PDF",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.a50.d01.wallpapermulti": {
+ "list": "Oem",
+ "description": "Provides the wallpapers used by the lockscreen multi-pack feature",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.SMT.lang_es_mx_f00": {
+ "list": "Oem",
+ "description": "Voice pack for Samsung TTS in Spanish (Mexico).",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.samsung.SMT.lang_pt_br_f00": {
+ "list": "Oem",
+ "description": "Voice pack for Samsung TTS in Portuguese (Brazil).",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.samsung.SMT.lang_en_us_f00": {
+ "list": "Oem",
+ "description": "Voice pack for Samsung TTS in English (United States).",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.samsung.android.internal.overlay.config.default_contextual_search": {
+ "list": "Oem",
+ "description": "The code only assigns (com.google.android.googlequicksearchbox) as the default contextual search package via (config_defaultContextualSearchPackageName).\nI suppose that if (com.google.android.googlequicksearchbox) is removed, this feature stops working.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.samsung.drmboost": {
+ "list": "Oem",
+ "description": "Boosts CPU performance during secure DRM (Digital Rights Management) playback by monitoring codec activity and applying a DVFS (Dynamic Voltage and Frequency Scaling) hint (1400).",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.samsung.android.nfc.resources.default": {
+ "list": "Oem",
+ "description": "Provides default NFC configuration resources (booleans and polling delays). Contains no executable code.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.samsung.android.privateaccesstokens": {
+ "list": "Oem",
+ "description": "Provides a system module used by Samsung Internet for an automatic verification feature on compatible websites to skip CAPTCHAs.\nOn my device the option never appeared. Removing it does not affect normal system functionality.\nIt relies on a few privileged permissions such as READ_PRIVILEGED_PHONE_STATE , SAMSUNG_KEYSTORE_PERMISSION , ACCESS_KEYGUARD_SECURE_STORAGE , and INTERNET/ACCESS_NETWORK_STATE.\nhttps://apps.samsung.com/appquery/appDetail.as?appId=com.samsung.android.privateaccesstokens",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.accessory.budsunitemgr": {
+ "list": "Oem",
+ "description": "Provides the system component that manages Galaxy Buds features and configuration. It handles firmware updates, noise control modes (ANC / Ambient sound), touch controls, and all device‑specific settings.\nOn my device, uninstalling it removed the ability to update the Buds or use any of the features mentioned above.\nAccording to the Galaxy Store description, it also requires the Galaxy Wearable package (com.samsung.android.app.watchmanagerstub) to function.\nhttps://apps.samsung.com/appquery/appDetail.as?appId=com.samsung.accessory.budsunitemgr\nhttps://play.google.com/store/apps/details?id=com.samsung.accessory.budsunitemgr",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
}
}
From 9f0e06774f55d71390ff0c8b5c8d0b5f0e584147 Mon Sep 17 00:00:00 2001
From: Forero-0
Date: Thu, 19 Mar 2026 12:22:20 -0500
Subject: [PATCH 037/111] Update uad_lists.json
---
resources/assets/uad_lists.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 68de48e..cdf7f0d 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -42231,5 +42231,13 @@
"neededBy": [],
"labels": [],
"removal": "Advanced"
+ },
+ "com.mygalaxy.service": {
+ "list": "Oem",
+ "description": "Module likely used by the MyGalaxy app (https://play.google.com/store/apps/details?id=com.mygalaxy).\nOnly works on India CSC INS/INU. On all other regions it disables itself automatically.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
}
}
From b9216c0120ac63fe59982e75c5fb7672f1e651bb Mon Sep 17 00:00:00 2001
From: HstSethi <107557004+hstsethi@users.noreply.github.com>
Date: Fri, 20 Mar 2026 09:31:37 +0530
Subject: [PATCH 038/111] pkg(in.gov.uidai.pehchaan) Add new Aadhaar app
mandated by government to list
---
resources/assets/uad_lists.json | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 00d7fc2..9255862 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -42151,5 +42151,13 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
- }
+ },
+ "in.gov.uidai.pehchaan": {
+ "list": "Oem",
+ "description": "National ID app based on a unique 12 digit number and biometrics information. Privately mandated by Government of India to be pre-installed on devices.\nSource: https://www.reuters.com/world/china/indias-proposal-preload-national-id-app-aadhaar-phones-faced-pushback-2026-03-19/",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
}
+}
From c93331e8c8cb5eeb79739b7af7b5a022227a0de1 Mon Sep 17 00:00:00 2001
From: nift4
Date: Fri, 20 Mar 2026 16:05:54 +0100
Subject: [PATCH 039/111] Some AOSP apps are better left alone
---
resources/assets/uad_lists.json | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 00d7fc2..03537dd 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -8097,8 +8097,8 @@
"removal": "Recommended"
},
"com.android.runintest.ddrtest": {
- "list": "Aosp",
- "description": "DDR Test\nRAM Stress tester\nCan be run from the bootloader\nNOTE: I'm not sure it's really from AOSP (seen in TCL Plex phone)\n",
+ "list": "Oem",
+ "description": "DDR Test\nRAM Stress tester\nCan be run from the bootloader\n(seen in TCL Plex phone)\n",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -8106,11 +8106,11 @@
},
"com.android.safetycenter.resources": {
"list": "Aosp",
- "description": "Google Safety Center.\nProbably affects malware detection in new app installs, Gmail, and Chrome. This will also revert back the\"Security & privacy\" look to the old style.\nYou can use a libre spam-blocking and DNS-blocking solution instead of this.\nhttps://safety.google",
+ "description": "Google/AOSP Safety Center resources.\n. Uninstalling this will change the configuration to revert back the\"Security & privacy\" look to the old style.\nDoes not contain code, just the configuration for code that lives in another package.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.android.sdksandbox": {
"list": "Aosp",
@@ -8282,7 +8282,7 @@
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.android.captiveportallogin": {
"list": "Aosp",
@@ -8748,7 +8748,7 @@
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.google.android.contactkeys": {
"list": "Google",
@@ -23426,8 +23426,8 @@
"labels": []
},
"com.svox.pico": {
- "description": "Pico TTS\nHidden sample voice data. Useless.",
- "removal": "Recommended",
+ "description": "Pico TTS\nOpen source TTS engine shipped on old Android devices and some custom ROMs\nUninstalling this without installing a TTS engine will break TTS, it also doesn't access the internet so there's not much to gain",
+ "removal": "Advanced",
"list": "Oem",
"dependencies": [],
"neededBy": [],
@@ -32255,11 +32255,11 @@
},
"com.android.fmradio": {
"list": "Aosp",
- "description": "FM Radio\n Plug in Head phones & listen to the Radio!\n",
+ "description": "FM Radio\n Plug in Head phones & listen to the Radio!\nUninstalling will break FM Radio until reinstalled, and no other FM apps can be downloaded from app stores",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.haoba.btsmart": {
"list": "Misc",
@@ -34980,7 +34980,7 @@
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.android.healthconnect.controller": {
"list": "Aosp",
@@ -34988,15 +34988,15 @@
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.android.virtualmachine.res": {
"list": "Aosp",
- "description": "unknown app with no code that only has permissions to Use, Manage, Debug: Virtual Machine.\nIntroduced in Android 14.",
+ "description": "Empty app with no code that declares permissions to Use, Manage, Debug: Virtual Machine for use by other apps. Deleting this app may cause potential security issues because another app could redefine the permissions with lower restriction level. Nothing to gain by removing.\nIntroduced in Android 14.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Expert"
},
"com.android.rkpdapp": {
"list": "Aosp",
@@ -35012,7 +35012,7 @@
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.android.systemui.accessibility.accessibilitymenu": {
"list": "Aosp",
@@ -38048,7 +38048,7 @@
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.xiaomi.oobhelper": {
"list": "Oem",
From 60477371186061c71ca09ccadf049612700bbfb7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 20 Mar 2026 18:12:23 +0000
Subject: [PATCH 040/111] chore(deps): bump tar from 0.4.44 to 0.4.45
Bumps [tar](https://github.com/alexcrichton/tar-rs) from 0.4.44 to 0.4.45.
- [Commits](https://github.com/alexcrichton/tar-rs/compare/0.4.44...0.4.45)
---
updated-dependencies:
- dependency-name: tar
dependency-version: 0.4.45
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 0043035..d8e38d2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3975,9 +3975,9 @@ dependencies = [
[[package]]
name = "tar"
-version = "0.4.44"
+version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
+checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
dependencies = [
"filetime",
"libc",
From 2caad7db20f08a48c9a625e868a1d2dc7da1c0f7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 21 Mar 2026 09:38:03 +0000
Subject: [PATCH 041/111] chore(deps): bump rustls-webpki from 0.103.8 to
0.103.10
Bumps [rustls-webpki](https://github.com/rustls/webpki) from 0.103.8 to 0.103.10.
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](https://github.com/rustls/webpki/compare/v/0.103.8...v/0.103.10)
---
updated-dependencies:
- dependency-name: rustls-webpki
dependency-version: 0.103.10
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 0043035..be367b4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3597,9 +3597,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
-version = "0.103.8"
+version = "0.103.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
+checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
dependencies = [
"ring",
"rustls-pki-types",
From 8caff5c7fda99c8f3e65242dd7aae2f83fad3d26 Mon Sep 17 00:00:00 2001
From: true_lock <168660625+truelockmc@users.noreply.github.com>
Date: Sat, 21 Mar 2026 17:36:35 +0100
Subject: [PATCH 042/111] fixed data for com.samsung.android.timezone.data_R
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 00d7fc2..5a28b1e 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -42146,10 +42146,10 @@
},
"com.samsung.android.timezone.data_R": {
"list": "Oem",
- "description": "Completely empty package. Useless. No issues with the clock after uninstalling",
+ "description": "Causes bootloop on Samsung Galaxy A50 (SM-A505FN). Rescue Party triggered, package manager service fails to start. Device becomes unbootable. Do NOT remove on older Samsung devices.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Unsafe"
}
}
From d2e81c66295068dd06173a3e637c0de007bd0f33 Mon Sep 17 00:00:00 2001
From: true_lock <168660625+truelockmc@users.noreply.github.com>
Date: Sat, 21 Mar 2026 22:25:52 +0100
Subject: [PATCH 043/111] Update description for Samsung Galaxy A50 bootloop
issue
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 5a28b1e..5910d21 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -42146,7 +42146,7 @@
},
"com.samsung.android.timezone.data_R": {
"list": "Oem",
- "description": "Causes bootloop on Samsung Galaxy A50 (SM-A505FN). Rescue Party triggered, package manager service fails to start. Device becomes unbootable. Do NOT remove on older Samsung devices.",
+ "description": "Causes bootloop on any Samsung Galaxy A50. Rescue Party triggered, package manager service fails to start. Device becomes unbootable. Do NOT remove on older Samsung devices.",
"dependencies": [],
"neededBy": [],
"labels": [],
From 51eb6e0a876baad8b0cdd164ab1f020baa1e84e6 Mon Sep 17 00:00:00 2001
From: true_lock <168660625+truelockmc@users.noreply.github.com>
Date: Wed, 25 Mar 2026 20:20:50 +0100
Subject: [PATCH 044/111] Restored Changes on
com.samsung.android.timezone.data_R description
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index c089830..d0aade5 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -42146,11 +42146,11 @@
},
"com.samsung.android.timezone.data_R": {
"list": "Oem",
- "description": "Completely empty package. Useless. No issues with the clock after uninstalling",
+ "description": "Causes bootloop on any Samsung Galaxy A50 when removed. \n Rescue Party will be triggered, package manager service will fail to start. \n Device becomes unbootable. Do NOT remove on older Samsung devices.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Unsafe"
},
"com.sec.android.usermanual": {
"list": "Oem",
From 32360a04b67dd42df84586dfbc256a0d20187f27 Mon Sep 17 00:00:00 2001
From: "Re*Index. (ot_inc)" <32851879+reindex-ot@users.noreply.github.com>
Date: Fri, 27 Mar 2026 02:12:24 +0900
Subject: [PATCH 045/111] Add Aura from Unity srction.
---
resources/assets/uad_lists.json | 68 ++++++++++++++++++++++++++++++++-
1 file changed, 66 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index caa0746..93b5ca5 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -32403,9 +32403,73 @@
"labels": [],
"removal": "Advanced"
},
- "com.aura.oobe.kbdi": {
+ "com.aura.oobe.kddi": {
+ "list": "carrier",
+ "description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some au carrier phones\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.aura.oobe.ntt": {
+ "list": "carrier",
+ "description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some docomo carrier phones\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.aura.oobe.softbank": {
+ "list": "carrier",
+ "description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some SoftBank carrier phones\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.aura.oobe.rakuten": {
+ "list": "carrier",
+ "description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Rakuten Mobile carrier phones\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.aura.oobe.solutions": {
"list": "Oem",
- "description": "Appcloud\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Xiaomi phones\nSafe to remove.",
+ "description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Nothing & CMF Phone\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.aura.oobe.lenovo": {
+ "list": "Oem",
+ "description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Lenovo\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.aura.oobe.ml": {
+ "list": "Oem",
+ "description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Motorola\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.aura.oobe.motorola": {
+ "list": "Oem",
+ "description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Motorola\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.dti.motorola": {
+ "list": "Oem",
+ "description": "Digital Turbine\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Motorola\nSafe to remove.",
"dependencies": [],
"neededBy": [],
"labels": [],
From 82adb10fc04c6cbcb10ecad0621aa3a7ea496c2f Mon Sep 17 00:00:00 2001
From: "Re*Index. (ot_inc)" <32851879+reindex-ot@users.noreply.github.com>
Date: Fri, 27 Mar 2026 02:13:11 +0900
Subject: [PATCH 046/111] Add Aura from Unity section
From ae3c59cf89d545da1eea1be2ddea07cd0a68bd43 Mon Sep 17 00:00:00 2001
From: Jacob L <52282566+lawson85@users.noreply.github.com>
Date: Thu, 2 Apr 2026 13:42:46 +0100
Subject: [PATCH 047/111] Add android.ext.shared entry to uad_lists.json
---
resources/assets/uad_lists.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index caa0746..4391266 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -6,6 +6,14 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
+ },
+ "android.ext.shared": {
+ "list": "Aosp",
+ "description": "Android Shared Library, removing may cause a bootloop.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Unsafe"
},
"org.lineageos.recorder": {
"list": "Oem",
From 8e852266b2538c115f41777eb111d95c57f2e1d6 Mon Sep 17 00:00:00 2001
From: Jacob L <52282566+lawson85@users.noreply.github.com>
Date: Thu, 2 Apr 2026 14:32:33 +0100
Subject: [PATCH 048/111] Add Cyanogenmod file manager to uad_lists.json
Added entry for Cyanogenmod file manager with details.
---
resources/assets/uad_lists.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 4391266..30e4221 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -6,6 +6,14 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
+ },
+ "com.cyanogenmod.filemanager": {
+ "list": "Oem",
+ "description": "Cyanogenmod file manager, safe to remove if you use another one.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
},
"android.ext.shared": {
"list": "Aosp",
From 4cec1c0a911509a135834ba0f4107a2b8ece2b62 Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 21:12:14 +0000
Subject: [PATCH 049/111] docs: update descriptions and removals for
com.google.android.soundpicker and com.google.android.settings.intelligence
---
resources/assets/uad_lists.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index caa0746..b1f809a 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -28989,11 +28989,11 @@
},
"com.google.android.soundpicker": {
"list": "Google",
- "description": "Google Sounds. Removable if you already have another media select service.\n",
+ "description": "Google Sounds. Provides notification, alarm, and ringtone sounds, will be set to default sounds (and cannot be changed) if removed, unless you already have another media select service.\n",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.google.android.street": {
"list": "Google",
@@ -40458,7 +40458,7 @@
},
"com.google.android.settings.intelligence": {
"list": "Aosp",
- "description": "Settings Services/nAdds the main search bar for the settings app (the one at the top on the default page). When uninstalled, search bar will be invisible. May have other purposes regarding settings. /nUses location, nearby devices, notifications permissions by default.",
+ "description": "Setting Services. Adds the main search bar for the settings app (the one at the top on the default page).\n",
"dependencies": [],
"neededBy": [],
"labels": [],
From f8ccfa686c7d572996e6f0f18e06aec03f5f07d7 Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 21:18:11 +0000
Subject: [PATCH 050/111] docs: update description and removal for
com.google.hearing.visualization.accessibility.scribe
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index b1f809a..0850eb2 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -29429,11 +29429,11 @@
},
"com.google.audio.hearing.visualization.accessibility.scribe": {
"list": "Google",
- "description": "Live Transcribe & Sound Notifications (https://play.google.com/store/apps/details?id=com.google.audio.hearing.visualization.accessibility.scribe)\nProvides push notifications for critical sounds around you. This feature can be helpful for people with hearing loss.\nhttps://blog.google/products/android/new-sound-notifications-on-android/\nWorks offline\n",
+ "description": "Live Transcribe & Sound Notifications (https://play.google.com/store/apps/details?id=com.google.audio.hearing.visualization.accessibility.scribe)\nProvides push notifications for critical sounds around you. This feature can be helpful for people with hearing loss.\nhttps://blog.google/products/android/new-sound-notifications-on-android/\nWorks offline\nProvides text-to-speech for most apps, find a replacement before uninstalling\n",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.android.vending": {
"list": "Google",
From e23a0c9058e629bc8ee88499c1a904684838508d Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 21:20:46 +0000
Subject: [PATCH 051/111] docs: update description for
com.google.android.apps.nexuslauncher
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 0850eb2..4da9968 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -29205,7 +29205,7 @@
},
"com.google.android.apps.nexuslauncher": {
"list": "Google",
- "description": "Pixel Launcher (https://play.google.com/store/apps/details?id=com.google.android.apps.nexuslauncher)\nUsed to be called Nexus Launcher(back when Google's phones were called Nexus, not Pixel).\nA launcher is basically your homescreen.\nDON'T REMOVE IF YOU HAVEN'T INSTALLED ANOTHER LAUNCHER! Nova Launcher is usually the go-to custom launcher.",
+ "description": "Pixel Launcher (https://play.google.com/store/apps/details?id=com.google.android.apps.nexuslauncher)\nUsed to be called Nexus Launcher(back when Google's phones were called Nexus, not Pixel).\nA launcher is basically your homescreen.\nDON'T REMOVE IF YOU HAVEN'T INSTALLED ANOTHER LAUNCHER!\nREMOVING CAUSES GESTURES/THREE BUTTON NAVIGATION TO DISAPPEAR ENTIRELY!\n",
"dependencies": [],
"neededBy": [],
"labels": [],
From 26b470d8a2200852a82e93b7448ebacd26069693 Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 21:24:53 +0000
Subject: [PATCH 052/111] docs: update com.google.android.settings.intelligence
add comprehensive comparison chart for alternative launchers
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 4da9968..14cdf01 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -29205,7 +29205,7 @@
},
"com.google.android.apps.nexuslauncher": {
"list": "Google",
- "description": "Pixel Launcher (https://play.google.com/store/apps/details?id=com.google.android.apps.nexuslauncher)\nUsed to be called Nexus Launcher(back when Google's phones were called Nexus, not Pixel).\nA launcher is basically your homescreen.\nDON'T REMOVE IF YOU HAVEN'T INSTALLED ANOTHER LAUNCHER!\nREMOVING CAUSES GESTURES/THREE BUTTON NAVIGATION TO DISAPPEAR ENTIRELY!\n",
+ "description": "Pixel Launcher (https://play.google.com/store/apps/details?id=com.google.android.apps.nexuslauncher)\nUsed to be called Nexus Launcher(back when Google's phones were called Nexus, not Pixel).\nA launcher is basically your homescreen.\nDON'T REMOVE IF YOU HAVEN'T INSTALLED ANOTHER LAUNCHER!\nREMOVING CAUSES GESTURES/THREE BUTTON NAVIGATION TO DISAPPEAR ENTIRELY!\nhttps://vikrant.is-a.dev/Android-Launcher-Comparison-Table/ has a comprehensive comparison of many alternative launchers\n",
"dependencies": [],
"neededBy": [],
"labels": [],
From 06e5dbd2db446388d5165020f7a2adc53ddcca81 Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 21:26:36 +0000
Subject: [PATCH 053/111] docs: update description and removal for
com.google.android.apps.camera.services
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 14cdf01..5dcd34a 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -36400,11 +36400,11 @@
},
"com.google.android.apps.camera.services": {
"list": "Oem",
- "description": "Pixel Camera Services\nExperimental stuff, Camera Calibration.",
+ "description": "Pixel Camera Services\nExperimental stuff, Camera Calibration. Will break any third-party camera app if removed",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Advanced"
+ "removal": "Expert"
},
"com.android.qns": {
"list": "Oem",
From 745f03654c533ad219ceab0791c9f347e5f70fc6 Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 21:30:21 +0000
Subject: [PATCH 054/111] docs: update description and removal for
android.auto_generated_rro_product__
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 5dcd34a..c948ea8 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -10926,11 +10926,11 @@
},
"android.auto_generated_rro_product__": {
"list": "Aosp",
- "description": "RRO = Runtime Resources Overlay. Used by OEMs to customize look and feel of certain applications.\nhttps://source.android.com/devices/architecture/rros\nhttps://code.tutsplus.com/tutorials/quick-tip-theme-android-with-the-runtime-resource-overlay-framework--cms-29708",
+ "description": "Runtime Resources Overlay. Used by OEMs to customize look and feel of certain applications.\nhttps://source.android.com/devices/architecture/rros\nhttps://code.tutsplus.com/tutorials/quick-tip-theme-android-with-the-runtime-resource-overlay-framework--cms-29708\nRemoving causes bootloop on Nokia C32\n",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Expert"
+ "removal": "Unsafe"
},
"android.auto_generated_rro_vendor__": {
"list": "Aosp",
From 1ef7a9f67c515ff86bde06603d88e3eeb1255a2e Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 21:31:48 +0000
Subject: [PATCH 055/111] docs: re-add missing description segment
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index c948ea8..d0ab526 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -10926,7 +10926,7 @@
},
"android.auto_generated_rro_product__": {
"list": "Aosp",
- "description": "Runtime Resources Overlay. Used by OEMs to customize look and feel of certain applications.\nhttps://source.android.com/devices/architecture/rros\nhttps://code.tutsplus.com/tutorials/quick-tip-theme-android-with-the-runtime-resource-overlay-framework--cms-29708\nRemoving causes bootloop on Nokia C32\n",
+ "description": "RRO = Runtime Resources Overlay. Used by OEMs to customize look and feel of certain applications.\nhttps://source.android.com/devices/architecture/rros\nhttps://code.tutsplus.com/tutorials/quick-tip-theme-android-with-the-runtime-resource-overlay-framework--cms-29708\nRemoving causes bootloop on Nokia C32\n",
"dependencies": [],
"neededBy": [],
"labels": [],
From 2cac0cb2ca3eac8a382c04d224741a44607b464f Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 21:37:00 +0000
Subject: [PATCH 056/111] Revert 1ef7a9f and 745f036
Didn't see that the issue was awaiting author response
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index d0ab526..5dcd34a 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -10926,11 +10926,11 @@
},
"android.auto_generated_rro_product__": {
"list": "Aosp",
- "description": "RRO = Runtime Resources Overlay. Used by OEMs to customize look and feel of certain applications.\nhttps://source.android.com/devices/architecture/rros\nhttps://code.tutsplus.com/tutorials/quick-tip-theme-android-with-the-runtime-resource-overlay-framework--cms-29708\nRemoving causes bootloop on Nokia C32\n",
+ "description": "RRO = Runtime Resources Overlay. Used by OEMs to customize look and feel of certain applications.\nhttps://source.android.com/devices/architecture/rros\nhttps://code.tutsplus.com/tutorials/quick-tip-theme-android-with-the-runtime-resource-overlay-framework--cms-29708",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Unsafe"
+ "removal": "Expert"
},
"android.auto_generated_rro_vendor__": {
"list": "Aosp",
From 5b52c2dbe6a319bf96f7f950dcd11994a67bd9ae Mon Sep 17 00:00:00 2001
From: Efreak
Date: Fri, 3 Apr 2026 15:16:43 -0700
Subject: [PATCH 057/111] disabling com.samsung.storyservice disables samsung
edge panels
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index caa0746..84e3a79 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -6198,7 +6198,7 @@
},
"com.samsung.storyservice": {
"list": "Oem",
- "description": "Samsung StoryService\nCreate stories in the Gallery from your pictures and videos.\nhttps://www.samsung.com/uk/support/mobile-devices/what-is-video-collage-and-how-do-i-use-it/\nUse of content recognition (so may be related)\n",
+ "description": "Samsung StoryService\nCreate stories in the Gallery from your pictures and videos.\nhttps://www.samsung.com/uk/support/mobile-devices/what-is-video-collage-and-how-do-i-use-it/\nUse of content recognition (so may be related)\nDisabling breaks edge panels on my s9+ with OneUI 8.0/Android 16\n",
"dependencies": [],
"neededBy": [],
"labels": [],
From a6865c01a56ad24bba86574129921774ffb19b0c Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 22:38:17 +0000
Subject: [PATCH 058/111] docs: change 7 package descriptions and/or removal
---
resources/assets/uad_lists.json | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 5dcd34a..f6101e1 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -4353,11 +4353,11 @@
},
"com.motorola.setup": {
"list": "Oem",
- "description": "Related to Motorola Account setup (only during first boot ?)\nSafe to remove according to xda users.\n",
+ "description": "Related to Motorola Account setup (only during first boot ?)\nWARNING: Removing this package breaks Google Play System Updates. Appears to be tied to Google's Play Store update mechanism on Motorola devices\n",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.motorola.slpc_sys": {
"list": "Oem",
@@ -28781,11 +28781,11 @@
},
"com.google.android.apps.wallpaper": {
"list": "Google",
- "description": "Google Wallpapers (https://play.google.com/store/apps/details?id=com.google.android.apps.wallpaper)\n",
+ "description": "Google Wallpapers (https://play.google.com/store/apps/details?id=com.google.android.apps.wallpaper)\nRemoves the wallpaper section in the settings app when removed, but keeps current wallpapers.\n",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.google.android.apps.wellbeing": {
"list": "Google",
@@ -28893,7 +28893,7 @@
},
"com.google.android.googlequicksearchbox": {
"list": "Google",
- "description": "Google Search box (https://play.google.com/store/apps/details?id=com.google.android.googlequicksearchbox)\nRuns in the background.\nPointless. If you need a shortcut to Google on your homescreen just use a web-browser shortcut. Does also remove the Google Sound Search widget, but you can get that functionality from an app like Shazam, that additionally doesn't run in the background constantly like this package does.\nThis app also powers the Google Discover page (the news 'widget' when you go to the left of the home screen) and the app symbol called 'Google'.\nWARNING: disabling this package also breaks the Ok Google Search functionality as well as Google Lens.",
+ "description": "Google Search box (https://play.google.com/store/apps/details?id=com.google.android.googlequicksearchbox)\nRuns in the background.\nPointless. If you need a shortcut to Google on your homescreen just use a web-browser shortcut. Does also remove the Google Sound Search widget, but you can get that functionality from an app like Shazam, that additionally doesn't run in the background constantly like this package does.\nThis app also powers the Google Discover page (the news 'widget' when you go to the left of the home screen) and the app symbol called 'Google'.\nWARNING: disabling this package also breaks the Ok Google Search functionality as well as Circle to Search functionality.",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -28917,11 +28917,11 @@
},
"com.google.android.markup": {
"list": "Google",
- "description": "Google Markup app made for modifying pictures, shipped by default on every Pie+ device.\n",
+ "description": "Google Markup app made for modifying pictures, shipped by default on every Pie+ device.\nRemoves the button to quickly edit screenshots once taken.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.google.android.marvin.talkback": {
"list": "Google",
@@ -28973,11 +28973,11 @@
},
"com.google.android.projection.gearhead": {
"list": "Google",
- "description": "Android Auto (https://play.google.com/store/apps/details?id=com.google.android.projection.gearhead)",
+ "description": "Android Auto (https://play.google.com/store/apps/details?id=com.google.android.projection.gearhead)\nNo direct replacement appears to exist.\n",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.google.android.pixel.setupwizard": {
"list": "Google",
@@ -33085,7 +33085,7 @@
},
"com.google.android.apps.safetyhub": {
"list": "Google",
- "description": "Personal Safety (https://play.google.com/store/apps/details?id=com.google.android.apps.safetyhub)\nPersonal Safety is a Pixel app that helps you prepare and react in an emergency by quickly calling emergency services (e.g if your phone detects that you've been in a car crash, it can call for help automatically)\n\nThis app has obviously a lot of dangerous permissions due to its operation.\n\nPithus analysis: https://beta.pithus.org/report/e207f7d0f59d9df268154b90fc10cd861d0483465e30bbac8f68a7b12340c67f",
+ "description": "Personal Safety (https://play.google.com/store/apps/details?id=com.google.android.apps.safetyhub)\nPersonal Safety is a Pixel app that helps you prepare and react in an emergency by quickly calling emergency services (e.g if your phone detects that you've been in a car crash, it can call for help automatically)\nMost features require a Google account to work unfortunately...\n\nThis app has obviously a lot of dangerous permissions due to its operation.\n\nPithus analysis: https://beta.pithus.org/report/e207f7d0f59d9df268154b90fc10cd861d0483465e30bbac8f68a7b12340c67f",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -33848,11 +33848,11 @@
},
"com.android.uwb.resources": {
"list": "Aosp",
- "description": "Ultra-wideband (UWB) communication feature.\nUWB is a radio technology that enables precise ranging between devices, allowing accurate location measurements with an accuracy of 10 cm.\nSee https://developer.android.com/develop/connectivity/uwb\nhttps://source.android.com/docs/core/connect/uwb\nOnly supported on a currently narrow amount of devices, primarily high-end devices. But the app itself is often preinstalled even if your phone doesn't have any UWB hardware, especially on newer Android versions.\nCheck if your device has UWB hardware. Safe to remove if it doesn't. Don't forget to remove its overlays and dependencies.",
+ "description": "Uninstalling will cause bootloop on certain devices. Seems to be not affected by whether the hardware supports UWB or not.\nUltra-wideband (UWB) communication feature.\nUWB is a radio technology that enables precise ranging between devices, allowing accurate location measurements with an accuracy of 10 cm.\nSee https://developer.android.com/develop/connectivity/uwb\nhttps://source.android.com/docs/core/connect/uwb\nOnly supported on a currently narrow amount of devices, primarily high-end devices. But the app itself is often preinstalled even if your phone doesn't have any UWB hardware, especially on newer Android versions.\n",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Expert"
+ "removal": "Unsafe"
},
"com.mediatek.gbaservice": {
"list": "Misc",
From 648f5a088faac4c5cae91754dab22b3b0ecd1a79 Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Fri, 3 Apr 2026 22:52:14 +0000
Subject: [PATCH 059/111] docs: change description and removal for
com.transsion.zahooc and com.transsion.batterylab
---
resources/assets/uad_lists.json | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index f6101e1..a5e11ff 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -25346,8 +25346,8 @@
"labels": []
},
"com.transsion.zahooc": {
- "description": "Za-Hooc\nit's for secure card and Theft Alert.",
- "removal": "Recommended",
+ "description": "This package is actually the 'Privacy' section in the Settings app. All the features inside, such as Blank Data, App Lock, App Twin, etc., belong to this package.",
+ "removal": "Expert",
"list": "Oem",
"dependencies": [],
"neededBy": [],
@@ -31463,11 +31463,11 @@
},
"com.transsion.batterylab": {
"list": "Oem",
- "description": "Supposed to improve battery life but logs especially lots of usage info and bind it to your unique android advertiser id...The app tries to send data to a server. The POST request URL and content is obfuscated and I don't have the time to dig deeper. According to a user, no battery impact after months of usage after uninstalling it.\n\nPithus analysis: https://beta.pithus.org/report/7ef2b186a74102828346f23b094ab2aaaad2c57806c7c18e7a23a494f3cc982c",
+ "description": "This package is actually the 'Battery & Power Saving' section in the Settings app, where you can: view battery information (such as health, usage, etc.), enable/disable Power Saving and Ultra Power Saving modes, adjust charging speed, set charging percentage limits, and more.\nTherefore, uninstalling or freezing this package may result in the loss of many useful options. Please make sure you really want to 'unleash' the full power of your battery before proceeding with uninstalling or freezing this package.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Expert"
},
"com.transsion.stasticalsales": {
"list": "Oem",
From a8ed2ea1ec3bf1657f23e98f99a2f042321bc644 Mon Sep 17 00:00:00 2001
From: "Re*Index. (ot_inc)" <32851879+reindex-ot@users.noreply.github.com>
Date: Sun, 5 Apr 2026 06:58:17 +0900
Subject: [PATCH 060/111] Fix typo
---
resources/assets/uad_lists.json | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 93b5ca5..d551f2f 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -32404,7 +32404,7 @@
"removal": "Advanced"
},
"com.aura.oobe.kddi": {
- "list": "carrier",
+ "list": "Carrier",
"description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some au carrier phones\nSafe to remove.",
"dependencies": [],
"neededBy": [],
@@ -32412,7 +32412,7 @@
"removal": "Recommended"
},
"com.aura.oobe.ntt": {
- "list": "carrier",
+ "list": "Carrier",
"description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some docomo carrier phones\nSafe to remove.",
"dependencies": [],
"neededBy": [],
@@ -32420,7 +32420,7 @@
"removal": "Recommended"
},
"com.aura.oobe.softbank": {
- "list": "carrier",
+ "list": "Carrier",
"description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some SoftBank carrier phones\nSafe to remove.",
"dependencies": [],
"neededBy": [],
@@ -32428,7 +32428,7 @@
"removal": "Recommended"
},
"com.aura.oobe.rakuten": {
- "list": "carrier",
+ "list": "Carrier",
"description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Rakuten Mobile carrier phones\nSafe to remove.",
"dependencies": [],
"neededBy": [],
From e2c47a7a2d11d36c3290034613a3bb073c701f81 Mon Sep 17 00:00:00 2001
From: Jacob L <52282566+lawson85@users.noreply.github.com>
Date: Sun, 5 Apr 2026 15:20:23 +0100
Subject: [PATCH 061/111] Fix formatting in uad_lists.json
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 30e4221..c978052 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -7,7 +7,7 @@
"labels": [],
"removal": "Recommended"
},
- "com.cyanogenmod.filemanager": {
+ "com.cyanogenmod.filemanager": {
"list": "Oem",
"description": "Cyanogenmod file manager, safe to remove if you use another one.",
"dependencies": [],
From 6a44fda50aa1f5a4d01e104e1ccbf895cef04089 Mon Sep 17 00:00:00 2001
From: Efreak
Date: Fri, 3 Apr 2026 15:16:43 -0700
Subject: [PATCH 062/111] Removal advanced for com.samsung.storyservice
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 84e3a79..6219a69 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -6202,7 +6202,7 @@
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.samsung.svoice.sync": {
"list": "Oem",
From a5d095e14056858636e505dd8ea487de0fbc4644 Mon Sep 17 00:00:00 2001
From: Forero-0 <175985207+Forero-0@users.noreply.github.com>
Date: Thu, 9 Apr 2026 19:02:25 -0500
Subject: [PATCH 063/111] Update uad_lists.json
---
resources/assets/uad_lists.json | 34 ++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 76b7938..19d8c7f 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -42263,5 +42263,37 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
+ },
+ "com.samsung.android.hwresourceshare.storage": {
+ "list": "Oem",
+ "description": "Allows the storage on your phone, tablet, computer, and TV to connect so you can view and use files from one device on another without cables or downloads.\nThe service always runs in the background, and removing it has not caused any problems.\nhttps://r1.community.samsung.com/t5/tips-how-to/the-new-storage-share-feature/ba-p/36247598\nhttps://www.samsung.com/us/support/answer/ANS10004607/",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.wallpaper.live": {
+ "list": "Oem",
+ "description": "Samsung official app for dynamic and live wallpapers with generative AI capabilities.\nBecause it provides a wallpaper service, it runs in the background and starts automatically when the phone boots.\nIf you remove it while using a wallpaper created by it, that wallpaper will be removed as well.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.nfc": {
+ "list": "Oem",
+ "description": "It’s the main NFC module on Samsung devices.\nIt handles contactless payments, card emulation for Samsung Pay, NFC tag reading and writing, and features like Wireless Power Sharing, and it also manages certain S Pen functions that rely on NFC.\nI assume NFC breaks when disabled.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.samsung.android.wifi.largetcpbuffer.resources": {
+ "list": "Oem",
+ "description": "It only provides configuration data with no executable code and adjusts Wi‑Fi TCP buffer sizes to optimized values\nDepending entirely on com.android.wifi.resources\nIn theory it shouldn’t negatively affect Wi‑Fi if deleted, but this hasn’t been tested. It isn’t required for basic Wi‑Fi functionality; it mainly improves performance on fast networks, so removing it may make Wi‑Fi slightly slower.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ }
}
-}
From 49250576f3ba27fe0c65b7ae400fed236906e1bf Mon Sep 17 00:00:00 2001
From: Rudxain <76864299+Rudxain@users.noreply.github.com>
Date: Sat, 11 Apr 2026 00:30:12 -0400
Subject: [PATCH 064/111] build(logo): optional `image` dep
---
.github/workflows/build_artifacts.yml | 2 +-
Cargo.toml | 7 ++++---
src/gui/mod.rs | 8 +++++++-
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/build_artifacts.yml b/.github/workflows/build_artifacts.yml
index e050ba5..22ae978 100644
--- a/.github/workflows/build_artifacts.yml
+++ b/.github/workflows/build_artifacts.yml
@@ -42,7 +42,7 @@ jobs:
restore-keys: ${{ runner.OS }}-release-
if: matrix.os == 'ubuntu-22.04'
- name: Building
- run: cargo build --release --no-default-features --features wgpu,${{ matrix.update_feature }}
+ run: cargo build --release --no-default-features --features wgpu,${{ matrix.update_feature }},img
- name: Renaming binaries [Windows]
if: matrix.os == 'windows-2022'
run: mv target/release/uad-ng.exe uad-ng-${{ matrix.build_target }}.exe
diff --git a/Cargo.toml b/Cargo.toml
index 9cbe7a9..2a863e0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,10 +12,11 @@ categories = ["gui"]
edition = "2024"
[features]
-default = ["wgpu", "self-update"]
+default = ["wgpu", "self-update", "img"]
wgpu = [] # Iced/wgpu is default
self-update = ["flate2", "tar"]
no-self-update = []
+img = ["image", "iced/image"]
[dependencies]
dark-light = "2"
@@ -31,8 +32,8 @@ toml = "^0"
dirs = "^6"
ureq = { version = "3", features = ["json"] }
retry = "^2.0.0"
-iced = { version = "=0.14.0", features = ["advanced", "image"] }
-image = "0.25"
+iced = { version = "=0.14.0", features = ["advanced"] }
+image = { version = "0.25", optional = true }
rfd = "^0.17.1"
csv = "^1.3"
diff --git a/src/gui/mod.rs b/src/gui/mod.rs
index d7e2676..8eeb561 100644
--- a/src/gui/mod.rs
+++ b/src/gui/mod.rs
@@ -4,13 +4,17 @@ pub mod widgets;
use crate::core::adb;
use crate::core::sync::{Phone, get_devices_list, initial_load};
-use crate::core::theme::{OS_COLOR_SCHEME, Theme};
+#[cfg(feature = "img")]
+use crate::core::theme::OS_COLOR_SCHEME;
+use crate::core::theme::Theme;
use crate::core::uad_lists::UadListState;
use crate::core::update::{Release, SelfUpdateState, SelfUpdateStatus, get_latest_release};
use crate::core::utils::{FULL_NAME, NAME, string_to_theme};
use iced::font;
+#[cfg(feature = "img")]
use iced::window::icon;
+#[cfg(feature = "img")]
use image::ImageFormat;
use views::about::{About as AboutView, Message as AboutMessage};
use views::list::{List as AppsView, LoadingState as ListLoadingState, Message as AppsMessage};
@@ -399,6 +403,7 @@ impl UadGui {
impl UadGui {
pub fn start() -> iced::Result {
+ #[cfg(feature = "img")]
let logo: &[u8] = match *OS_COLOR_SCHEME {
// remember to keep `Unspecified` in sync with `src/core/theme`
dark_light::Mode::Dark | dark_light::Mode::Unspecified => {
@@ -425,6 +430,7 @@ impl UadGui {
},
resizable: true,
decorations: true,
+ #[cfg(feature = "img")]
icon: icon::from_file_data(logo, Some(ImageFormat::Png)).ok(),
..iced::window::Settings::default()
})
From 3e52ff6ba1297b51d31c4682836303e6c1c2d7a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Domeradzki?=
Date: Wed, 22 Apr 2026 01:20:53 +0200
Subject: [PATCH 065/111] Move com.xiaomi.cameramind under advanced
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index fb96a6d..548473e 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -425,11 +425,11 @@
},
"com.xiaomi.cameramind": {
"list": "Oem",
- "description": "The core of all AI features for Xiaomi's camera app. Won't impact other camera apps' AI features.\nSafe to delete if you don't need them or if you use another camera app.",
+ "description": "The core of all AI features for Xiaomi's camera app. Won't impact other camera apps' AI features.\nSafe to delete if you use another camera app, otherwise, removal may cause background connection issues.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"com.xiaomi.bluetooth.rro.device.config.overlay": {
"list": "Oem",
From acef695f8ecac352b143d9f2ef4249c58c541184 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Domeradzki?=
Date: Wed, 22 Apr 2026 01:38:39 +0200
Subject: [PATCH 066/111] Add camera as dependency to cameramind
---
resources/assets/uad_lists.json | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 548473e..518a6c9 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -427,7 +427,9 @@
"list": "Oem",
"description": "The core of all AI features for Xiaomi's camera app. Won't impact other camera apps' AI features.\nSafe to delete if you use another camera app, otherwise, removal may cause background connection issues.",
"dependencies": [],
- "neededBy": [],
+ "neededBy": [
+ "com.android.camera"
+ ],
"labels": [],
"removal": "Advanced"
},
From 01a37e2d33b47b7b93fa8a47abfb9aa1bae40abf Mon Sep 17 00:00:00 2001
From: Asahi <217256082+asahi-xd@users.noreply.github.com>
Date: Sat, 25 Apr 2026 00:39:14 +0530
Subject: [PATCH 067/111] fixed typo and added personal observations
I have fixed a few typos, and added my personal experiences with this program. I was feeling experimental and tried to use its 'battery saving' features, and ended up completely regretting it.
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 518a6c9..c338ad5 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -31481,7 +31481,7 @@
},
"com.transsion.batterylab": {
"list": "Oem",
- "description": "Supposed to improve battery life but logs especially lots of usage info and bind it to your unique android advertiser id...The app tries to send data to a server. The POST request URL and content is obfuscated and I don't have the time to dig deeper. According to a user, no battery impact after months of usage after uninstalling it.\n\nPithus analysis: https://beta.pithus.org/report/7ef2b186a74102828346f23b094ab2aaaad2c57806c7c18e7a23a494f3cc982c",
+ "description": "Supposed to improve battery life but instead it does the opposite. It completely destroys your phone's ability to enter 'deep sleep'. This essentially means rapid battery drain, and your phone will heat up. 7-8% screen-off battery use when using it, vs 0.7-1% usage without it. It also logs lots of usage info and binds it to your unique android advertiser id. The app tries to send data to a server. The POST request URL and content is obfuscated and I don't have the time to dig deeper.\n\nPithus analysis: https://beta.pithus.org/report/7ef2b186a74102828346f23b094ab2aaaad2c57806c7c18e7a23a494f3cc982c",
"dependencies": [],
"neededBy": [],
"labels": [],
From 0a76d615ba7dd0e40219ca417e663385b5c43295 Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Wed, 29 Apr 2026 20:49:16 +0000
Subject: [PATCH 068/111] docs: update personal safety app
change from recommended to advanced, plus a bit of info about what this app adds without a google account
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index a5e11ff..52b0526 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -33085,11 +33085,11 @@
},
"com.google.android.apps.safetyhub": {
"list": "Google",
- "description": "Personal Safety (https://play.google.com/store/apps/details?id=com.google.android.apps.safetyhub)\nPersonal Safety is a Pixel app that helps you prepare and react in an emergency by quickly calling emergency services (e.g if your phone detects that you've been in a car crash, it can call for help automatically)\nMost features require a Google account to work unfortunately...\n\nThis app has obviously a lot of dangerous permissions due to its operation.\n\nPithus analysis: https://beta.pithus.org/report/e207f7d0f59d9df268154b90fc10cd861d0483465e30bbac8f68a7b12340c67f",
+ "description": "Personal Safety (https://play.google.com/store/apps/details?id=com.google.android.apps.safetyhub)\nPersonal Safety is a Pixel app that helps you prepare and react in an emergency by quickly calling emergency services (e.g if your phone detects that you've been in a car crash, it can call for help automatically, but only with a google account)\nMost features require a Google account to work except for medical information and emergency contacts. Emergency SOS (ie. pressing the power button 5 times to call emergency services) still works without this app.\n\nThis app has obviously a lot of dangerous permissions due to its operation.\n\nPithus analysis: https://beta.pithus.org/report/e207f7d0f59d9df268154b90fc10cd861d0483465e30bbac8f68a7b12340c67f",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Recommended"
+ "removal": "Advanced"
},
"androidhwext": {
"list": "Oem",
From e7a96d7e0f8da048c24d5974cbf9804592dbf79c Mon Sep 17 00:00:00 2001
From: nyxSeal <155689615+nyxSeal@users.noreply.github.com>
Date: Wed, 29 Apr 2026 22:22:57 +0000
Subject: [PATCH 069/111] docs: update conflicted package description
added both the part where it will drain your battery and where it contains a lot of useful features
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 1458489..dbcd2fd 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -31481,11 +31481,11 @@
},
"com.transsion.batterylab": {
"list": "Oem",
- "description": "Supposed to improve battery life but instead it does the opposite. It completely destroys your phone's ability to enter 'deep sleep'. This essentially means rapid battery drain, and your phone will heat up. 7-8% screen-off battery use when using it, vs 0.7-1% usage without it. It also logs lots of usage info and binds it to your unique android advertiser id. The app tries to send data to a server. The POST request URL and content is obfuscated and I don't have the time to dig deeper.\n\nPithus analysis: https://beta.pithus.org/report/7ef2b186a74102828346f23b094ab2aaaad2c57806c7c18e7a23a494f3cc982c",
+ "description": "Will either kill your battery life or is the \"Battery & Power Saving\" section in the Settings app with many useful battery features, depending on device. \n\nPithus analysis: https://beta.pithus.org/report/7ef2b186a74102828346f23b094ab2aaaad2c57806c7c18e7a23a494f3cc982c",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Expert"
+ "removal": "Advanced"
},
"com.transsion.stasticalsales": {
"list": "Oem",
From 1d93422e6fa48337bf2592a05384f1ba77e89407 Mon Sep 17 00:00:00 2001
From: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
Date: Thu, 30 Apr 2026 02:08:56 +0200
Subject: [PATCH 070/111] build: fix error and warnings (#1384)
* build: fix error and warnings
Address clippy suggestions and clean up pattern matching:
- Replace manual sort_by with sort_by_key(|a| a.name.to_lowercase()) for user_package in fetch_packages.
- Add #[allow(clippy::unused_self)] to UadGui::title and UadGui::subscription to silence unused_self warnings.
- Simplify the keyboard event match by destructuring the Character variant directly for clearer pattern matching.
- Add #[allow(clippy::too_many_lines)] to nav_menu to silence the long-function lint.
These are lint and readability-focused changes with no intended behavioral change.
* chore(clippy): add reason
* build(ci): fix formatting
---
src/core/utils.rs | 2 +-
src/gui/mod.rs | 35 +++++++++++++++++-------------
src/gui/widgets/navigation_menu.rs | 1 +
3 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/src/core/utils.rs b/src/core/utils.rs
index eb0c7fc..e6a3fe1 100644
--- a/src/core/utils.rs
+++ b/src/core/utils.rs
@@ -122,7 +122,7 @@ pub fn fetch_packages(
PackageRow::new(p_name, state, description, uad_list, removal, false, false);
user_package.push(package_row);
}
- user_package.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
+ user_package.sort_by_key(|a| a.name.to_lowercase());
user_package
}
diff --git a/src/gui/mod.rs b/src/gui/mod.rs
index 8eeb561..883b1f0 100644
--- a/src/gui/mod.rs
+++ b/src/gui/mod.rs
@@ -81,6 +81,10 @@ pub enum Message {
}
impl UadGui {
+ #[allow(
+ clippy::unused_self,
+ reason = "required by iced's Application trait interface"
+ )]
fn title(&self) -> String {
FULL_NAME.to_string()
}
@@ -102,23 +106,24 @@ impl UadGui {
)
}
+ #[allow(
+ clippy::unused_self,
+ reason = "required by iced's Application trait interface"
+ )]
fn subscription(&self) -> Subscription {
event::listen_with(|event, _status, _env| match event {
- iced::Event::Keyboard(keyboard::Event::KeyPressed { key, modifiers, .. })
- if modifiers.control() && modifiers.shift() =>
- {
- match key {
- keyboard::Key::Character(c) => match c.as_str() {
- "r" => Some(Message::RebootButtonPressed),
- "5" => Some(Message::RefreshButtonPressed),
- "a" => Some(Message::AppsPress),
- "i" => Some(Message::AboutPressed),
- "s" => Some(Message::SettingsPressed),
- _ => None,
- },
- _ => None,
- }
- }
+ iced::Event::Keyboard(keyboard::Event::KeyPressed {
+ key: keyboard::Key::Character(c),
+ modifiers,
+ ..
+ }) if modifiers.control() && modifiers.shift() => match c.as_str() {
+ "r" => Some(Message::RebootButtonPressed),
+ "5" => Some(Message::RefreshButtonPressed),
+ "a" => Some(Message::AppsPress),
+ "i" => Some(Message::AboutPressed),
+ "s" => Some(Message::SettingsPressed),
+ _ => None,
+ },
_ => None,
})
}
diff --git a/src/gui/widgets/navigation_menu.rs b/src/gui/widgets/navigation_menu.rs
index 5d9ff50..f0f9dd9 100644
--- a/src/gui/widgets/navigation_menu.rs
+++ b/src/gui/widgets/navigation_menu.rs
@@ -13,6 +13,7 @@ pub const ICONS: Font = Font {
..Font::DEFAULT
};
+#[allow(clippy::too_many_lines)]
pub fn nav_menu<'a>(
device_list: &'a [Phone],
selected_device: Option,
From d6a0d0733e9f5b6d81386c7fd21aa647121de47a Mon Sep 17 00:00:00 2001
From: Raihan <98381055+Raihann22@users.noreply.github.com>
Date: Thu, 30 Apr 2026 15:53:37 +0800
Subject: [PATCH 071/111] Update uad_lists.json
Updated the description for the com.android.providers.contacts to include additional information about Bluetooth malfunction on POCO Pad M1.
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index c338ad5..6ceb3b3 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -8962,7 +8962,7 @@
},
"com.android.providers.contacts": {
"list": "Aosp",
- "description": "Contacts Storage\nProvider for contact data.\nContent providers encapsulate data, providing centralized management of data shared between apps.\nhttps://developer.android.com/guide/topics/providers/content-providers.html\nBreaks contact functionality if disabled. Not recommended to disable if you plan to use your device as a phone.",
+ "description": "Contacts Storage\nProvider for contact data.\nContent providers encapsulate data, providing centralized management of data shared between apps.\nhttps://developer.android.com/guide/topics/providers/content-providers.html\nBreaks contact functionality if disabled. Not recommended to disable if you plan to use your device as a phone.\nOn POCO Pad M1, disabling this will cause Bluetooth to malfunction, turning on and off continuously.",
"dependencies": [],
"neededBy": [],
"labels": [],
From ede2b02501efcdbb62efe17157deb0a3fe9194c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Domeradzki?=
Date: Fri, 1 May 2026 00:09:12 +0200
Subject: [PATCH 072/111] pkg(com.motorola.securevault) Move under advanced
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index c338ad5..977c68c 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -20418,8 +20418,8 @@
"labels": []
},
"com.motorola.securevault": {
- "description": "Secure Folder\nUnnecessary tools to keep device secure.\nhttps://play.google.com/store/apps/details?id=com.motorola.securevault",
- "removal": "Recommended",
+ "description": "Secure Folder\nNormally unnecessary tools to keep device secure, however, removal on motorola devices may cause background issues.\nhttps://play.google.com/store/apps/details?id=com.motorola.securevault",
+ "removal": "Advanced",
"list": "Oem",
"dependencies": [],
"neededBy": [],
From 20fcc6e7b6c65fe1e3dbab15b52634771f114fe1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Domeradzki?=
Date: Fri, 1 May 2026 14:09:49 +0200
Subject: [PATCH 073/111] pkg(com.motorola.securevault): Improve description
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 977c68c..6668469 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -20418,7 +20418,7 @@
"labels": []
},
"com.motorola.securevault": {
- "description": "Secure Folder\nNormally unnecessary tools to keep device secure, however, removal on motorola devices may cause background issues.\nhttps://play.google.com/store/apps/details?id=com.motorola.securevault",
+ "description": "Secure Folder\nNormally unnecessary tools to keep device secure, however, removal may cause background issues - it should be safe to disable instead.\nhttps://play.google.com/store/apps/details?id=com.motorola.securevault",
"removal": "Advanced",
"list": "Oem",
"dependencies": [],
From 1731d39a2dd83bd4b90c499b9dd401a1ceda0a02 Mon Sep 17 00:00:00 2001
From: Mickmick21
Date: Fri, 13 Mar 2026 20:18:36 +0100
Subject: [PATCH 074/111] Update uad_lists.json
Update uad_lists.json
Final ?
Update uad_lists.json
Update uad_lists.json0
Update uad_lists.json
Final commit.
Perfect example of why to check your commits.
pkg(jp.co.omronsoft.iwnnime.ml): change to unsafe
Don't know how to name this.
Try to resolve conflicts
I hate conflicts so much
---
resources/assets/uad_lists.json | 692 +++++++++++++++++++++++++++++++-
1 file changed, 691 insertions(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 82faa2e..a5d517f 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -32468,7 +32468,7 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
- },
+ },
"com.aura.oobe.ml": {
"list": "Oem",
"description": "Aura from Unity\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Motorola\nSafe to remove.",
@@ -42330,6 +42330,696 @@
"labels": [],
"removal": "Recommended"
},
+ "com.hihonor.android.launcher": {
+ "list": "Oem",
+ "description": "Honor launcher app.\nIt's basically the home screen, the way icons apps are organized and displayed.\nDON'T REMOVE THIS IF YOU DIDN'T INSTALL ANOTHER LAUNCHER !\nYou will need this package for the recent apps feature to work, and will completely break the gestural navigation bar.\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.calendar": {
+ "list": "Oem",
+ "description": "Honor's calendar app.\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.photos": {
+ "list": "Oem",
+ "description": "Honor's photos app.\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.lens": {
+ "list": "Oem",
+ "description": "App kinda like Google Lens, used for scanning QR Codes and more.\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.appmarket": {
+ "list": "Oem",
+ "description": "HONOR's App store.\nSafe to remove.\nNOTE: Installed apps via this store will no longer auto-update after removal.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.phoneservice": {
+ "list": "Oem",
+ "description": "My Honor.\nhttps://play.google.com/store/apps/details?id=com.hihonor.phoneservice&hl=fr",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.notepad": {
+ "list": "Oem",
+ "description": "Honor's notepad app.\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.filemanager": {
+ "list": "Oem",
+ "description": "Honor's file manager.\nIt is not the system one so it's safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.calculator": {
+ "list": "Oem",
+ "description": "Honor's calculator app.\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.contacts": {
+ "list": "Oem",
+ "description": "Honor's contacts app.\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.videoeditor": {
+ "list": "Oem",
+ "description": "Honor's video editing app.\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.magazine": {
+ "list": "Oem",
+ "description": "Magic Pictorial/Magazine unlock.\nSafe to remove if you're not using it.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.android.thememanager": {
+ "list": "Oem",
+ "description": "Honor's Theme manager.\nDisabling it will prevent you from changing themes.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.search": {
+ "list": "Oem",
+ "description": "HONOR Search.\nhttps://www.honor.com/sa-en/support/content/en-us15829481/\nSafe to remove if you're not using it.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.collectcenter": {
+ "list": "Oem",
+ "description": "HONOR Favourites space.\nSafe to remove if you're not using it.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.soundrecorder": {
+ "list": "Oem",
+ "description": "Honor's audio recording app.\nSafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.bluetooth": {
+ "list": "Oem",
+ "description": "Contact import via blueooth on Honor devices, probably safe to remove if you don't plan using this function.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.ouc": {
+ "list": "Oem",
+ "description": "OTA Updates for Honor devices. Probably unsafe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.mmitest": {
+ "list": "Oem",
+ "description": "MMITest\nHidden hardware tests. Safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.android.fmradio": {
+ "list": "Oem",
+ "description": "Honor's stock radio player. Remove if FM isn't relevant for you.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.keychain": {
+ "list": "Oem",
+ "description": "Face recognition and fingerprint authentication. Probably a bad idea to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Unsafe"
+ },
+ "com.hihonor.compass": {
+ "list": "Oem",
+ "description": "Honor's compass app. Safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.imedia.sws": {
+ "list": "Oem",
+ "description": "Audio 3D effects found in the settings. Safe to remove if you don't use these settings.\nCauses an audio glitch after the first reboot following the uninstallation or disabling of this package.\nWhen you start or resume playing any audio content in any media application, the sound volume initially sets to maximum for half a second, then normalizes.\nAffects only external audio devices with any connection type.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.hnasm": {
+ "list": "Oem",
+ "description": "FIDO UAF Authenticator-Specific Module.\nSee 'com.hihonor.fido.uafclient' for FIDO explaination.\nThe UAF Authenticator-Specific Module (ASM) is a software interface on top of UAF authenticators which gives a standardized way for FIDO UAF clients to detect and access the functionality of UAF authenticators and hides internal communication complexity from FIDO UAF Client.\nhttps://fidoalliance.org/specs/fido-uaf-v1.0-ps-20141208/fido-uaf-asm-api-v1.0-ps-20141208.html",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.fido.uafclient": {
+ "list": "Oem",
+ "description": "UAF client for FIDO.\nFido is a set of open technical specifications for mechanisms of authenticating users to online services that do not depend on passwords.\nhttps://fidoalliance.org/specs/u2f-specs-1.0-bt-nfc-id-amendment/fido-glossary.html\nhttps://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-overview-v2.0-rd-20170927.html\nThe UAF protocol is designed to enable online services to offer passwordless and multi-factor security by allowing users to register their device to the online service and using a local authentication mechanism such as iris or fingerprint recognition.\nhttps://developers.google.com/identity/fido/android/native-apps\nSafe to remove if you don't use password-less authentication to access online services.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.dsdscardmanager": {
+ "list": "Oem",
+ "description": "Dual card management\nIt's sim card management in Honor settings.\nAfter removing, sim card management in settings will not work.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Unsafe"
+ },
+ "com.hihonor.gameassistant": {
+ "list": "Oem",
+ "description": "Honor Game Suite (HiGame).\nMobile game app store.\nhttps://club.hihonor.com/in/topic/16341/detail.htm\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.game.kitserver": {
+ "list": "Oem",
+ "description": "Probably safe to remove if you don't play games.\nHas window show, keybind set and more things.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.powergenie": {
+ "list": "Oem",
+ "description": "Task killer app in EMUI 9+ (Android 9+).\nTask killer apps tend to do more harm than help as they clear cached RAM for no good reason, removing the battery and time savings involved in caching. In addition to the obvious issues with background functionality like notifications.\nFrom issue#104.\nSystem will start lagging a little bit (you will notice it while scrolling and on some animations, for example scrolling installed apps), battery consumption will become slightly higher and battery stats will disappear soon. At the same time, logcat will be full of errors like: PowerKit: PG Server is not found. calling pid xxxx.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.hiviewtunnel": {
+ "list": "Oem",
+ "description": "This displays details/attributes of pictures in the gallery (ISO, exposure time, etc.).\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.hiview": {
+ "list": "Oem",
+ "description": "hiview\nRemoving this doesn't remove access to the picture attributes, so what does it actually do?\nIt's the same as (com.hihonor.hiviewtunnel), which is useless.\nIt has 19 permissions, Crash App Dialog, logs. So do not trust these apps.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.assetsync": {
+ "list": "Oem",
+ "description": "HnAssetSync\nNeeded for HiCloud, Cloud syncing.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.assetsyncservice": {
+ "list": "Oem",
+ "description": "It's for 'com.hihonor.securityserver' for start this service app.\nNeeded for HiCloud sync security.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.securityserver": {
+ "list": "Oem",
+ "description": "HnSecurityServer\nNot needed app without code and useless assets to spying apps.\nNeeded for face unlock, black screen will be shown if you remove this package (?). Doesn't apply to all devices",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.iaware": {
+ "list": "Oem",
+ "description": "App Prioritizer. Prioritizes apps to avoid slowdown\nUp to you but there is apparently no noticeable difference when deleted?\nSystem will start lagging a little bit (you will notice it while scrolling and on some animations, for example scrolling installed apps), battery consumption will become slightly higher and battery stats will disappear soon. At the same time, logcat will be full of errors like: PowerKit: PG Server is not found. calling pid xxxx.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.autoinstallapkfrommcc": {
+ "list": "Oem",
+ "description": "Auto Install apk from mcc\nAuto Install apk from mcc? it's only information and logs.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.omacp": {
+ "list": "Oem",
+ "description": "Provisioning message\nUsed for provisioning APN settings to devices via SMS. I think you shouldnt touch it if you want sms messages.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.motionservice": {
+ "list": "Oem",
+ "description": "Gesture Service\nNot very useful gestures available in settings.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.hndockbar": {
+ "list": "Oem",
+ "description": "Honor Multi-Window dock\nProbably fine to remove if you're not using Honor Multi-Window features.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.pcassistant": {
+ "list": "Oem",
+ "description": "HiSuite service. Used by HiSuite PC software.\nHiSuite enables you to backup your data and restore them from/to your phone.\nhttps://consumer.huawei.com/en/support/hisuite/\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.wifieapsimplmn": {
+ "list": "Oem",
+ "description": "PredefinedEapSim\nNeeded for WiFi to work properly? WiFi may not work (?)",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.android.mirrorshare": {
+ "list": "Oem",
+ "description": "MirrorShare feature (Miracast rebranded by Honor)\nUsed to mirror screen of you smartphone on a TV.\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.android.projectmenu": {
+ "list": "Oem",
+ "description": "ProjectMenu\nHidden settings not available for users. ProjectMenu interface: phone *#*#2846579#*#*\nhttps://www.99mediasector.com/open-project-menu-huawei-device-huawei-code/",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.remotepassword": {
+ "list": "Oem",
+ "description": "RemotePassword\nremotepassword: errors, invalid, null, errors generally\nalso subscribe info, device info. Better remove that.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.koBackup": {
+ "list": "Oem",
+ "description": "As of writing this, Honor phones cannot be rooted.\nThis Backup application is probably able to backup more than any other 3rd party backup app.\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.iconnect": {
+ "list": "Oem",
+ "description": "iConnect\nHidden menu 'install PCAssistant' when connected to PC? I have never seen it. Safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.linktowindowsservice": {
+ "list": "Oem",
+ "description": "Windows Phone Link Service. Safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.systemserver": {
+ "list": "Oem",
+ "description": "Honor System Services\nIt depends on (com.hihonor.systemmanager).\nNeeded for navigation with a fingerprint reader that is on a Huawei Mate 10, but fingerprint unlock will still work if you remove it.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.android.internal.app": {
+ "list": "Oem",
+ "description": "Component of Honor sharing\nMay break the sharing function in several applications (in particular, apps will crash).",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.synergy": {
+ "list": "Oem",
+ "description": "Honor Cloud & Network Synergy.\nSeems to be related to B2B (Business To Business) cloud stuff.\nhttps://www.huawei.com/en/press-events/news/2016/10/Cloud-Network-Synergy-Whitepaper\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.contacts.sync": {
+ "list": "Oem",
+ "description": "Huawei Contacts sync\nMy guess (can't have the apk on hand) is this enables you to synchronise your contacts with your Huawei account.\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.deviceauth": {
+ "list": "Oem",
+ "description": "TrustedDeviceAuth\nI guess it's for authentication keys",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.android.FloatTasks": {
+ "list": "Oem",
+ "description": "Floating/Navigation dock (also called NaviDot).\nhttps://consumer.huawei.com/en/support/how-to/detail-troubleshooting/en-us00310067/",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.android.wfdft": {
+ "list": "Oem",
+ "description": "Wi-Fi Direct feature.\nNote: Wifi direct enables devices to establish a direct Wi-Fi connection (without a router) over which the two can send and receive files.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.browserhomepage": {
+ "list": "Oem",
+ "description": "Honor Browser component.\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.searchservice": {
+ "list": "Oem",
+ "description": "Fusion Search Service\nNeeded for searching? \nalso found trackers components that connects to Honor servers unnecessarily.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.assistant": {
+ "list": "Oem",
+ "description": "AI Suggestions\nDidn't find any issues when removing it.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.hnstartupguide": {
+ "list": "Oem",
+ "description": "A one-time setup app that is no longer needed",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.camera": {
+ "list": "Oem",
+ "description": "Safe to remove, but not recommended, as other camera apps are not much better than this one.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.HnMultiScreenShot": {
+ "list": "Oem",
+ "description": "Scrolling screenshot feature\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.smartshot": {
+ "list": "Oem",
+ "description": "Smart screenshots\nNeeded for screenshots.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.screenrecorder": {
+ "list": "Oem",
+ "description": "Stock screen recorder\nUseful only in pre-Android Pie for having system audio recording without root.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.permissioncontroller.overlay": {
+ "list": "Oem",
+ "description": "Found help app permissions - only link to Google site in code, overlay to permission things like buttons, dialogs, etc.\nBut it's not needed?",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.ddmp": {
+ "list": "Oem",
+ "description": "DDMP\nHas a lot frameworks.\nUninstalling breaks calling app even if you disable.\nIt does not cause bootloop but removing is highly not recommended.\nNot only breaks the dialer app, but causes lag in whole system too.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Unsafe"
+ },
+ "com.hihonor.detectrepair": {
+ "list": "Oem",
+ "description": "Honor Smart diagnosis (discontinued?)\nUseless features and run in background.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.android.hnaps": {
+ "list": "Oem",
+ "description": "HnAps\nManages Intelligent Resolution and changing screen resolution in settings.\nIntelligent Resolution will be not available and changing screen resolution in settings.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Unsafe"
+ },
+ "com.hihonor.behaviorauth": {
+ "list": "Oem",
+ "description": "BehaviorAuth\nIt seems to be related to verifying the authenticity of user behavior and enhancing password security. User can disable it so it's safe to remove.\nhttps://www.android-hilfe.de/forum/huawei-p30-p30-pro-p30-lite.3510/was-ist-die-behaviorauth-app-fuer-das-p30.1008750.html",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.android.chr": {
+ "list": "Oem",
+ "description": "HnChrService\nHonor Call History Record.\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.coauthservice": {
+ "list": "Oem",
+ "description": "HnCoAuthService\nApplock, lockscreen password, face recognition things, fingerprint, not sure if it's worth removing it.\nNeeded for manual apk installation.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.nearby": {
+ "list": "Oem",
+ "description": "HnNearby\nNeeded for Honor Share features. (com.hihonor.android.instantshare)\nHonor Share features may not work after remove.\nNeeded to show a preview of recently opened apps in task manager. I agree, makes no sense, but that's what it is.",
+ "dependencies": [
+ "com.hihonor.android.instantshare"
+ ],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.hnpanpayservice": {
+ "list": "Oem",
+ "description": "Payment related service. Safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.securitypluginbase": {
+ "list": "Oem",
+ "description": "HnSecurityPluginBase\nAntivirus Service supports bad antiviruses, HnLog, not needed",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.android.hnupgradeguide": {
+ "list": "Oem",
+ "description": "hnupgradeguide\nit's guide menu at first start Honor App Market.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.android.instantshare": {
+ "list": "Oem",
+ "description": "Honor Share features.\nFile transfer tool between Honor mobiles, using Bluetooth connection and WiFi Direct technology.\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.numberidentity": {
+ "list": "Oem",
+ "description": "Designed to block unwanted calls.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.deskclock": {
+ "list": "Oem",
+ "description": "Honor Clock App.\n",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.systemmanager": {
+ "list": "Oem",
+ "description": "System Manager\nHonor's stock phone cleaner. Consumes a lot of battery power for useless 'security' checks.\n NOTE: breaks the functionality of closing and cleaning background apps.\nThis is more than a phone cleaner, you will lose a lot of settings like battery and notifications management if you remove this.\n WARNING: apparently needed for managing app permissions, not safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Unsafe"
+ },
+ "com.hihonor.airlink": {
+ "list": "Oem",
+ "description": "Air link service, it's probably needed for Wireless Projection.\nNo activities, only more debugging stuff, location things, logs",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "androidhnext": {
+ "list": "Oem",
+ "description": "EMUI Graphical User Interface:\nhttps://fixyourandroid.com/about/androidhwext\nThe framework responsible for the themes (even the standard one) of EMUI to launch. Also, it's the core for the Themes app. REMOVING IT CAUSES A BOOTLOOP!",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Unsafe"
+ },
+ "com.hihonor.trustcircle": {
+ "list": "Oem",
+ "description": "Device authentication service\nThe app's usage is unknown, but it can be removed if apps such as com.hihonor.id, com.hihonor.appmarket are also removed. This is what I found while exploring the APK: Huawei Mobile Services?, managing installation and updates of AppGallery.\nHuawei HWID account may be inaccessible without this app.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.id": {
+ "list": "Oem",
+ "description": "Honor Mobile Services\nHonor’s alternative to Google Play Services. Needed to access advanced Honor features.\nA Honor ID is required to access services, like Themes. This may break an app like InPost Mobile, see:\nhttps://github.com/0x192/universal-android-debloater/issues/477\nSee more about Honor Mobile Services: https://www.xda-developers.com/huawei-hms-core-android-alternative-google-play-services-gms/",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.printservice": {
+ "list": "Oem",
+ "description": "Print service",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.hihonor.lbs": {
+ "list": "Oem",
+ "description": "Location Based Services\nLocation-based services (LBS) are applications or services that utilize location data from a user's device, such as a smartphone or GPS, to provide relevant information, directions, or recommendations tailored to their specific location. These services rely on a combination of technologies, including Global Positioning System (GPS), Wi-Fi, cellular networks, and sensors, to determine a user's position accurately.\nNOTE: Can cause bootloops on some devices.\nThe primary goal of LBS is to offer personalized and context-aware experiences based on a user's geographical location. This can include services like:\n1. Navigation and Mapping, 2. Location-Based Advertising, 3. Social Networking, 4. Emergency Services, 5. IoT Asset Tracking\nhttps://forum.huawei.com/enterprise/en/location-based-services/thread/703168442200375296-667213855346012160",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.aipluginengine": {
+ "list": "Oem",
+ "description": "Assistant Basic Services\nSeems to be a dependency of Honor Lens. Safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.hihonor.systemappsupdater": {
+ "list": "Oem",
+ "description": "System apps update\nUnless you want to manually update system apps, do not remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
+ },
+ "com.hihonor.awareness": {
+ "list": "Oem",
+ "description": "Dependency of YOYO Assistant and Honor AI ? Didn't notice anything when removed.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
"com.samsung.android.hwresourceshare.storage": {
"list": "Oem",
"description": "Allows the storage on your phone, tablet, computer, and TV to connect so you can view and use files from one device on another without cables or downloads.\nThe service always runs in the background, and removing it has not caused any problems.\nhttps://r1.community.samsung.com/t5/tips-how-to/the-new-storage-share-feature/ba-p/36247598\nhttps://www.samsung.com/us/support/answer/ANS10004607/",
From c16ee8b379fe6486a852419ee31e03dc943da06f Mon Sep 17 00:00:00 2001
From: Evelyn Torres
Date: Fri, 8 May 2026 13:17:26 -0230
Subject: [PATCH 075/111] pkg(insulet): add packes from omnipod dash pdm
---
resources/assets/uad_lists.json | 40 +++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index a5d517f..8c44d22 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -43051,5 +43051,45 @@
"neededBy": [],
"labels": [],
"removal": "Expert"
+ },
+ "com.android.onetimeinitializer": {
+ "list": "Aosp",
+ "description": "Needed for first time setup. Due to how UAD works, the package will be restored on factory reset, so it's safe to remove. No purpose to keep it after setup.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.insulet.myblue.pdm": {
+ "list": "Oem",
+ "description": "App to control OmniPod insulin pumps. Preinstalled on the OmniPod DASH and OmniPod 5 PDMs. If you're seeing this package you're probably on a modded PDM, so you almost certainly know what this is and it's absolutely unsafe to remove if you're actively using OmniPod.\nhttps://play.google.com/store/apps/details?id=com.insulet.myblue.pdm",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Unsafe"
+ },
+ "com.insulet.myblue.pdmsystem": {
+ "list": "Oem",
+ "description": "Additional package needed to control pods on the OmniPod DASH PDM. Doesn't seem to be present on OmniPod 5. See com.insulet.myblue.pdm\n tl;dr: needed to control your insulin pump, absolutely do not remove this.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Unsafe"
+ },
+ "com.nbbsw.compatiblemark": {
+ "list": "Oem",
+ "description": "Not exactly sure what this is. Trying to launch mainActivity, you get a Chinese error message, but you can see a java error saying it's trying to connect to s2.sv.wxjyun.cn, which is a non-existent URL. No issues when removing this so it's safe to remove.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "org.simalliance.openmobileapi.eseterminal": {
+ "list": "Aosp",
+ "description": "Needed for NFC payments (e.g. Google Wallet) on older Android versions.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
}
}
From 01dd13117c573f2eea16bf429ba0a042db5fb0fb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 9 May 2026 04:08:01 -0400
Subject: [PATCH 076/111] chore(deps): bump rustls-webpki from 0.103.10 to
0.103.13 (#1383)
Bumps [rustls-webpki](https://github.com/rustls/webpki) from 0.103.10 to 0.103.13.
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](https://github.com/rustls/webpki/compare/v/0.103.10...v/0.103.13)
---
updated-dependencies:
- dependency-name: rustls-webpki
dependency-version: 0.103.13
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index a8b93ce..da30636 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3597,9 +3597,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
-version = "0.103.10"
+version = "0.103.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
+checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
dependencies = [
"ring",
"rustls-pki-types",
From e0e87e39eaf75b137cf649aedfb5badc869c1474 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 9 May 2026 04:30:51 -0400
Subject: [PATCH 077/111] chore(deps): bump rand from 0.8.5 to 0.8.6 (#1387)
Bumps [rand](https://github.com/rust-random/rand) from 0.8.5 to 0.8.6.
- [Release notes](https://github.com/rust-random/rand/releases)
- [Changelog](https://github.com/rust-random/rand/blob/0.8.6/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand/compare/0.8.5...0.8.6)
---
updated-dependencies:
- dependency-name: rand
dependency-version: 0.8.6
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anonymoussaurus <50231698+AnonymousWP@users.noreply.github.com>
---
Cargo.lock | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index da30636..bf050ff 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -170,7 +170,7 @@ dependencies = [
"enumflags2",
"futures-channel",
"futures-util",
- "rand 0.8.5",
+ "rand 0.8.6",
"serde",
"serde_repr",
"url",
@@ -3262,9 +3262,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "rand"
-version = "0.8.5"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
dependencies = [
"libc",
"rand_chacha 0.3.1",
From 9108e3d4b4ec84635f0b694f79b658d571ed3301 Mon Sep 17 00:00:00 2001
From: "bobbie.w" <172299513+bobbynona@users.noreply.github.com>
Date: Tue, 10 Mar 2026 10:20:33 -0700
Subject: [PATCH 078/111] fix(gui): explicitly request Adwaita Sans font on
Linux to prevent Bounding Box clipping from monospace fallback
---
src/gui/mod.rs | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/gui/mod.rs b/src/gui/mod.rs
index 883b1f0..c32f844 100644
--- a/src/gui/mod.rs
+++ b/src/gui/mod.rs
@@ -426,6 +426,11 @@ impl UadGui {
.settings(Settings {
id: Some(String::from(NAME)),
default_text_size: iced::Pixels(16.0),
+ #[cfg(target_os = "linux")]
+ default_font: iced::Font {
+ family: iced::font::Family::Name("Adwaita Sans"),
+ ..Default::default()
+ },
..Settings::default()
})
.window(Window {
From 51a929009c190968fbc1049a219a3822d12bb490 Mon Sep 17 00:00:00 2001
From: Rudxain <76864299+Rudxain@users.noreply.github.com>
Date: Sat, 9 May 2026 04:54:02 -0400
Subject: [PATCH 079/111] docs(gui): explain Adwaita hack
---
src/gui/mod.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/gui/mod.rs b/src/gui/mod.rs
index c32f844..c88fd08 100644
--- a/src/gui/mod.rs
+++ b/src/gui/mod.rs
@@ -426,6 +426,8 @@ impl UadGui {
.settings(Settings {
id: Some(String::from(NAME)),
default_text_size: iced::Pixels(16.0),
+ // HACK: avoid glyph clipping on some systems. Details:
+ // https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/pull/1337
#[cfg(target_os = "linux")]
default_font: iced::Font {
family: iced::font::Family::Name("Adwaita Sans"),
From 8b0e15eb9a945fe1ac765bc9b5b8d6065cd9ed4c Mon Sep 17 00:00:00 2001
From: Rudxain <76864299+Rudxain@users.noreply.github.com>
Date: Sat, 9 May 2026 05:17:41 -0400
Subject: [PATCH 080/111] pkg: update
com.google.android.wifi.resources.overlay.common
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index a5d517f..5093d73 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -313,7 +313,7 @@
},
"com.google.android.wifi.resources.overlay.common": {
"list": "Aosp",
- "description": "An overlay-google addition for com.android.wifi.resoruces, presumably google bloat. No issues with Wi-Fi found after removal.\nThere's no such package as com.google.android.wifi.resources, but only com.android.wifi.resources, so it's likely a part of a google addition for Wi-Fi services, so likely bloat. Safe to delete.",
+ "description": "An overlay-google addition for `com.android.wifi.resources`, presumably Google bloat.\nA user reported some issues with Hotspot",
"dependencies": [],
"neededBy": [],
"labels": [],
From fb0dfa8d1448b20666e77c0b2dc960419af0e00f Mon Sep 17 00:00:00 2001
From: Evelyn
Date: Tue, 12 May 2026 17:17:10 -0230
Subject: [PATCH 081/111] pkg(aosp): Update description for onetimeinitalizer
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 8c44d22..d82f40f 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -43054,7 +43054,7 @@
},
"com.android.onetimeinitializer": {
"list": "Aosp",
- "description": "Needed for first time setup. Due to how UAD works, the package will be restored on factory reset, so it's safe to remove. No purpose to keep it after setup.",
+ "description": "Needed for first time setup. Due to how UAD works, the package will be restored on factory reset, so it's safe to disable. No purpose to keep it after setup. Better to disable; not uninstall",
"dependencies": [],
"neededBy": [],
"labels": [],
From 6e02459ee241eeabe129f9625572136dda4a9245 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 29 May 2026 21:57:11 +0000
Subject: [PATCH 082/111] chore(deps): bump tar from 0.4.45 to 0.4.46
Bumps [tar](https://github.com/composefs/tar-rs) from 0.4.45 to 0.4.46.
- [Release notes](https://github.com/composefs/tar-rs/releases)
- [Commits](https://github.com/composefs/tar-rs/compare/0.4.45...0.4.46)
---
updated-dependencies:
- dependency-name: tar
dependency-version: 0.4.46
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index bf050ff..988976d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3975,9 +3975,9 @@ dependencies = [
[[package]]
name = "tar"
-version = "0.4.45"
+version = "0.4.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
+checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840"
dependencies = [
"filetime",
"libc",
From b11ac0bff9a8d18506389d000bada7df5a53c499 Mon Sep 17 00:00:00 2001
From: Evelyn Torres
Date: Sun, 31 May 2026 08:17:58 -0230
Subject: [PATCH 083/111] pkg(samsung, bell): Add packages from Samsung Galaxy
A21
---
resources/assets/uad_lists.json | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 6bd102a..ce25c48 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -43091,5 +43091,29 @@
"neededBy": [],
"labels": [],
"removal": "Advanced"
+ },
+ "com.bell.ptt": {
+ "list": "Carrier",
+ "description": "Bell Push to Talk app. Apparently the 'most advanced carrier-grade Push-to-talk coomunicates technology available today.' (doubt). Realistically, no one is using this, safe to remove.\n https://play.google.com/store/apps/details?id=com.bell.ptt",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
+ },
+ "com.samsung.android.A21.d01.wallpapermulti": {
+ "list": "Oem",
+ "description": "Dynamic lock screen wallpaper feature for the Samsung Galaxy A21. Why is this device specific? I have no idea!",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.sec.android.app.camera.sticker": {
+ "list": "Oem",
+ "description": "Samsung DECO PIC. Add things such as live stickers, AR masks, frames, and GIFs to your photos and videos.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Recommended"
}
}
From 649d0d0bcf91a398b26fd7bbb8647ec18b6462cb Mon Sep 17 00:00:00 2001
From: Angel J <78835633+iamanaws@users.noreply.github.com>
Date: Thu, 4 Jun 2026 19:31:58 -0700
Subject: [PATCH 084/111] pkg(aosp): fix typo in AOSP keyboard app description
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index ce25c48..323c7d3 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -8434,7 +8434,7 @@
},
"com.android.inputmethod.latin": {
"list": "Aosp",
- "description": "The AOSP keyboard app\nMame sure you have another installed before you disable.",
+ "description": "The AOSP keyboard app\nMake sure you have another installed before you disable.",
"dependencies": [],
"neededBy": [],
"labels": [],
From b86c41187c2a719378b47c428190e44a83737510 Mon Sep 17 00:00:00 2001
From: itz8bitstudios
Date: Sat, 13 Jun 2026 17:06:29 +0200
Subject: [PATCH 085/111] pkg(motorola): update com.motorola.setup removal
level and description
- Change removal level from Advanced to Expert
- Update description to emphasize security patch implications
- Clarify that freezing breaks Google Play System Updates (Project Mainline)
- Add clear warning about security patch impact
Closes #1412
---
resources/assets/uad_lists.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 323c7d3..42a33d6 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -4371,11 +4371,11 @@
},
"com.motorola.setup": {
"list": "Oem",
- "description": "Related to Motorola Account setup (only during first boot ?)\nWARNING: Removing this package breaks Google Play System Updates. Appears to be tied to Google's Play Store update mechanism on Motorola devices\n",
+ "description": "Related to Motorola Account setup (only during first boot?) DO NOT REMOVE unless you don't care about security patches. Freezing this package completely halts Google Play System Updates (Project Mainline), preventing the device from receiving security fixes.",
"dependencies": [],
"neededBy": [],
"labels": [],
- "removal": "Advanced"
+ "removal": "Expert"
},
"com.motorola.slpc_sys": {
"list": "Oem",
From 7dcb7e9315bb57db06e18cc2937e81f2d8292fee Mon Sep 17 00:00:00 2001
From: iamanaws <78835633+Iamanaws@users.noreply.github.com>
Date: Sat, 25 Oct 2025 15:23:47 -0700
Subject: [PATCH 086/111] feat: add CLI and restructure into multi-package
workspace
- Add crates/uad-cli for command-line interface
- Extract shared logic into crates/uad-core
- Separate GUI into crates/uad-gui
- Enable code reuse across components
---
.github/workflows/build_artifacts.yml | 58 +-
.github/workflows/release.yml | 4 +-
Cargo.lock | 807 ++++++++++++++----
Cargo.toml | 71 +-
crates/uad-cli/Cargo.toml | 53 ++
crates/uad-cli/README.md | 276 ++++++
crates/uad-cli/examples/usage.sh | 44 +
crates/uad-cli/src/commands.rs | 464 ++++++++++
crates/uad-cli/src/device.rs | 45 +
crates/uad-cli/src/filters.rs | 98 +++
crates/uad-cli/src/main.rs | 232 +++++
crates/uad-cli/src/output.rs | 18 +
crates/uad-cli/src/repl.rs | 369 ++++++++
crates/uad-core/Cargo.toml | 56 ++
{src/core => crates/uad-core/src}/adb.rs | 14 +-
{src/core => crates/uad-core/src}/config.rs | 27 +-
crates/uad-core/src/lib.rs | 24 +
{src/core => crates/uad-core/src}/save.rs | 23 +-
{src/core => crates/uad-core/src}/sync.rs | 228 +++--
{src/core => crates/uad-core/src}/theme.rs | 22 +
.../core => crates/uad-core/src}/uad_lists.rs | 11 +-
{src/core => crates/uad-core/src}/update.rs | 4 +-
{src/core => crates/uad-core/src}/utils.rs | 98 ++-
crates/uad-gui/Cargo.toml | 63 ++
src/gui/mod.rs => crates/uad-gui/src/gui.rs | 90 +-
crates/uad-gui/src/helpers.rs | 23 +
crates/uad-gui/src/lib.rs | 11 +
{src => crates/uad-gui/src}/main.rs | 15 +-
{src/gui => crates/uad-gui/src}/style.rs | 27 +-
crates/uad-gui/src/theme.rs | 72 ++
.../gui => crates/uad-gui/src}/views/about.rs | 17 +-
{src/gui => crates/uad-gui/src}/views/list.rs | 172 ++--
{src/gui => crates/uad-gui/src}/views/mod.rs | 0
.../uad-gui/src}/views/settings.rs | 81 +-
.../gui => crates/uad-gui/src}/widgets/mod.rs | 0
.../uad-gui/src}/widgets/modal.rs | 1 +
.../uad-gui/src}/widgets/navigation_menu.rs | 19 +-
.../uad-gui/src}/widgets/package_row.rs | 79 +-
.../uad-gui/src}/widgets/text.rs | 3 +-
src/core/helpers.rs | 14 -
src/core/mod.rs | 9 -
41 files changed, 3128 insertions(+), 614 deletions(-)
create mode 100644 crates/uad-cli/Cargo.toml
create mode 100644 crates/uad-cli/README.md
create mode 100755 crates/uad-cli/examples/usage.sh
create mode 100644 crates/uad-cli/src/commands.rs
create mode 100644 crates/uad-cli/src/device.rs
create mode 100644 crates/uad-cli/src/filters.rs
create mode 100644 crates/uad-cli/src/main.rs
create mode 100644 crates/uad-cli/src/output.rs
create mode 100644 crates/uad-cli/src/repl.rs
create mode 100644 crates/uad-core/Cargo.toml
rename {src/core => crates/uad-core/src}/adb.rs (98%)
rename {src/core => crates/uad-core/src}/config.rs (86%)
create mode 100644 crates/uad-core/src/lib.rs
rename {src/core => crates/uad-core/src}/save.rs (90%)
rename {src/core => crates/uad-core/src}/sync.rs (77%)
rename {src/core => crates/uad-core/src}/theme.rs (92%)
rename {src/core => crates/uad-core/src}/uad_lists.rs (95%)
rename {src/core => crates/uad-core/src}/update.rs (99%)
rename {src/core => crates/uad-core/src}/utils.rs (80%)
create mode 100644 crates/uad-gui/Cargo.toml
rename src/gui/mod.rs => crates/uad-gui/src/gui.rs (86%)
create mode 100644 crates/uad-gui/src/helpers.rs
create mode 100644 crates/uad-gui/src/lib.rs
rename {src => crates/uad-gui/src}/main.rs (90%)
rename {src/gui => crates/uad-gui/src}/style.rs (98%)
create mode 100644 crates/uad-gui/src/theme.rs
rename {src/gui => crates/uad-gui/src}/views/about.rs (94%)
rename {src/gui => crates/uad-gui/src}/views/list.rs (92%)
rename {src/gui => crates/uad-gui/src}/views/mod.rs (100%)
rename {src/gui => crates/uad-gui/src}/views/settings.rs (88%)
rename {src/gui => crates/uad-gui/src}/widgets/mod.rs (100%)
rename {src/gui => crates/uad-gui/src}/widgets/modal.rs (99%)
rename {src/gui => crates/uad-gui/src}/widgets/navigation_menu.rs (90%)
rename {src/gui => crates/uad-gui/src}/widgets/package_row.rs (71%)
rename {src/gui => crates/uad-gui/src}/widgets/text.rs (92%)
delete mode 100644 src/core/helpers.rs
delete mode 100644 src/core/mod.rs
diff --git a/.github/workflows/build_artifacts.yml b/.github/workflows/build_artifacts.yml
index 22ae978..63e6542 100644
--- a/.github/workflows/build_artifacts.yml
+++ b/.github/workflows/build_artifacts.yml
@@ -42,7 +42,7 @@ jobs:
restore-keys: ${{ runner.OS }}-release-
if: matrix.os == 'ubuntu-22.04'
- name: Building
- run: cargo build --release --no-default-features --features wgpu,${{ matrix.update_feature }},img
+ run: cargo build --release -p uad-gui --no-default-features --features wgpu,${{ matrix.update_feature }},img
- name: Renaming binaries [Windows]
if: matrix.os == 'windows-2022'
run: mv target/release/uad-ng.exe uad-ng-${{ matrix.build_target }}.exe
@@ -68,3 +68,59 @@ jobs:
with:
name: uad-ng${{ matrix.update_name }}-${{ matrix.build_target }}
path: uad-ng-*
+
+ build-cli:
+ name: Building CLI ${{ matrix.build_target }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ include:
+ - build_target: linux
+ os: ubuntu-22.04
+ - build_target: macos
+ os: macos-15
+ - build_target: macos-intel
+ os: macos-15-intel
+ - build_target: windows
+ os: windows-2022
+ steps:
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@stable
+ - uses: actions/cache@v4
+ with:
+ path: |
+ ~/.cargo/bin/
+ ~/.cargo/registry/index/
+ ~/.cargo/registry/cache/
+ ~/.cargo/git/db/
+ target
+ key: ${{ runner.os }}-release-cli-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: ${{ runner.OS }}-release-cli-
+ if: matrix.os == 'ubuntu-22.04'
+ - name: Building
+ run: cargo build --release -p uad-cli
+ - name: Renaming binaries [Windows]
+ if: matrix.os == 'windows-2022'
+ run: mv target/release/uad.exe uad-cli-${{ matrix.build_target }}.exe
+ - name: Renaming binaries [Others]
+ if: matrix.os != 'windows-2022'
+ run: mv target/release/uad uad-cli-${{ matrix.build_target }}
+ - name: Tarball Linux/MacOS binary
+ if: matrix.os != 'windows-2022'
+ run: tar -czf uad-cli-${{ matrix.build_target }}{.tar.gz,}
+ - name: Install coreutils for macOS
+ if: startsWith(matrix.os, 'macos')
+ run: brew install coreutils
+ - name: Create checksums for binaries and archives [Windows]
+ if: matrix.os == 'windows-2022'
+ run: sha256sum uad-cli-${{ matrix.build_target }}.exe | tee uad-cli-${{ matrix.build_target }}.exe-checksum.txt
+ - name: Create checksums for binaries and archives [Others]
+ if: matrix.os != 'windows-2022'
+ run: |
+ sha256sum uad-cli-${{ matrix.build_target }} | tee uad-cli-${{ matrix.build_target }}-checksum
+ sha256sum uad-cli-${{ matrix.build_target }}.tar.gz | tee uad-cli-${{ matrix.build_target }}.tar.gz-checksum
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: uad-cli-${{ matrix.build_target }}
+ path: uad-cli-*
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8d8c307..66ef045 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -25,7 +25,9 @@ jobs:
- name: Create release
uses: softprops/action-gh-release@v2
with:
- files: uad-ng-*/*
+ files: |
+ uad-ng-*/*
+ uad-cli-*/*
generate_release_notes: true
body: |
> [!NOTE]
diff --git a/Cargo.lock b/Cargo.lock
index 988976d..63ccf02 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -101,10 +101,60 @@ dependencies = [
]
[[package]]
-name = "anyhow"
-version = "1.0.100"
+name = "anstream"
+version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
[[package]]
name = "arbitrary"
@@ -409,7 +459,7 @@ dependencies = [
"num-traits",
"pastey",
"rayon",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"v_frame",
"y4m",
]
@@ -430,9 +480,9 @@ dependencies = [
[[package]]
name = "avif-serialize"
-version = "0.8.6"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f"
+checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d"
dependencies = [
"arrayvec",
]
@@ -536,9 +586,9 @@ checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
[[package]]
name = "bytemuck"
-version = "1.24.0"
+version = "1.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
+checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
dependencies = [
"bytemuck_derive",
]
@@ -619,9 +669,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.51"
+version = "1.2.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
+checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -641,6 +691,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+[[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
[[package]]
name = "cfg_aliases"
version = "0.2.1"
@@ -649,15 +705,64 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
-version = "0.4.42"
+version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
+checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
dependencies = [
"iana-time-zone",
"num-traits",
"windows-link",
]
+[[package]]
+name = "clap"
+version = "4.5.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_complete"
+version = "4.5.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c757a3b7e39161a4e56f9365141ada2a6c915a8622c408ab6bb4b5d047371031"
+dependencies = [
+ "clap",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
+
[[package]]
name = "clipboard-win"
version = "5.4.1"
@@ -693,7 +798,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd63e33452ffdafd39924c4f05a5dd1e94db646c779c6bd59148a3d95fff5ad4"
dependencies = [
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"x11rb",
]
@@ -705,7 +810,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
dependencies = [
"serde",
"termcolor",
- "unicode-width",
+ "unicode-width 0.2.2",
]
[[package]]
@@ -714,6 +819,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+[[package]]
+name = "colorchoice"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
[[package]]
name = "colored"
version = "2.2.0"
@@ -951,9 +1062,9 @@ dependencies = [
[[package]]
name = "ctor-lite"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b"
+checksum = "b29fccfdaeb0f9bd90da5759b1d0eaa2f6cfcfe90960124cfc83141ed4e111fd"
[[package]]
name = "cursor-icon"
@@ -977,9 +1088,9 @@ dependencies = [
[[package]]
name = "deranged"
-version = "0.5.5"
+version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
+checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4"
dependencies = [
"powerfmt",
]
@@ -1090,6 +1201,12 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
+[[package]]
+name = "endian-type"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
+
[[package]]
name = "enumflags2"
version = "0.7.12"
@@ -1165,9 +1282,9 @@ dependencies = [
[[package]]
name = "euclid"
-version = "0.22.11"
+version = "0.22.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48"
+checksum = "df61bf483e837f88d5c2291dcf55c67be7e676b3a51acc48db3a7b163b91ed63"
dependencies = [
"num-traits",
]
@@ -1240,6 +1357,17 @@ dependencies = [
"syn",
]
+[[package]]
+name = "fd-lock"
+version = "4.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
+dependencies = [
+ "cfg-if",
+ "rustix 1.1.3",
+ "windows-sys 0.59.0",
+]
+
[[package]]
name = "fdeflate"
version = "0.3.7"
@@ -1261,27 +1389,26 @@ dependencies = [
[[package]]
name = "filetime"
-version = "0.2.26"
+version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed"
+checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
dependencies = [
"cfg-if",
"libc",
"libredox",
- "windows-sys 0.60.2",
]
[[package]]
name = "find-msvc-tools"
-version = "0.1.6"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "flate2"
-version = "1.1.5"
+version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
+checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -1482,9 +1609,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.16"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"libc",
@@ -1503,6 +1630,19 @@ dependencies = [
"wasip2",
]
+[[package]]
+name = "getrandom"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
+ "wasip3",
+]
+
[[package]]
name = "gif"
version = "0.14.1"
@@ -1667,6 +1807,12 @@ dependencies = [
"foldhash 0.2.0",
]
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
[[package]]
name = "hermit-abi"
version = "0.5.2"
@@ -1685,6 +1831,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
+[[package]]
+name = "home"
+version = "0.5.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "http"
version = "1.4.0"
@@ -1703,9 +1858,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "iana-time-zone"
-version = "0.1.64"
+version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
+checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
@@ -1739,7 +1894,7 @@ dependencies = [
"iced_widget",
"iced_winit",
"image",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
]
[[package]]
@@ -1756,7 +1911,7 @@ dependencies = [
"num-traits",
"rustc-hash 2.1.1",
"smol_str",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"web-time",
]
@@ -1802,7 +1957,7 @@ dependencies = [
"log",
"raw-window-handle",
"rustc-hash 2.1.1",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"unicode-segmentation",
]
@@ -1826,7 +1981,7 @@ dependencies = [
"iced_tiny_skia",
"iced_wgpu",
"log",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
]
[[package]]
@@ -1839,7 +1994,7 @@ dependencies = [
"iced_core",
"iced_futures",
"raw-window-handle",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
]
[[package]]
@@ -1875,7 +2030,7 @@ dependencies = [
"iced_graphics",
"log",
"rustc-hash 2.1.1",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"wgpu",
]
@@ -1889,7 +2044,7 @@ dependencies = [
"log",
"num-traits",
"rustc-hash 2.1.1",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"unicode-segmentation",
]
@@ -1904,7 +2059,7 @@ dependencies = [
"log",
"mundy",
"rustc-hash 2.1.1",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tracing",
"wasm-bindgen-futures",
"web-sys",
@@ -1993,6 +2148,12 @@ dependencies = [
"zerovec",
]
+[[package]]
+name = "id-arena"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
+
[[package]]
name = "idna"
version = "1.1.0"
@@ -2034,8 +2195,8 @@ dependencies = [
"rayon",
"rgb",
"tiff",
- "zune-core 0.5.0",
- "zune-jpeg 0.5.8",
+ "zune-core 0.5.1",
+ "zune-jpeg 0.5.12",
]
[[package]]
@@ -2056,12 +2217,14 @@ checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8"
[[package]]
name = "indexmap"
-version = "2.12.1"
+version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
dependencies = [
"equivalent",
"hashbrown 0.16.1",
+ "serde",
+ "serde_core",
]
[[package]]
@@ -2075,6 +2238,12 @@ dependencies = [
"syn",
]
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
[[package]]
name = "itertools"
version = "0.14.0"
@@ -2124,9 +2293,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.83"
+version = "0.3.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
+checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -2183,6 +2352,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+[[package]]
+name = "leb128fmt"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
+
[[package]]
name = "lebe"
version = "0.5.3"
@@ -2191,15 +2366,15 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
[[package]]
name = "libc"
-version = "0.2.179"
+version = "0.2.181"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f"
+checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5"
[[package]]
name = "libfuzzer-sys"
-version = "0.4.10"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404"
+checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
dependencies = [
"arbitrary",
"cc",
@@ -2217,9 +2392,9 @@ dependencies = [
[[package]]
name = "libm"
-version = "0.2.15"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
@@ -2229,7 +2404,7 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
dependencies = [
"bitflags 2.10.0",
"libc",
- "redox_syscall 0.7.0",
+ "redox_syscall 0.7.1",
]
[[package]]
@@ -2325,9 +2500,9 @@ dependencies = [
[[package]]
name = "memchr"
-version = "2.7.6"
+version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "memmap2"
@@ -2372,6 +2547,17 @@ dependencies = [
"simd-adler32",
]
+[[package]]
+name = "mio"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "moxcms"
version = "0.7.11"
@@ -2423,7 +2609,7 @@ dependencies = [
"bit-set",
"bitflags 2.10.0",
"cfg-if",
- "cfg_aliases",
+ "cfg_aliases 0.2.1",
"codespan-reporting",
"half",
"hashbrown 0.16.1",
@@ -2435,7 +2621,7 @@ dependencies = [
"once_cell",
"rustc-hash 1.1.0",
"spirv",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"unicode-ident",
]
@@ -2476,16 +2662,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
-name = "nix"
-version = "0.30.1"
+name = "nibble_vec"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
+checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
+dependencies = [
+ "smallvec",
+]
+
+[[package]]
+name = "nix"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags 2.10.0",
"cfg-if",
- "cfg_aliases",
+ "cfg_aliases 0.1.1",
"libc",
- "memoffset",
]
[[package]]
@@ -2957,6 +3151,12 @@ version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
[[package]]
name = "option-ext"
version = "0.2.0"
@@ -3132,15 +3332,15 @@ checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
[[package]]
name = "portable-atomic"
-version = "1.13.0"
+version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
+checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
[[package]]
name = "portable-atomic-util"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5"
dependencies = [
"portable-atomic",
]
@@ -3175,6 +3375,16 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
+[[package]]
+name = "prettyplease"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
[[package]]
name = "proc-macro-crate"
version = "3.4.0"
@@ -3186,9 +3396,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.105"
+version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
@@ -3247,9 +3457,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.43"
+version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
+checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
dependencies = [
"proc-macro2",
]
@@ -3260,6 +3470,16 @@ version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+[[package]]
+name = "radix_trie"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
+dependencies = [
+ "endian-type",
+ "nibble_vec",
+]
+
[[package]]
name = "rand"
version = "0.8.6"
@@ -3278,7 +3498,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha 0.9.0",
- "rand_core 0.9.3",
+ "rand_core 0.9.5",
]
[[package]]
@@ -3298,7 +3518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
- "rand_core 0.9.3",
+ "rand_core 0.9.5",
]
[[package]]
@@ -3307,14 +3527,14 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
]
[[package]]
name = "rand_core"
-version = "0.9.3"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
dependencies = [
"getrandom 0.3.4",
]
@@ -3361,7 +3581,7 @@ dependencies = [
"rand 0.9.2",
"rand_chacha 0.9.0",
"simd_helpers",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"v_frame",
"wasm-bindgen",
]
@@ -3438,9 +3658,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
+checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b"
dependencies = [
"bitflags 2.10.0",
]
@@ -3451,9 +3671,9 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
"libredox",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
]
[[package]]
@@ -3464,18 +3684,18 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
[[package]]
name = "retry"
-version = "2.1.0"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1e211f878258887b3e65dd3c8ff9f530fe109f441a117ee0cdc27f341355032"
+checksum = "1cab9bd343c737660e523ee69f788018f3db686d537d2fd0f99c9f747c1bda4f"
dependencies = [
"rand 0.9.2",
]
[[package]]
name = "rfd"
-version = "0.17.1"
+version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "069d6129dede311430d0dcf1ded88a7affc7a342c2d8e6336043d43ed14dac17"
+checksum = "20dafead71c16a34e1ff357ddefc8afc11e7d51d6d2b9fbd07eaa48e3e540220"
dependencies = [
"block2 0.6.2",
"dispatch2",
@@ -3512,7 +3732,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if",
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
"libc",
"untrusted",
"windows-sys 0.52.0",
@@ -3588,9 +3808,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.13.2"
+version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
+checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
dependencies = [
"zeroize",
]
@@ -3613,10 +3833,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
-name = "ryu"
-version = "1.0.22"
+name = "rustyline"
+version = "14.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
+checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63"
+dependencies = [
+ "bitflags 2.10.0",
+ "cfg-if",
+ "clipboard-win",
+ "fd-lock",
+ "home",
+ "libc",
+ "log",
+ "memchr",
+ "nix",
+ "radix_trie",
+ "unicode-segmentation",
+ "unicode-width 0.1.14",
+ "utf8parse",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "same-file"
@@ -3770,9 +4012,9 @@ dependencies = [
[[package]]
name = "slab"
-version = "0.4.11"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "slotmap"
@@ -3828,7 +4070,7 @@ dependencies = [
"log",
"memmap2",
"rustix 1.1.3",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"wayland-backend",
"wayland-client",
"wayland-csd-frame",
@@ -3861,6 +4103,16 @@ dependencies = [
"serde",
]
+[[package]]
+name = "socket2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
+dependencies = [
+ "libc",
+ "windows-sys 0.60.2",
+]
+
[[package]]
name = "softbuffer"
version = "0.4.8"
@@ -3919,6 +4171,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
[[package]]
name = "subtle"
version = "2.6.1"
@@ -3944,9 +4202,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.113"
+version = "2.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4"
+checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12"
dependencies = [
"proc-macro2",
"quote",
@@ -3986,12 +4244,12 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.24.0"
+version = "3.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
+checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1"
dependencies = [
"fastrand",
- "getrandom 0.3.4",
+ "getrandom 0.4.1",
"once_cell",
"rustix 1.1.3",
"windows-sys 0.61.2",
@@ -4017,11 +4275,11 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "2.0.17"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
- "thiserror-impl 2.0.17",
+ "thiserror-impl 2.0.18",
]
[[package]]
@@ -4037,9 +4295,9 @@ dependencies = [
[[package]]
name = "thiserror-impl"
-version = "2.0.17"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
@@ -4155,10 +4413,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
-name = "toml"
-version = "0.9.10+spec-1.1.0"
+name = "tokio"
+version = "1.49.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0825052159284a1a8b4d6c0c86cbc801f2da5afd2b225fa548c72f2e74002f48"
+checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "toml"
+version = "0.9.12+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
dependencies = [
"indexmap",
"serde_core",
@@ -4192,9 +4478,9 @@ dependencies = [
[[package]]
name = "toml_parser"
-version = "1.0.6+spec-1.1.0"
+version = "1.0.7+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
+checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1"
dependencies = [
"winnow",
]
@@ -4247,26 +4533,61 @@ dependencies = [
]
[[package]]
-name = "uad-ng"
+name = "uad-cli"
+version = "1.2.0"
+dependencies = [
+ "chrono",
+ "clap",
+ "clap_complete",
+ "csv",
+ "dirs",
+ "log",
+ "retry",
+ "rustyline",
+ "serde",
+ "serde_json",
+ "tokio",
+ "toml",
+ "uad-core",
+ "ureq",
+]
+
+[[package]]
+name = "uad-core"
version = "1.2.0"
dependencies = [
"chrono",
"csv",
"dark-light",
"dirs",
+ "flate2",
+ "iced",
+ "log",
+ "retry",
+ "serde",
+ "serde_json",
+ "tar",
+ "toml",
+ "ureq",
+ "win32console",
+]
+
+[[package]]
+name = "uad-gui"
+version = "1.2.0"
+dependencies = [
+ "chrono",
+ "dark-light",
+ "dirs",
"embed-resource",
"fern",
"flate2",
"iced",
"image",
"log",
- "retry",
"rfd",
- "serde",
- "serde_json",
"tar",
- "toml",
- "ureq",
+ "uad-core",
"win32console",
]
@@ -4289,9 +4610,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-ident"
-version = "1.0.22"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e"
[[package]]
name = "unicode-linebreak"
@@ -4311,12 +4632,24 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+[[package]]
+name = "unicode-width"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
[[package]]
name = "untrusted"
version = "0.9.0"
@@ -4325,9 +4658,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "ureq"
-version = "3.1.4"
+version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a"
+checksum = "fdc97a28575b85cfedf2a7e7d3cc64b3e11bd8ac766666318003abbacc7a21fc"
dependencies = [
"base64",
"cookie_store",
@@ -4381,10 +4714,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
-name = "uuid"
-version = "1.19.0"
+name = "utf8parse"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "uuid"
+version = "1.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f"
dependencies = [
"js-sys",
"serde_core",
@@ -4452,18 +4791,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasip2"
-version = "1.0.1+wasi-0.2.4"
+version = "1.0.2+wasi-0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasip3"
+version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasm-bindgen"
-version = "0.2.106"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
+checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
dependencies = [
"cfg-if",
"once_cell",
@@ -4474,11 +4822,12 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.56"
+version = "0.4.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
+checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f"
dependencies = [
"cfg-if",
+ "futures-util",
"js-sys",
"once_cell",
"wasm-bindgen",
@@ -4487,9 +4836,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.106"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
+checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -4497,9 +4846,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.106"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
+checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -4510,13 +4859,47 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.106"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
+checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
dependencies = [
"unicode-ident",
]
+[[package]]
+name = "wasm-encoder"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
+dependencies = [
+ "leb128fmt",
+ "wasmparser",
+]
+
+[[package]]
+name = "wasm-metadata"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
+dependencies = [
+ "anyhow",
+ "indexmap",
+ "wasm-encoder",
+ "wasmparser",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
+dependencies = [
+ "bitflags 2.10.0",
+ "hashbrown 0.15.5",
+ "indexmap",
+ "semver",
+]
+
[[package]]
name = "wasmtimer"
version = "0.4.3"
@@ -4668,9 +5051,9 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.83"
+version = "0.3.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
+checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -4688,9 +5071,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
-version = "1.0.5"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c"
+checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
dependencies = [
"rustls-pki-types",
]
@@ -4710,7 +5093,7 @@ dependencies = [
"arrayvec",
"bitflags 2.10.0",
"cfg-if",
- "cfg_aliases",
+ "cfg_aliases 0.2.1",
"document-features",
"hashbrown 0.16.1",
"js-sys",
@@ -4741,7 +5124,7 @@ dependencies = [
"bit-vec",
"bitflags 2.10.0",
"bytemuck",
- "cfg_aliases",
+ "cfg_aliases 0.2.1",
"document-features",
"hashbrown 0.16.1",
"indexmap",
@@ -4754,7 +5137,7 @@ dependencies = [
"raw-window-handle",
"rustc-hash 1.1.0",
"smallvec",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"wgpu-core-deps-apple",
"wgpu-core-deps-emscripten",
"wgpu-core-deps-windows-linux-android",
@@ -4803,7 +5186,7 @@ dependencies = [
"block",
"bytemuck",
"cfg-if",
- "cfg_aliases",
+ "cfg_aliases 0.2.1",
"core-graphics-types 0.2.0",
"glow",
"glutin_wgl_sys",
@@ -4830,7 +5213,7 @@ dependencies = [
"raw-window-handle",
"renderdoc-sys",
"smallvec",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"wasm-bindgen",
"web-sys",
"wgpu-types",
@@ -4848,7 +5231,7 @@ dependencies = [
"bytemuck",
"js-sys",
"log",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"web-sys",
]
@@ -4903,7 +5286,7 @@ dependencies = [
"clipboard_wayland",
"clipboard_x11",
"raw-window-handle",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
]
[[package]]
@@ -5390,7 +5773,7 @@ dependencies = [
"block2 0.5.1",
"bytemuck",
"calloop 0.13.0",
- "cfg_aliases",
+ "cfg_aliases 0.2.1",
"concurrent-queue",
"core-foundation 0.9.4",
"core-graphics",
@@ -5460,9 +5843,91 @@ dependencies = [
[[package]]
name = "wit-bindgen"
-version = "0.46.0"
+version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+dependencies = [
+ "wit-bindgen-rust-macro",
+]
+
+[[package]]
+name = "wit-bindgen-core"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
+dependencies = [
+ "anyhow",
+ "heck",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-bindgen-rust"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
+dependencies = [
+ "anyhow",
+ "heck",
+ "indexmap",
+ "prettyplease",
+ "syn",
+ "wasm-metadata",
+ "wit-bindgen-core",
+ "wit-component",
+]
+
+[[package]]
+name = "wit-bindgen-rust-macro"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
+dependencies = [
+ "anyhow",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wit-bindgen-core",
+ "wit-bindgen-rust",
+]
+
+[[package]]
+name = "wit-component"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
+dependencies = [
+ "anyhow",
+ "bitflags 2.10.0",
+ "indexmap",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-encoder",
+ "wasm-metadata",
+ "wasmparser",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-parser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+ "wasmparser",
+]
[[package]]
name = "writeable"
@@ -5580,9 +6045,9 @@ dependencies = [
[[package]]
name = "zbus"
-version = "5.12.0"
+version = "5.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91"
+checksum = "1bfeff997a0aaa3eb20c4652baf788d2dfa6d2839a0ead0b3ff69ce2f9c4bdd1"
dependencies = [
"async-broadcast",
"async-executor",
@@ -5598,8 +6063,9 @@ dependencies = [
"futures-core",
"futures-lite",
"hex",
- "nix",
+ "libc",
"ordered-stream",
+ "rustix 1.1.3",
"serde",
"serde_repr",
"tracing",
@@ -5614,9 +6080,9 @@ dependencies = [
[[package]]
name = "zbus_macros"
-version = "5.12.0"
+version = "5.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314"
+checksum = "0bbd5a90dbe8feee5b13def448427ae314ccd26a49cac47905cafefb9ff846f1"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -5629,12 +6095,11 @@ dependencies = [
[[package]]
name = "zbus_names"
-version = "4.2.0"
+version = "4.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97"
+checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f"
dependencies = [
"serde",
- "static_assertions",
"winnow",
"zvariant",
]
@@ -5647,18 +6112,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524"
[[package]]
name = "zerocopy"
-version = "0.8.31"
+version = "0.8.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
+checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.31"
+version = "0.8.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
+checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
dependencies = [
"proc-macro2",
"quote",
@@ -5727,9 +6192,9 @@ dependencies = [
[[package]]
name = "zmij"
-version = "1.0.12"
+version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
[[package]]
name = "zune-core"
@@ -5739,9 +6204,9 @@ checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
[[package]]
name = "zune-core"
-version = "0.5.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "111f7d9820f05fd715df3144e254d6fc02ee4088b0644c0ffd0efc9e6d9d2773"
+checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"
[[package]]
name = "zune-inflate"
@@ -5763,18 +6228,18 @@ dependencies = [
[[package]]
name = "zune-jpeg"
-version = "0.5.8"
+version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e35aee689668bf9bd6f6f3a6c60bb29ba1244b3b43adfd50edd554a371da37d5"
+checksum = "410e9ecef634c709e3831c2cfdb8d9c32164fae1c67496d5b68fff728eec37fe"
dependencies = [
- "zune-core 0.5.0",
+ "zune-core 0.5.1",
]
[[package]]
name = "zvariant"
-version = "5.8.0"
+version = "5.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2be61892e4f2b1772727be11630a62664a1826b62efa43a6fe7449521cb8744c"
+checksum = "68b64ef4f40c7951337ddc7023dd03528a57a3ce3408ee9da5e948bd29b232c4"
dependencies = [
"endi",
"enumflags2",
@@ -5787,9 +6252,9 @@ dependencies = [
[[package]]
name = "zvariant_derive"
-version = "5.8.0"
+version = "5.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006"
+checksum = "484d5d975eb7afb52cc6b929c13d3719a20ad650fea4120e6310de3fc55e415c"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -5800,9 +6265,9 @@ dependencies = [
[[package]]
name = "zvariant_utils"
-version = "3.2.1"
+version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599"
+checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index 2a863e0..3529c3e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,12 @@
-[package]
-name = "uad-ng"
-description = "A cross-platform GUI debloater for android devices"
+[workspace]
+members = [
+ "crates/uad-core",
+ "crates/uad-gui",
+ "crates/uad-cli"
+]
+resolver = "2"
+
+[workspace.package]
version = "1.2.0"
authors = ["Universal-Debloater-Alliance"]
license = "GPL-3.0"
@@ -11,59 +17,38 @@ keywords = ["debloater", "android", "adb", "privacy", "bloatware"]
categories = ["gui"]
edition = "2024"
-[features]
-default = ["wgpu", "self-update", "img"]
-wgpu = [] # Iced/wgpu is default
-self-update = ["flate2", "tar"]
-no-self-update = []
-img = ["image", "iced/image"]
-
-[dependencies]
-dark-light = "2"
+[workspace.dependencies]
+# Core dependencies
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0"
-fern = { version = "^0", features = ["colored"] }
-chrono = { version = "^0.4", default-features = false, features = [
- "std",
- "clock",
-] }
log = "^0.4"
+chrono = { version = "^0.4", default-features = false, features = ["std", "clock"] }
toml = "^0"
dirs = "^6"
ureq = { version = "3", features = ["json"] }
retry = "^2.0.0"
-iced = { version = "=0.14.0", features = ["advanced"] }
-image = { version = "0.25", optional = true }
-rfd = "^0.17.1"
csv = "^1.3"
-[target.'cfg(not(target_os = "windows"))'.dependencies]
-flate2 = { version = "^1", optional = true }
-tar = { version = "^0.4", optional = true }
+# GUI dependencies
+iced = { version = "=0.14.0", features = ["advanced"] }
+image = "0.25"
+rfd = "^0.17.1"
+dark-light = "2"
+fern = { version = "^0", features = ["colored"] }
-[target.'cfg(target_os = "windows")'.dependencies]
+# CLI dependencies
+clap = { version = "4.5", features = ["derive"] }
+tokio = { version = "1.0", features = ["full"] }
+
+# Platform-specific dependencies
+flate2 = "^1"
+tar = "^0.4"
win32console = "^0.1.5"
-[profile.release]
-lto = "thin"
-opt-level = 2
-codegen-units = 4
-
-[profile.opt]
-inherits = "release"
-opt-level = "s"
-codegen-units = 1
-lto = "fat"
-strip = true
-panic = "abort"
-
-[build-dependencies]
-embed-resource = "3"
-
-[lints.rust]
+[workspace.lints.rust]
deprecated_safe = "warn"
-[lints.clippy]
+[workspace.lints.clippy]
undocumented_unsafe_blocks = "forbid"
panic_in_result_fn = "warn"
infinite_loop = "warn"
@@ -75,4 +60,4 @@ struct_field_names = "allow" # annoying
disallowed_types = "deny"
disallowed_methods = "deny"
-pedantic = { level = "warn", priority = -1 }
+pedantic = { level = "warn", priority = -1 }
\ No newline at end of file
diff --git a/crates/uad-cli/Cargo.toml b/crates/uad-cli/Cargo.toml
new file mode 100644
index 0000000..d0118ae
--- /dev/null
+++ b/crates/uad-cli/Cargo.toml
@@ -0,0 +1,53 @@
+[package]
+name = "uad-cli"
+version.workspace = true
+authors.workspace = true
+license.workspace = true
+homepage.workspace = true
+repository.workspace = true
+readme.workspace = true
+keywords.workspace = true
+categories = ["command-line-utilities"]
+edition.workspace = true
+
+[[bin]]
+name = "uad"
+path = "src/main.rs"
+
+[dependencies]
+uad-core = { path = "../uad-core" }
+clap.workspace = true
+clap_complete = "4.4"
+tokio.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+log.workspace = true
+chrono.workspace = true
+toml.workspace = true
+dirs.workspace = true
+ureq.workspace = true
+retry.workspace = true
+csv.workspace = true
+rustyline = "14.0"
+
+[lints.rust]
+deprecated_safe = "warn"
+
+[lints.clippy]
+undocumented_unsafe_blocks = "deny"
+exit = "deny"
+panic_in_result_fn = "warn"
+infinite_loop = "warn"
+mem_forget = "warn"
+implicit_clone = "warn"
+format_push_string = "warn"
+large_include_file = "warn"
+shadow_unrelated = "warn"
+struct_field_names = "allow" # annoying
+module_name_repetitions = "allow" # annoying
+
+disallowed_types = "deny"
+disallowed_methods = "deny"
+
+allow_attributes_without_reason = "warn"
+pedantic = { level = "warn", priority = -1 }
diff --git a/crates/uad-cli/README.md b/crates/uad-cli/README.md
new file mode 100644
index 0000000..86a2a77
--- /dev/null
+++ b/crates/uad-cli/README.md
@@ -0,0 +1,276 @@
+# UAD CLI - Universal Android Debloater Command Line Interface
+
+A powerful command-line interface for debloating Android devices, sharing the core functionality with the UAD GUI application.
+
+## Features
+
+- 🚀 **Fast & Efficient** - Direct command execution without GUI overhead
+- 📦 **Package Manager-like Interface** - Intuitive commands similar to `apt`, `dnf`, or `pacman`
+- 🔍 **Advanced Filtering** - Filter packages by state, removal category, UAD list, or search terms
+- 🛡️ **Safety Features** - Dry-run mode, warnings for unsafe packages
+- 🔄 **Multiple Actions** - Enable, disable, uninstall, and restore packages
+- 🖥️ **Interactive REPL Mode** - Keep device state in memory for faster operations
+- 📋 **Shell Completion** - Generate completions for bash, zsh, fish, and more
+- 👥 **Multi-user Support** - Target specific Android user profiles
+
+## Installation
+
+Build from source:
+
+```bash
+cd /path/to/universal-android-debloater-next-generation
+cargo build --release -p uad-cli
+```
+
+The binary will be available at `target/release/uad` (the package is `uad-cli`; the installed binary name is `uad`).
+
+## Usage
+
+### List Connected Devices
+
+```bash
+uad devices
+```
+
+### List Packages
+
+List all packages on the first connected device:
+
+```bash
+uad list
+# or use the short alias
+uad ls
+```
+
+Filter packages by state:
+
+```bash
+uad list --state enabled
+uad list --state disabled
+uad list --state uninstalled
+```
+
+Filter by removal category:
+
+```bash
+uad list --removal recommended
+uad list --removal advanced
+uad list --removal expert
+uad list --removal unsafe
+```
+
+Filter by UAD list:
+
+```bash
+uad list --list google
+uad list --list oem
+uad list --list aosp
+```
+
+Search for packages:
+
+```bash
+uad list --search "facebook"
+uad list -q "chrome"
+```
+
+Combine filters:
+
+```bash
+uad list --state enabled --removal recommended --search "google"
+```
+
+### Show Package Information
+
+```bash
+uad info com.android.chrome
+uad info com.facebook.katana --device SERIAL123
+```
+
+### Uninstall Packages
+
+Uninstall one or more packages:
+
+```bash
+uad uninstall com.facebook.katana
+uad rm com.facebook.katana com.facebook.services
+```
+
+Dry-run to see what would happen:
+
+```bash
+uad uninstall com.facebook.katana --dry-run
+```
+
+Specify device and user:
+
+```bash
+uad uninstall com.facebook.katana --device SERIAL123 --user 0
+```
+
+### Enable/Restore Packages
+
+```bash
+uad enable com.android.chrome
+uad restore com.google.android.gms
+```
+
+### Disable Packages
+
+```bash
+uad disable com.facebook.katana
+```
+
+### Update Package Lists
+
+Update UAD lists from the remote repository:
+
+```bash
+uad update
+```
+
+### Interactive REPL Mode
+
+Start an interactive session for faster repeated operations:
+
+```bash
+uad repl
+# or
+uad shell
+```
+
+Within the REPL:
+
+```
+uad> help
+uad> list --state enabled
+uad> info com.facebook.katana
+uad> uninstall com.facebook.katana
+uad> enable com.android.chrome
+uad> device
+uad> exit
+```
+
+The REPL mode:
+- Keeps device state in memory (faster operations)
+- Saves command history (accessible with up/down arrows)
+- Loads UAD lists once at startup
+- Supports all the same commands as the CLI
+
+### Shell Completion
+
+Generate completion scripts for your shell:
+
+```bash
+# Bash
+uad completions bash > /usr/share/bash-completion/completions/uad
+
+# Zsh
+uad completions zsh > /usr/local/share/zsh/site-functions/_uad
+
+# Fish
+uad completions fish > ~/.config/fish/completions/uad.fish
+
+# PowerShell
+uad completions powershell > uad.ps1
+```
+
+## Command Reference
+
+| Command | Aliases | Description |
+|---------|---------|-------------|
+| `devices` | - | List connected Android devices |
+| `list` | `ls` | List packages with optional filters |
+| `info` | - | Show detailed package information |
+| `uninstall` | `rm` | Uninstall one or more packages |
+| `enable` | `restore` | Enable/restore packages |
+| `disable` | - | Disable packages (keeps data) |
+| `update` | - | Update UAD package lists |
+| `completions` | - | Generate shell completions |
+| `repl` | `shell` | Start interactive mode |
+
+## Examples
+
+### Remove all Facebook packages
+
+```bash
+uad list --search facebook
+uad uninstall com.facebook.katana com.facebook.services --dry-run
+# If it looks good:
+uad uninstall com.facebook.katana com.facebook.services
+```
+
+### Debloat recommended Google apps
+
+```bash
+# See what would be uninstalled
+uad list --removal recommended --list google
+
+# Uninstall them (you'd list the actual package names)
+uad uninstall com.google.package1 com.google.package2
+```
+
+### Work with a specific device
+
+```bash
+# List devices
+uad devices
+
+# Use specific device
+uad list --device SERIAL123
+uad uninstall com.facebook.katana --device SERIAL123
+```
+
+## Safety
+
+- **Dry-run mode**: Always test with `--dry-run` first
+- **Warnings**: The CLI warns you about packages marked as "Unsafe"
+- **Reversible**: Most operations can be reversed with the `enable` command
+- **Multi-user aware**: Respects Android's multi-user system
+
+## Comparison with GUI
+
+### CLI Advantages:
+- Faster for power users
+- Scriptable and automatable
+- Lower resource usage
+- Works over SSH
+- Better for batch operations
+- Can run on Android itself (though not recommended for same-device debloating)
+
+### GUI Advantages:
+- Visual feedback
+- Easier for beginners
+- Package descriptions always visible
+- Batch selection with checkboxes
+
+## Requirements
+
+- ADB (Android Debug Bridge) installed and in PATH
+- Android device with USB debugging enabled
+- Device authorized in ADB (run `adb devices` to check)
+
+## Troubleshooting
+
+**No devices found**
+- Ensure USB debugging is enabled on your device
+- Run `adb devices` to check if device is authorized
+- Try unplugging and replugging the device
+
+**Package not found**
+- The package might already be uninstalled
+- Check the exact package name with `adb shell pm list packages`
+- Try running `uad update` to refresh package lists
+
+**Permission denied**
+- Some system packages can't be modified without root
+- Some devices have locked bootloaders preventing certain operations
+
+## Contributing
+
+See the main project [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.
+
+## License
+
+GPL-3.0 - See [LICENSE](../../LICENSE) for details.
+
diff --git a/crates/uad-cli/examples/usage.sh b/crates/uad-cli/examples/usage.sh
new file mode 100755
index 0000000..ab3192e
--- /dev/null
+++ b/crates/uad-cli/examples/usage.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+# Example usage script for UAD CLI
+
+# Check if uad-cli is available
+if ! command -v uad &> /dev/null; then
+ echo "uad command not found. Please build and install uad-cli first."
+ exit 1
+fi
+
+echo "=== UAD CLI Usage Examples ==="
+echo
+
+echo "1. List connected devices:"
+uad devices
+echo
+
+echo "2. List all enabled packages:"
+uad list --state enabled | head -20
+echo "... (showing first 20)"
+echo
+
+echo "3. Search for Google packages:"
+uad list --search google | head -10
+echo "... (showing first 10)"
+echo
+
+echo "4. Show info about a package (example):"
+echo "uad info com.google.android.gms"
+echo
+
+echo "5. Dry-run uninstall (safe to test):"
+echo "uad uninstall com.example.package --dry-run"
+echo
+
+echo "6. Start interactive mode:"
+echo "uad repl"
+echo
+
+echo "=== Generate shell completions ==="
+echo "For bash: uad completions bash > ~/.local/share/bash-completion/completions/uad"
+echo "For zsh: uad completions zsh > ~/.local/share/zsh/site-functions/_uad"
+echo "For fish: uad completions fish > ~/.config/fish/completions/uad.fish"
+
diff --git a/crates/uad-cli/src/commands.rs b/crates/uad-cli/src/commands.rs
new file mode 100644
index 0000000..3d0f13d
--- /dev/null
+++ b/crates/uad-cli/src/commands.rs
@@ -0,0 +1,464 @@
+use clap::CommandFactory;
+use clap_complete::{Shell, generate};
+use std::collections::{HashMap, HashSet};
+use std::io::Write;
+use uad_core::adb::{ACommand, PmListPacksFlag};
+use uad_core::sync::{
+ CorePackage, Phone, User, apply_pkg_state_commands, get_devices_list, get_package_state,
+ run_adb_shell_action,
+};
+use uad_core::uad_lists::{Package, PackageState, Removal, UadList, load_debloat_lists};
+use uad_core::utils::{matches_search, truncate_description};
+
+use crate::device::{get_target_device, get_user};
+use crate::filters::{ListFilter, RemovalFilter, StateFilter};
+use crate::{Cli, print_or_exit, println_or_exit};
+
+/// List all connected Android devices
+pub fn list_devices() -> Result<(), Box> {
+ println!("Scanning for connected devices...");
+ let devices = get_devices_list();
+
+ if devices.is_empty() {
+ eprintln!("No devices found. Make sure ADB is installed and devices are connected.");
+ return Err("No devices found".into());
+ }
+
+ println!("\nFound {} device(s):\n", devices.len());
+ for device in &devices {
+ println!(" Model: {}", device.model);
+ println!(" Serial: {}", device.adb_id);
+ println!(" Android SDK: {}", device.android_sdk);
+
+ if !device.user_list.is_empty() {
+ println!(" Users: {} user(s)", device.user_list.len());
+ for user in &device.user_list {
+ let protected = if user.protected { " (protected)" } else { "" };
+ println!(" - User ID: {}{}", user.id, protected);
+ }
+ }
+ println!();
+ }
+
+ Ok(())
+}
+
+/// Context for package filtering and display
+pub struct PackageListContext {
+ pub state_filter: Option,
+ pub removal_filter: Option,
+ pub list_filter: Option,
+ pub search: Option,
+}
+
+impl PackageListContext {
+ /// Check if package passes all filters
+ pub fn filter_package(
+ &self,
+ pkg_name: &str,
+ pkg_info: Option<&Package>,
+ pkg_state: PackageState,
+ ) -> bool {
+ // Removal filter
+ if let Some(removal) = self.removal_filter {
+ if !removal.matches(pkg_info) {
+ return false;
+ }
+ }
+
+ // State filter
+ if let Some(state) = self.state_filter {
+ if !state.matches(pkg_state) {
+ return false;
+ }
+ }
+
+ // List filter
+ if let Some(list) = self.list_filter {
+ if !list.matches(pkg_info) {
+ return false;
+ }
+ }
+
+ // Search filter
+ if let Some(ref search_term) = self.search {
+ let description = pkg_info.map(|p| p.description.as_str());
+ if !matches_search(pkg_name, search_term, description) {
+ return false;
+ }
+ }
+
+ true
+ }
+
+ /// Determine what information to show based on active filters
+ pub fn display_config(&self) -> DisplayConfig {
+ DisplayConfig {
+ show_state: self.state_filter.is_none_or(|f| !f.is_specific()),
+ show_removal: self.removal_filter.is_none_or(|f| !f.is_specific()),
+ }
+ }
+}
+
+pub struct DisplayConfig {
+ pub show_state: bool,
+ pub show_removal: bool,
+}
+
+/// List packages on a device with filtering
+pub fn list_packages(
+ device: Option,
+ state_filter: Option,
+ removal_filter: Option,
+ list_filter: Option,
+ search: Option,
+ user_id: Option,
+) -> Result<(), Box> {
+ let target_device = get_target_device(device)?;
+ let uad_lists = load_debloat_lists(false).unwrap_or_else(|lists| lists);
+
+ println_or_exit!(
+ "Listing packages on: {} ({})\n",
+ target_device.model,
+ target_device.adb_id
+ );
+
+ let context = PackageListContext {
+ state_filter,
+ removal_filter,
+ list_filter,
+ search,
+ };
+
+ let pm_flag = state_filter.and_then(StateFilter::to_pm_flag);
+ let system_packages = ACommand::new()
+ .shell(&target_device.adb_id)
+ .pm()
+ .list_packages_sys(pm_flag, user_id)?;
+
+ let displayed_count = display_package_list(
+ &system_packages,
+ &uad_lists,
+ &target_device.adb_id,
+ user_id,
+ &context,
+ )?;
+
+ if displayed_count == 0 {
+ println_or_exit!(" No packages found matching the specified filters.");
+ } else {
+ println_or_exit!("\nTotal: {} package(s)", displayed_count);
+ }
+
+ Ok(())
+}
+
+/// Display a list of packages with their info
+pub fn display_package_list(
+ packages: &[String],
+ uad_lists: &HashMap,
+ device_serial: &str,
+ user_id: Option,
+ context: &PackageListContext,
+) -> Result> {
+ let config = context.display_config();
+ let mut displayed_count = 0;
+
+ let enabled_packages: HashSet = ACommand::new()
+ .shell(device_serial)
+ .pm()
+ .list_packages_sys(Some(PmListPacksFlag::OnlyEnabled), user_id)
+ .unwrap_or_default()
+ .into_iter()
+ .collect();
+ let disabled_packages: HashSet = ACommand::new()
+ .shell(device_serial)
+ .pm()
+ .list_packages_sys(Some(PmListPacksFlag::OnlyDisabled), user_id)
+ .unwrap_or_default()
+ .into_iter()
+ .collect();
+
+ for pkg_name in packages {
+ let pkg_info = uad_lists.get(pkg_name);
+
+ let pkg_state = if enabled_packages.contains(pkg_name) {
+ PackageState::Enabled
+ } else if disabled_packages.contains(pkg_name) {
+ PackageState::Disabled
+ } else {
+ PackageState::Uninstalled
+ };
+
+ if !context.filter_package(pkg_name, pkg_info, pkg_state) {
+ continue;
+ }
+
+ display_package_entry(pkg_name, pkg_info, pkg_state, &config);
+ displayed_count += 1;
+ }
+
+ Ok(displayed_count)
+}
+
+/// Display a single package entry
+pub fn display_package_entry(
+ pkg_name: &str,
+ pkg_info: Option<&Package>,
+ pkg_state: PackageState,
+ config: &DisplayConfig,
+) {
+ print_or_exit!("[");
+
+ if let Some(info) = pkg_info {
+ if config.show_removal {
+ print_or_exit!("{}", info.removal);
+ if config.show_state {
+ print_or_exit!(" - ");
+ }
+ }
+ if config.show_state {
+ print_or_exit!("{}", pkg_state);
+ }
+ print_or_exit!("] {}", pkg_name);
+ if !info.description.is_empty() {
+ print_or_exit!(" - {}", truncate_description(&info.description, 80));
+ }
+ } else {
+ if config.show_removal {
+ print_or_exit!("Unlisted");
+ if config.show_state {
+ print_or_exit!(" - ");
+ }
+ }
+ if config.show_state {
+ print_or_exit!("{}", pkg_state);
+ }
+ print_or_exit!("] {}", pkg_name);
+ }
+
+ println_or_exit!();
+}
+
+/// Change the state of one or more packages
+pub fn change_package_state(
+ packages: &[String],
+ device: Option,
+ user_id: Option,
+ dry_run: bool,
+ target_state: PackageState,
+ action_name: &str,
+) -> Result<(), Box> {
+ if packages.is_empty() {
+ eprintln!("Error: No packages specified");
+ return Err("No packages specified".into());
+ }
+
+ let target_device = get_target_device(device)?;
+ let user = get_user(&target_device, user_id)?;
+ let uad_lists = load_debloat_lists(false).unwrap_or_else(|lists| lists);
+
+ println!(
+ "{} {} package(s) on: {} ({})\n",
+ action_name,
+ packages.len(),
+ target_device.model,
+ target_device.adb_id
+ );
+
+ if dry_run {
+ println!("DRY RUN - No changes will be made\n");
+ }
+
+ for pkg_name in packages {
+ process_package_state_change(
+ pkg_name,
+ &target_device,
+ user,
+ target_state,
+ dry_run,
+ &uad_lists,
+ )?;
+ println!();
+ }
+
+ if dry_run {
+ println!("Dry run completed. No changes were made.");
+ } else {
+ println!("Operation completed successfully.");
+ }
+
+ Ok(())
+}
+
+/// Process state change for a single package
+fn process_package_state_change(
+ pkg_name: &str,
+ device: &Phone,
+ user: User,
+ target_state: PackageState,
+ dry_run: bool,
+ uad_lists: &HashMap,
+) -> Result<(), Box> {
+ let current_state = get_package_state(&device.adb_id, pkg_name, Some(user.id))
+ .ok_or("Package not found on device")?;
+
+ println!(" {} ({})", pkg_name, current_state);
+
+ if current_state == target_state {
+ println!(" → Already in target state, skipping");
+ return Ok(());
+ }
+
+ let pkg_info = uad_lists.get(pkg_name);
+ if let Some(info) = pkg_info {
+ if info.removal == Removal::Unsafe {
+ println!(" ⚠ WARNING: This package is marked as UNSAFE to remove!");
+ }
+ }
+
+ let core_pkg = CorePackage {
+ name: pkg_name.to_string(),
+ description: pkg_info.map(|p| p.description.clone()).unwrap_or_default(),
+ removal: pkg_info.map(|p| p.removal).unwrap_or(Removal::Unlisted),
+ state: current_state,
+ list: pkg_info.map(|p| p.list).unwrap_or(UadList::Unlisted),
+ };
+
+ let commands = apply_pkg_state_commands(&core_pkg, target_state, user, device);
+
+ if dry_run {
+ for cmd in &commands {
+ println!(" Would run: {}", cmd);
+ }
+ } else {
+ execute_with_fallback(
+ pkg_name,
+ target_state,
+ &core_pkg,
+ user,
+ device,
+ &commands,
+ " ",
+ )?;
+ }
+
+ Ok(())
+}
+
+/// Execute commands and verify package state with fallback
+pub fn execute_with_fallback(
+ package: &str,
+ target_state: PackageState,
+ core_pkg: &CorePackage,
+ user: User,
+ device: &Phone,
+ commands: &[String],
+ indent: &str,
+) -> Result<(), Box> {
+ // Capture the before-state of packages on other users for cross-user detection
+ let before_cross_user_states =
+ uad_core::sync::capture_cross_user_states(package, &device.adb_id, user.id, device);
+
+ // Execute commands
+ for cmd in commands {
+ match run_adb_shell_action(&device.adb_id, cmd.as_str()) {
+ Ok(_) => println!("{}✓ {}", indent, cmd),
+ Err(e) => {
+ eprintln!("{}✗ Failed: {:?}", indent, e);
+ return Err(format!("Failed to execute: {}", cmd).into());
+ }
+ }
+ }
+
+ // Verify package state and attempt fallback if needed
+ let actual_state =
+ get_package_state(&device.adb_id, package, Some(user.id)).unwrap_or(PackageState::Enabled);
+
+ if actual_state != target_state {
+ println!(
+ "{}⚠ Package state verification failed: expected {:?}, got {:?}",
+ indent, target_state, actual_state
+ );
+
+ // Attempt fallback
+ if let Ok(fallback_action) =
+ uad_core::sync::attempt_fallback(core_pkg, target_state, actual_state, user, device)
+ {
+ println!("{}↻ Fallback: {}", indent, fallback_action);
+ } else {
+ println!("{}✗ No fallback available", indent);
+ }
+ }
+
+ // Check for cross-user behavior if operation succeeded
+ if actual_state == target_state {
+ if let Some(notification) = uad_core::sync::detect_cross_user_behavior(
+ package,
+ device.adb_id.as_str(),
+ user.id,
+ target_state,
+ actual_state,
+ device,
+ &before_cross_user_states,
+ ) {
+ println!("{}ℹ {}", indent, notification);
+ }
+ }
+
+ Ok(())
+}
+
+/// Show detailed information about a package
+pub fn show_package_info(
+ package: &str,
+ device: Option,
+) -> Result<(), Box> {
+ println!("Package: {}\n", package);
+
+ let uad_lists = load_debloat_lists(false).unwrap_or_else(|lists| lists);
+
+ if let Some(pkg_info) = uad_lists.get(package) {
+ println!("UAD Information:");
+ println!(" List: {}", pkg_info.list);
+ println!(" Removal: {}", pkg_info.removal);
+ println!(" Description: {}", pkg_info.description);
+ println!();
+ } else {
+ println!(" Not found in UAD lists (unlisted package)\n");
+ }
+
+ if let Some(device_id) = device {
+ let target_device = get_target_device(Some(device_id))?;
+ println!("Device: {} ({})", target_device.model, target_device.adb_id);
+
+ let state = get_package_state(&target_device.adb_id, package, None)
+ .ok_or("Package not found on device")?;
+ println!(" State: {}", state);
+ }
+
+ Ok(())
+}
+
+/// Update UAD package lists from remote repository
+pub fn update_lists() -> Result<(), Box> {
+ println!("Updating UAD package lists from remote repository...");
+
+ match load_debloat_lists(true) {
+ Ok(_lists) => {
+ println!("✓ Successfully updated package lists");
+ Ok(())
+ }
+ Err(_lists) => {
+ eprintln!("✗ Failed to update lists from remote, using cached version");
+ Err("Failed to update lists".into())
+ }
+ }
+}
+
+/// Generate shell completion script
+pub fn generate_completions(shell: Shell) {
+ let mut cmd = Cli::command();
+ let name = cmd.get_name().to_string();
+ generate(shell, &mut cmd, name, &mut std::io::stdout());
+}
diff --git a/crates/uad-cli/src/device.rs b/crates/uad-cli/src/device.rs
new file mode 100644
index 0000000..ddc23a9
--- /dev/null
+++ b/crates/uad-cli/src/device.rs
@@ -0,0 +1,45 @@
+use uad_core::sync::{Phone, User, get_devices_list};
+
+/// Get target device, either by serial or first available
+pub fn get_target_device(device: Option) -> Result> {
+ let devices = get_devices_list();
+
+ if devices.is_empty() {
+ eprintln!("Error: No devices found");
+ return Err("No devices found".into());
+ }
+
+ let target_device = if let Some(device_id) = device {
+ devices
+ .iter()
+ .find(|d| d.adb_id == device_id)
+ .ok_or("Device not found")?
+ .clone()
+ } else {
+ if devices.len() > 1 {
+ eprintln!(
+ "Warning: Multiple devices found, using first one: {}",
+ devices[0].adb_id
+ );
+ }
+ devices[0].clone()
+ };
+
+ Ok(target_device)
+}
+
+/// Get user from device, creating a basic one if not found
+pub fn get_user(device: &Phone, user_id: Option) -> Result> {
+ let uid = user_id.unwrap_or(0);
+
+ if let Some(user) = device.user_list.iter().find(|u| u.id == uid) {
+ Ok(*user)
+ } else {
+ // Create a basic user if not found in list
+ Ok(User {
+ id: uid,
+ index: 0,
+ protected: false,
+ })
+ }
+}
diff --git a/crates/uad-cli/src/filters.rs b/crates/uad-cli/src/filters.rs
new file mode 100644
index 0000000..5ae156f
--- /dev/null
+++ b/crates/uad-cli/src/filters.rs
@@ -0,0 +1,98 @@
+use clap::ValueEnum;
+use uad_core::adb::PmListPacksFlag;
+use uad_core::uad_lists::{Package, PackageState, Removal, UadList};
+
+#[derive(Debug, Clone, Copy, ValueEnum)]
+pub enum StateFilter {
+ /// Show all packages regardless of state
+ All,
+ /// Show only enabled packages
+ Enabled,
+ /// Show only disabled packages
+ Disabled,
+ /// Show only uninstalled packages
+ Uninstalled,
+}
+
+#[derive(Debug, Clone, Copy, ValueEnum)]
+pub enum RemovalFilter {
+ All,
+ Recommended,
+ Advanced,
+ Expert,
+ Unsafe,
+ Unlisted,
+}
+
+#[derive(Debug, Clone, Copy, ValueEnum)]
+pub enum ListFilter {
+ All,
+ Aosp,
+ Carrier,
+ Google,
+ Misc,
+ Oem,
+ Pending,
+ Unlisted,
+}
+
+impl StateFilter {
+ pub fn to_pm_flag(self) -> Option {
+ match self {
+ Self::Enabled => Some(PmListPacksFlag::OnlyEnabled),
+ Self::Disabled => Some(PmListPacksFlag::OnlyDisabled),
+ Self::Uninstalled | Self::All => Some(PmListPacksFlag::IncludeUninstalled),
+ }
+ }
+
+ pub fn matches(self, pkg_state: PackageState) -> bool {
+ match self {
+ Self::All => true,
+ Self::Enabled => pkg_state == PackageState::Enabled,
+ Self::Disabled => pkg_state == PackageState::Disabled,
+ Self::Uninstalled => pkg_state == PackageState::Uninstalled,
+ }
+ }
+
+ pub fn is_specific(self) -> bool {
+ matches!(self, Self::Enabled | Self::Disabled | Self::Uninstalled)
+ }
+}
+
+impl RemovalFilter {
+ pub fn matches(self, pkg_info: Option<&Package>) -> bool {
+ match pkg_info {
+ Some(info) => match self {
+ Self::All => true,
+ Self::Recommended => info.removal == Removal::Recommended,
+ Self::Advanced => info.removal == Removal::Advanced,
+ Self::Expert => info.removal == Removal::Expert,
+ Self::Unsafe => info.removal == Removal::Unsafe,
+ Self::Unlisted => info.removal == Removal::Unlisted,
+ },
+ None => matches!(self, Self::All | Self::Unlisted),
+ }
+ }
+
+ pub fn is_specific(self) -> bool {
+ !matches!(self, Self::All)
+ }
+}
+
+impl ListFilter {
+ pub fn matches(self, pkg_info: Option<&Package>) -> bool {
+ match pkg_info {
+ Some(info) => match self {
+ Self::All => true,
+ Self::Aosp => info.list == UadList::Aosp,
+ Self::Carrier => info.list == UadList::Carrier,
+ Self::Google => info.list == UadList::Google,
+ Self::Misc => info.list == UadList::Misc,
+ Self::Oem => info.list == UadList::Oem,
+ Self::Pending => info.list == UadList::Pending,
+ Self::Unlisted => info.list == UadList::Unlisted,
+ },
+ None => matches!(self, Self::All | Self::Unlisted),
+ }
+ }
+}
diff --git a/crates/uad-cli/src/main.rs b/crates/uad-cli/src/main.rs
new file mode 100644
index 0000000..e849e68
--- /dev/null
+++ b/crates/uad-cli/src/main.rs
@@ -0,0 +1,232 @@
+#![allow(
+ clippy::needless_continue,
+ clippy::collapsible_if,
+ clippy::uninlined_format_args,
+ clippy::map_unwrap_or,
+ clippy::unnecessary_wraps,
+ reason = "Suppress non-critical pedantic/style lints to keep build green"
+)]
+
+use clap::{Parser, Subcommand};
+use clap_complete::Shell;
+use uad_core::uad_lists::PackageState;
+
+mod commands;
+mod device;
+mod filters;
+mod output;
+mod repl;
+
+use filters::{ListFilter, RemovalFilter, StateFilter};
+
+#[derive(Parser)]
+#[command(name = "uad")]
+#[command(about = "Universal Android Debloater - Command Line Interface", long_about = None)]
+#[command(version)]
+#[command(propagate_version = true)]
+pub struct Cli {
+ #[command(subcommand)]
+ command: Commands,
+}
+
+#[derive(Subcommand)]
+enum Commands {
+ /// List connected Android devices
+ Devices,
+
+ /// List packages on a device
+ #[command(name = "list", visible_alias = "ls")]
+ List {
+ /// Device serial number (optional, uses first device if not specified)
+ #[arg(short, long)]
+ device: Option,
+
+ /// Filter by package state
+ #[arg(short, long, value_enum)]
+ state: Option,
+
+ /// Filter by removal category
+ #[arg(short, long, value_enum)]
+ removal: Option,
+
+ /// Filter by UAD list
+ #[arg(short, long, value_enum)]
+ list: Option,
+
+ /// Search pattern (matches package name or description)
+ #[arg(short = 'q', long)]
+ search: Option,
+
+ /// User ID (defaults to 0)
+ #[arg(short, long)]
+ user: Option,
+ },
+
+ /// Uninstall packages (default removal action)
+ #[command(visible_alias = "rm")]
+ Uninstall {
+ /// Package names to uninstall
+ packages: Vec,
+
+ /// Device serial number (optional, uses first device if not specified)
+ #[arg(short, long)]
+ device: Option,
+
+ /// User ID (defaults to 0)
+ #[arg(short, long)]
+ user: Option,
+
+ /// Dry run - show what would be done without actually doing it
+ #[arg(long)]
+ dry_run: bool,
+ },
+
+ /// Restore (reinstall) packages
+ #[command(visible_alias = "restore")]
+ Enable {
+ /// Package names to restore/enable
+ packages: Vec,
+
+ /// Device serial number (optional, uses first device if not specified)
+ #[arg(short, long)]
+ device: Option,
+
+ /// User ID (defaults to 0)
+ #[arg(short, long)]
+ user: Option,
+
+ /// Dry run - show what would be done without actually doing it
+ #[arg(long)]
+ dry_run: bool,
+ },
+
+ /// Disable packages (keeps data but prevents execution)
+ Disable {
+ /// Package names to disable
+ packages: Vec,
+
+ /// Device serial number (optional, uses first device if not specified)
+ #[arg(short, long)]
+ device: Option,
+
+ /// User ID (defaults to 0)
+ #[arg(short, long)]
+ user: Option,
+
+ /// Dry run - show what would be done without actually doing it
+ #[arg(long)]
+ dry_run: bool,
+ },
+
+ /// Show detailed information about a package
+ Info {
+ /// Package name
+ package: String,
+
+ /// Device serial number (optional, uses first device if not specified)
+ #[arg(short, long)]
+ device: Option,
+ },
+
+ /// Update UAD package lists from remote repository
+ Update,
+
+ /// Generate shell completion script
+ Completions {
+ /// Shell to generate completions for
+ #[arg(value_enum)]
+ shell: Shell,
+ },
+
+ /// Start interactive REPL mode
+ #[command(visible_alias = "shell")]
+ Repl {
+ /// Device serial number (optional, uses first device if not specified)
+ #[arg(short, long)]
+ device: Option,
+
+ /// User ID (defaults to 0)
+ #[arg(short, long)]
+ user: Option,
+ },
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let cli = Cli::parse();
+
+ match cli.command {
+ Commands::Devices => {
+ commands::list_devices()?;
+ }
+ Commands::List {
+ device,
+ state,
+ removal,
+ list,
+ search,
+ user,
+ } => {
+ commands::list_packages(device, state, removal, list, search, user)?;
+ }
+ Commands::Uninstall {
+ packages,
+ device,
+ user,
+ dry_run,
+ } => {
+ commands::change_package_state(
+ &packages,
+ device,
+ user,
+ dry_run,
+ PackageState::Uninstalled,
+ "Uninstalling",
+ )?;
+ }
+ Commands::Enable {
+ packages,
+ device,
+ user,
+ dry_run,
+ } => {
+ commands::change_package_state(
+ &packages,
+ device,
+ user,
+ dry_run,
+ PackageState::Enabled,
+ "Enabling",
+ )?;
+ }
+ Commands::Disable {
+ packages,
+ device,
+ user,
+ dry_run,
+ } => {
+ commands::change_package_state(
+ &packages,
+ device,
+ user,
+ dry_run,
+ PackageState::Disabled,
+ "Disabling",
+ )?;
+ }
+ Commands::Info { package, device } => {
+ commands::show_package_info(&package, device)?;
+ }
+ Commands::Update => {
+ commands::update_lists()?;
+ }
+ Commands::Completions { shell } => {
+ commands::generate_completions(shell);
+ }
+ Commands::Repl { device, user } => {
+ repl::repl_mode(device, user)?;
+ }
+ }
+
+ Ok(())
+}
diff --git a/crates/uad-cli/src/output.rs b/crates/uad-cli/src/output.rs
new file mode 100644
index 0000000..cff4724
--- /dev/null
+++ b/crates/uad-cli/src/output.rs
@@ -0,0 +1,18 @@
+/// Helper macro to handle broken pipe errors gracefully
+/// When piping to commands like `head`, we want to exit cleanly when the pipe closes
+#[macro_export]
+macro_rules! println_or_exit {
+ () => {
+ let _ = writeln!(std::io::stdout());
+ };
+ ($($arg:tt)*) => {
+ let _ = writeln!(std::io::stdout(), $($arg)*);
+ };
+}
+
+#[macro_export]
+macro_rules! print_or_exit {
+ ($($arg:tt)*) => {
+ let _ = write!(std::io::stdout(), $($arg)*);
+ };
+}
diff --git a/crates/uad-cli/src/repl.rs b/crates/uad-cli/src/repl.rs
new file mode 100644
index 0000000..0e78b6c
--- /dev/null
+++ b/crates/uad-cli/src/repl.rs
@@ -0,0 +1,369 @@
+use rustyline::DefaultEditor;
+use rustyline::error::ReadlineError;
+use std::collections::HashMap;
+use std::io::Write;
+use uad_core::adb::ACommand;
+use uad_core::sync::{CorePackage, Phone, User, apply_pkg_state_commands, get_package_state};
+use uad_core::uad_lists::{Package, PackageState, Removal, UadList, load_debloat_lists};
+
+use crate::commands::{PackageListContext, display_package_list, execute_with_fallback};
+use crate::device::{get_target_device, get_user};
+use crate::filters::StateFilter;
+use crate::println_or_exit;
+
+/// Start interactive REPL mode
+pub fn repl_mode(
+ device: Option,
+ user_id: Option,
+) -> Result<(), Box> {
+ println!("Universal Android Debloater - Interactive Mode");
+ println!("Type 'help' for available commands, 'exit' or 'quit' to leave\n");
+
+ let target_device = get_target_device(device)?;
+ let user = get_user(&target_device, user_id)?;
+
+ println!(
+ "Connected to: {} ({})",
+ target_device.model, target_device.adb_id
+ );
+ println!("User: {}\n", user.id);
+
+ let uad_lists = load_debloat_lists(false).unwrap_or_else(|lists| lists);
+ let mut rl = DefaultEditor::new()?;
+
+ // Try to load history
+ let history_file = dirs::cache_dir().map(|d| d.join("uad").join("cli_history.txt"));
+ if let Some(ref path) = history_file {
+ let _ = rl.load_history(path);
+ }
+
+ loop {
+ let readline = rl.readline("uad> ");
+ match readline {
+ Ok(line) => {
+ if let Err(e) =
+ handle_repl_line(&line, &mut rl, &target_device, user, user_id, &uad_lists)
+ {
+ if e.to_string() == "exit" {
+ break;
+ }
+ eprintln!("Error: {}", e);
+ }
+ }
+ Err(ReadlineError::Interrupted) => {
+ println!("Interrupted (Ctrl-C). Type 'exit' to quit.");
+ continue;
+ }
+ Err(ReadlineError::Eof) => {
+ println!("Goodbye!");
+ break;
+ }
+ Err(err) => {
+ eprintln!("Error: {:?}", err);
+ break;
+ }
+ }
+ }
+
+ // Save history
+ if let Some(ref path) = history_file {
+ if let Some(parent) = path.parent() {
+ let _ = std::fs::create_dir_all(parent);
+ }
+ let _ = rl.save_history(path);
+ }
+
+ Ok(())
+}
+
+/// Handle a single line of REPL input
+fn handle_repl_line(
+ line: &str,
+ rl: &mut DefaultEditor,
+ device: &Phone,
+ user: User,
+ user_id: Option,
+ uad_lists: &HashMap,
+) -> Result<(), Box> {
+ let line = line.trim();
+ if line.is_empty() {
+ return Ok(());
+ }
+
+ let _ = rl.add_history_entry(line);
+
+ let parts: Vec<&str> = line.split_whitespace().collect();
+ if parts.is_empty() {
+ return Ok(());
+ }
+
+ match parts[0] {
+ "help" => print_repl_help(),
+ "exit" | "quit" => {
+ println!("Goodbye!");
+ return Err("exit".into());
+ }
+ "list" | "ls" => {
+ handle_list_command(&parts[1..], device, user_id, uad_lists)?;
+ }
+ "info" => {
+ handle_info_command(&parts[1..], device, uad_lists)?;
+ }
+ "uninstall" | "rm" => {
+ handle_state_change_command(
+ &parts[1..],
+ device,
+ user,
+ PackageState::Uninstalled,
+ "Uninstalling",
+ uad_lists,
+ )?;
+ }
+ "enable" | "restore" => {
+ handle_state_change_command(
+ &parts[1..],
+ device,
+ user,
+ PackageState::Enabled,
+ "Enabling",
+ uad_lists,
+ )?;
+ }
+ "disable" => {
+ handle_state_change_command(
+ &parts[1..],
+ device,
+ user,
+ PackageState::Disabled,
+ "Disabling",
+ uad_lists,
+ )?;
+ }
+ "device" => {
+ println!(
+ "Device: {} ({}), Android SDK: {}, User: {}",
+ device.model, device.adb_id, device.android_sdk, user.id
+ );
+ }
+ "clear" => {
+ print!("\x1B[2J\x1B[1;1H");
+ }
+ _ => {
+ eprintln!(
+ "Unknown command: '{}'. Type 'help' for available commands.",
+ parts[0]
+ );
+ }
+ }
+
+ Ok(())
+}
+
+/// Parse REPL arguments into filters
+struct ReplListArgs {
+ state_filter: Option,
+ search_term: Option,
+}
+
+impl ReplListArgs {
+ fn parse(args: &[&str]) -> Result {
+ let mut state_filter = None;
+ let mut search_term = None;
+ let mut i = 0;
+
+ while i < args.len() {
+ match args[i] {
+ "--state" | "-s" => {
+ if i + 1 >= args.len() {
+ return Err("--state requires a value".to_string());
+ }
+ state_filter = match args[i + 1].to_lowercase().as_str() {
+ "enabled" => Some(StateFilter::Enabled),
+ "disabled" => Some(StateFilter::Disabled),
+ "uninstalled" => Some(StateFilter::Uninstalled),
+ "all" => Some(StateFilter::All),
+ _ => return Err(format!("Invalid state: {}", args[i + 1])),
+ };
+ i += 2;
+ }
+ "--search" | "-q" => {
+ if i + 1 >= args.len() {
+ return Err("--search requires a value".to_string());
+ }
+ search_term = Some(args[i + 1].to_string());
+ i += 2;
+ }
+ _ => {
+ return Err(format!("Unknown option: {}", args[i]));
+ }
+ }
+ }
+
+ Ok(Self {
+ state_filter,
+ search_term,
+ })
+ }
+}
+
+/// Handle list command in REPL
+fn handle_list_command(
+ args: &[&str],
+ device: &Phone,
+ user_id: Option,
+ uad_lists: &HashMap,
+) -> Result<(), Box> {
+ let parsed = ReplListArgs::parse(args)?;
+
+ let pm_flag = parsed.state_filter.and_then(StateFilter::to_pm_flag);
+ let system_packages = ACommand::new()
+ .shell(&device.adb_id)
+ .pm()
+ .list_packages_sys(pm_flag, user_id)?;
+
+ let context = PackageListContext {
+ state_filter: parsed.state_filter,
+ removal_filter: None,
+ list_filter: None,
+ search: parsed.search_term,
+ };
+
+ let displayed_count = display_package_list(
+ &system_packages,
+ uad_lists,
+ &device.adb_id,
+ user_id,
+ &context,
+ )?;
+
+ if displayed_count == 0 {
+ println_or_exit!(" No packages found.");
+ } else {
+ println_or_exit!("\nTotal: {} package(s)", displayed_count);
+ }
+
+ Ok(())
+}
+
+/// Handle info command in REPL
+fn handle_info_command(
+ args: &[&str],
+ device: &Phone,
+ uad_lists: &HashMap,
+) -> Result<(), Box> {
+ if args.is_empty() {
+ eprintln!("Usage: info ");
+ return Ok(());
+ }
+
+ let package = args[0];
+ println!("Package: {}", package);
+
+ if let Some(pkg_info) = uad_lists.get(package) {
+ println!(" List: {}", pkg_info.list);
+ println!(" Removal: {}", pkg_info.removal);
+ println!(" Description: {}", pkg_info.description);
+ } else {
+ println!(" Not found in UAD lists (unlisted package)");
+ }
+
+ let state =
+ get_package_state(&device.adb_id, package, None).ok_or("Package not found on device")?;
+ println!(" State: {}", state);
+
+ Ok(())
+}
+
+/// Handle state change command in REPL
+fn handle_state_change_command(
+ args: &[&str],
+ device: &Phone,
+ user: User,
+ target_state: PackageState,
+ action_name: &str,
+ uad_lists: &HashMap,
+) -> Result<(), Box> {
+ if args.is_empty() {
+ eprintln!(
+ "Usage: {} [package_name...]",
+ action_name.to_lowercase()
+ );
+ return Ok(());
+ }
+
+ for pkg_name in args {
+ process_package_change(pkg_name, device, user, target_state, action_name, uad_lists)?;
+ }
+
+ Ok(())
+}
+
+/// Process state change for a single package in REPL
+fn process_package_change(
+ pkg_name: &str,
+ device: &Phone,
+ user: User,
+ target_state: PackageState,
+ action_name: &str,
+ uad_lists: &HashMap,
+) -> Result<(), Box> {
+ let current_state = get_package_state(&device.adb_id, pkg_name, Some(user.id))
+ .ok_or("Package not found on device")?;
+
+ println!("{} {} (current: {})", action_name, pkg_name, current_state);
+
+ if current_state == target_state {
+ println!(" → Already in target state, skipping");
+ return Ok(());
+ }
+
+ let pkg_info = uad_lists.get(pkg_name);
+ if let Some(info) = pkg_info {
+ if info.removal == Removal::Unsafe {
+ println!(" ⚠ WARNING: This package is marked as UNSAFE to remove!");
+ }
+ }
+
+ let core_pkg = CorePackage {
+ name: pkg_name.to_string(),
+ description: pkg_info.map(|p| p.description.clone()).unwrap_or_default(),
+ removal: pkg_info.map(|p| p.removal).unwrap_or(Removal::Unlisted),
+ state: current_state,
+ list: pkg_info.map(|p| p.list).unwrap_or(UadList::Unlisted),
+ };
+
+ let commands = apply_pkg_state_commands(&core_pkg, target_state, user, device);
+
+ execute_with_fallback(
+ pkg_name,
+ target_state,
+ &core_pkg,
+ user,
+ device,
+ &commands,
+ " ",
+ )
+}
+
+/// Print REPL help message
+fn print_repl_help() {
+ println!("Available commands:");
+ println!(" list [--state ] [--search ]");
+ println!(" List packages with optional filters");
+ println!(" info ");
+ println!(" Show information about a package");
+ println!(" uninstall [package_name...]");
+ println!(" Uninstall one or more packages");
+ println!(" enable [package_name...]");
+ println!(" Enable/restore one or more packages");
+ println!(" disable [package_name...]");
+ println!(" Disable one or more packages");
+ println!(" device");
+ println!(" Show current device information");
+ println!(" clear");
+ println!(" Clear the screen");
+ println!(" help");
+ println!(" Show this help message");
+ println!(" exit, quit");
+ println!(" Exit the interactive mode");
+}
diff --git a/crates/uad-core/Cargo.toml b/crates/uad-core/Cargo.toml
new file mode 100644
index 0000000..b73d746
--- /dev/null
+++ b/crates/uad-core/Cargo.toml
@@ -0,0 +1,56 @@
+[package]
+name = "uad-core"
+version.workspace = true
+authors.workspace = true
+license.workspace = true
+homepage.workspace = true
+repository.workspace = true
+readme.workspace = true
+keywords.workspace = true
+categories = ["command-line-utilities"]
+edition.workspace = true
+
+[features]
+default = []
+gui = ["dep:iced", "dep:dark-light"]
+self-update = ["dep:flate2", "dep:tar"]
+
+[dependencies]
+serde.workspace = true
+serde_json.workspace = true
+log.workspace = true
+chrono.workspace = true
+toml.workspace = true
+dirs.workspace = true
+ureq.workspace = true
+retry.workspace = true
+csv.workspace = true
+iced = { workspace = true, optional = true }
+dark-light = { workspace = true, optional = true }
+flate2 = { workspace = true, optional = true }
+tar = { workspace = true, optional = true }
+
+[target.'cfg(target_os = "windows")'.dependencies]
+win32console.workspace = true
+
+[lints.rust]
+deprecated_safe = "warn"
+
+[lints.clippy]
+undocumented_unsafe_blocks = "forbid"
+exit = "deny"
+panic_in_result_fn = "warn"
+infinite_loop = "warn"
+mem_forget = "warn"
+implicit_clone = "warn"
+format_push_string = "warn"
+large_include_file = "warn"
+shadow_unrelated = "warn"
+struct_field_names = "allow" # annoying
+module_name_repetitions = "allow" # annoying
+
+disallowed_types = "deny"
+disallowed_methods = "deny"
+
+allow_attributes_without_reason = "warn"
+pedantic = { level = "warn", priority = -1 }
diff --git a/src/core/adb.rs b/crates/uad-core/src/adb.rs
similarity index 98%
rename from src/core/adb.rs
rename to crates/uad-core/src/adb.rs
index ecb112c..8d06268 100644
--- a/src/core/adb.rs
+++ b/crates/uad-core/src/adb.rs
@@ -43,16 +43,18 @@ use serde::{Deserialize, Serialize};
#[cfg(target_os = "windows")]
use std::os::windows::process::CommandExt;
-use crate::core::utils::is_all_w_c;
+use crate::utils::is_all_w_c;
+use log::{error, info};
/// Convert ADB output bytes to a trimmed UTF-8 string.
/// Uses lossy conversion to prevent panics on non-UTF8 output from certain OEMs.
+#[must_use]
pub fn to_trimmed_utf8(v: &[u8]) -> String {
String::from_utf8_lossy(v).trim_end().to_string()
}
-#[must_use]
#[cfg(debug_assertions)]
+#[must_use]
fn is_version_triple(s: &str) -> bool {
let mut components = s.split('.');
for _ in 0..3 {
@@ -213,6 +215,12 @@ impl ACommand {
}
}
+impl Default for ACommand {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
/// Builder object for a command that runs on the device's default `sh` implementation.
/// Typically MKSH, but could be Ash.
///
@@ -221,6 +229,7 @@ impl ACommand {
pub struct ShellCommand(ACommand);
impl ShellCommand {
/// `pm` command builder
+ #[must_use]
pub fn pm(mut self) -> PmCommand {
self.0.0.arg("pm");
PmCommand(self)
@@ -273,6 +282,7 @@ impl PackageId {
/// Creates a package-ID if it's valid according to:
/// -
/// -
+ #[must_use]
pub fn new(p_id: Box) -> Option {
let mut components = p_id.split('.');
for _ in 0..2 {
diff --git a/src/core/config.rs b/crates/uad-core/src/config.rs
similarity index 86%
rename from src/core/config.rs
rename to crates/uad-core/src/config.rs
index f2329a4..eebfc63 100644
--- a/src/core/config.rs
+++ b/crates/uad-core/src/config.rs
@@ -1,8 +1,8 @@
use crate::CACHE_DIR;
use crate::CONFIG_DIR;
-use crate::core::utils::DisplayablePath;
-use crate::core::{sync::User, theme::Theme};
-use crate::gui::views::settings::Settings;
+use crate::utils::DisplayablePath;
+use crate::{sync::User, theme::Theme};
+use log::error;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
@@ -54,23 +54,26 @@ impl Default for GeneralSettings {
static CONFIG_FILE: LazyLock = LazyLock::new(|| CONFIG_DIR.join("config.toml"));
impl Config {
- pub fn save_changes(settings: &Settings, device_id: &String) {
- let mut config = Self::load_configuration_file();
- if let Some(device) = config
+ pub fn save_device_settings(
+ &mut self,
+ device_settings: DeviceSettings,
+ general: GeneralSettings,
+ ) {
+ if let Some(device) = self
.devices
.iter_mut()
- .find(|x| x.device_id == *device_id)
+ .find(|x| x.device_id == device_settings.device_id)
{
- device.clone_from(&settings.device);
+ *device = device_settings;
} else {
- debug!("config: New device settings saved");
- config.devices.push(settings.device.clone());
+ self.devices.push(device_settings);
}
- config.general.clone_from(&settings.general);
- let toml = toml::to_string(&config).unwrap();
+ self.general = general;
+ let toml = toml::to_string(&self).unwrap();
fs::write(&*CONFIG_FILE, toml).expect("Could not write config file to disk!");
}
+ #[must_use]
pub fn load_configuration_file() -> Self {
match fs::read_to_string(&*CONFIG_FILE) {
Ok(s) => match toml::from_str(&s) {
diff --git a/crates/uad-core/src/lib.rs b/crates/uad-core/src/lib.rs
new file mode 100644
index 0000000..76b1271
--- /dev/null
+++ b/crates/uad-core/src/lib.rs
@@ -0,0 +1,24 @@
+#![allow(
+ clippy::missing_panics_doc,
+ clippy::missing_errors_doc,
+ clippy::collapsible_if,
+ clippy::uninlined_format_args,
+ clippy::result_unit_err,
+ reason = "Doc+style pedantic lints are out-of-scope for this pass"
+)]
+
+pub mod adb;
+pub mod config;
+pub mod save;
+pub mod sync;
+pub mod theme;
+pub mod uad_lists;
+pub mod update;
+pub mod utils;
+
+use std::path::PathBuf;
+use std::sync::LazyLock;
+pub static CONFIG_DIR: LazyLock =
+ LazyLock::new(|| utils::setup_uad_dir(&dirs::config_dir().expect("Can't detect config dir")));
+pub static CACHE_DIR: LazyLock =
+ LazyLock::new(|| utils::setup_uad_dir(&dirs::cache_dir().expect("Can't detect cache dir")));
diff --git a/src/core/save.rs b/crates/uad-core/src/save.rs
similarity index 90%
rename from src/core/save.rs
rename to crates/uad-core/src/save.rs
index 7be7084..8c1db07 100644
--- a/src/core/save.rs
+++ b/crates/uad-core/src/save.rs
@@ -1,7 +1,6 @@
-use crate::core::config::{Config, DeviceSettings};
-use crate::core::sync::{CorePackage, Phone, User, apply_pkg_state_commands};
-use crate::core::utils::DisplayablePath;
-use crate::gui::widgets::package_row::PackageRow;
+use crate::config::{Config, DeviceSettings};
+use crate::sync::{CorePackage, Phone, User, apply_pkg_state_commands};
+use crate::utils::DisplayablePath;
use log::{error, info, warn};
use serde::{Deserialize, Serialize};
use std::{
@@ -22,10 +21,10 @@ pub struct UserBackup {
}
/// Backup all `Uninstalled` and `Disabled` packages
-pub async fn backup_phone(
+pub fn backup_phone(
users: Vec,
device_id: String,
- phone_packages: Vec>,
+ phone_packages: &[Vec],
) -> Result {
let mut backup = PhoneBackup {
device_id: device_id.clone(),
@@ -38,11 +37,8 @@ pub async fn backup_phone(
..UserBackup::default()
};
- for p in phone_packages[u.index].clone() {
- user_backup.packages.push(CorePackage {
- name: p.name.clone(),
- state: p.state,
- });
+ for p in phone_packages[u.index].iter().cloned() {
+ user_backup.packages.push(p);
}
backup.users.push(user_backup);
}
@@ -79,6 +75,7 @@ pub fn list_available_backups(dir: &Path) -> Vec {
}
}
+#[must_use]
pub fn list_available_backup_user(backup: DisplayablePath) -> Vec {
match fs::read_to_string(backup.path) {
Ok(data) => serde_json::from_str::(&data)
@@ -113,7 +110,7 @@ pub struct RestoreResult {
pub fn restore_backup(
selected_device: &Phone,
- packages: &[Vec],
+ packages: &[Vec],
settings: &DeviceSettings,
) -> Result {
match fs::read_to_string(
@@ -142,7 +139,7 @@ pub fn restore_backup(
.iter()
.find(|x| x.name == backup_package.name)
{
- p.into()
+ p.clone()
} else {
skipped_packages += 1;
warn!(
diff --git a/src/core/sync.rs b/crates/uad-core/src/sync.rs
similarity index 77%
rename from src/core/sync.rs
rename to crates/uad-core/src/sync.rs
index 932c006..fe83788 100644
--- a/src/core/sync.rs
+++ b/crates/uad-core/src/sync.rs
@@ -1,8 +1,8 @@
-use crate::core::{
+use crate::{
adb::{ACommand as AdbCommand, PM_CLEAR_PACK},
uad_lists::PackageState,
};
-use crate::gui::{views::list::PackageInfo, widgets::package_row::PackageRow};
+use log::{error, info};
use retry::{OperationResult, delay::Fixed, retry};
use serde::{Deserialize, Serialize};
@@ -61,27 +61,25 @@ pub enum AdbError {
/// This replaces the deprecated `adb_shell_command`.
///
/// If `serial` is empty, it lets ADB choose the default device.
-pub async fn run_adb_action>(
+pub fn run_adb_shell_action>(
device_serial: S,
- action: String,
- p: PackageInfo,
-) -> Result {
+ action: &str,
+) -> Result {
let serial = device_serial.as_ref();
- let label = &p.removal;
- match AdbCommand::new().shell(serial).raw(&action) {
+ match AdbCommand::new().shell(serial).raw(action) {
Ok(o) => {
if ["Error", "Failure"].iter().any(|&e| o.contains(e)) {
- let friendly_msg = make_friendly_error_message(&o, &action);
- return Err(AdbError::Generic(format!("[{label}] {friendly_msg}")));
+ let friendly_msg = make_friendly_error_message(&o, action);
+ return Err(AdbError::Generic(friendly_msg));
}
- info!("[{label}] {action} -> {o}");
- Ok(p)
+ info!("{action} -> {o}");
+ Ok(o)
}
Err(err) => {
if !err.contains("[not installed for") {
- let friendly_msg = make_friendly_error_message(&err, &action);
- return Err(AdbError::Generic(format!("[{label}] {friendly_msg}")));
+ let friendly_msg = make_friendly_error_message(&err, action);
+ return Err(AdbError::Generic(friendly_msg));
}
Err(AdbError::Generic(err))
}
@@ -141,6 +139,7 @@ fn make_friendly_error_message(error_output: &str, action: &str) -> String {
}
/// If `None`, returns an empty String, not " --user 0"
+#[must_use]
pub fn user_flag(user_id: Option) -> String {
user_id
.map(|user| format!(" --user {}", user.id))
@@ -151,35 +150,16 @@ pub fn user_flag(user_id: Option) -> String {
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub struct CorePackage {
pub name: String,
+ pub description: String,
+ #[serde(default)]
+ pub removal: crate::uad_lists::Removal,
+ #[serde(default)]
pub state: PackageState,
+ #[serde(default)]
+ pub list: crate::uad_lists::UadList,
}
-impl From<&mut PackageRow> for CorePackage {
- fn from(pr: &mut PackageRow) -> Self {
- Self {
- name: pr.name.clone(),
- state: pr.state,
- }
- }
-}
-impl From for CorePackage {
- fn from(pr: PackageRow) -> Self {
- Self {
- name: pr.name.clone(),
- state: pr.state,
- }
- }
-}
-
-impl From<&PackageRow> for CorePackage {
- fn from(pr: &PackageRow) -> Self {
- Self {
- name: pr.name.clone(),
- state: pr.state,
- }
- }
-}
-
+#[must_use]
pub fn apply_pkg_state_commands(
package: &CorePackage,
wanted_state: PackageState,
@@ -224,6 +204,7 @@ pub fn apply_pkg_state_commands(
/// Build a command request to be sent via ADB to a device.
/// `commands` accepts one or more ADB shell commands
/// which act on a common `package` and `user`.
+#[must_use]
pub fn request_builder(commands: &[&str], package: &str, user: Option) -> Vec {
let maybe_user_flag = user_flag(user);
commands
@@ -235,6 +216,7 @@ pub fn request_builder(commands: &[&str], package: &str, user: Option) ->
/// Get the model by querying the `ro.product.model` property.
///
/// If `serial` is empty, it lets ADB choose the default device.
+#[must_use]
pub fn get_device_model(serial: &str) -> String {
AdbCommand::new()
.shell(serial)
@@ -253,6 +235,7 @@ pub fn get_device_model(serial: &str) -> String {
/// Get the brand by querying the `ro.product.brand` property.
///
/// If `serial` is empty, it lets ADB choose the default device.
+#[must_use]
pub fn get_device_brand(serial: &str) -> String {
AdbCommand::new()
.shell(serial)
@@ -266,6 +249,7 @@ pub fn get_device_brand(serial: &str) -> String {
// `ro.build.version.sdk` property or defaulting to 0.
///
/// If `device_serial` is empty, it lets ADB choose the default device.
+#[must_use]
pub fn get_android_sdk(device_serial: &str) -> u8 {
AdbCommand::new()
.shell(device_serial)
@@ -280,6 +264,7 @@ pub fn get_android_sdk(device_serial: &str) -> u8 {
///
/// Only includes users where the package exists (Some state). Users where the package
/// doesn't exist (None) are not tracked.
+#[must_use]
pub fn capture_cross_user_states(
package_name: &str,
device_serial: &str,
@@ -301,6 +286,7 @@ pub fn capture_cross_user_states(
/// - Case A: Uninstall → Restore (package appears on other users)
/// - Case B: Uninstall → Uninstall (package disappears from other users that previously had it)
/// - Case C: Restore → Restore (package appears on other users)
+#[must_use]
pub fn detect_cross_user_behavior(
package_name: &str,
device_serial: &str,
@@ -433,6 +419,7 @@ pub fn is_protected_user>(user_id: u16, device_serial: S) -> bool
.is_err()
}
+#[must_use]
pub fn list_users_idx_prot(device_serial: &str) -> Vec {
AdbCommand::new()
.shell(device_serial)
@@ -456,9 +443,10 @@ pub fn list_users_idx_prot(device_serial: &str) -> Vec {
/// This matches serials (`getprop ro.serialno`)
/// that are authorized by the user.
-pub async fn get_devices_list() -> Vec {
+#[must_use]
+pub fn get_devices_list() -> Vec {
retry(
- Fixed::from_millis(500).take(if cfg!(debug_assertions) { 3 } else { 120 }),
+ Fixed::from_millis(500).take(if cfg!(debug_assertions) { 3 } else { 10 }),
|| match AdbCommand::new().devices() {
Ok(devices) => {
let mut device_list: Vec = vec![];
@@ -486,20 +474,22 @@ pub async fn get_devices_list() -> Vec {
.unwrap_or_default()
}
-pub async fn initial_load() -> bool {
+#[must_use]
+pub fn initial_load() -> bool {
match AdbCommand::new().devices() {
Ok(_devices) => true,
Err(_err) => false,
}
}
-/// Verify the actual state of a package on the device
-pub fn verify_package_state(
- package_name: &str,
+/// Get the current state of a package on a device
+#[must_use]
+pub fn get_package_state(
device_serial: &str,
+ package_name: &str,
user_id: Option,
) -> Option {
- use crate::core::adb::{ACommand as AdbCommand, PmListPacksFlag};
+ use crate::adb::{ACommand as AdbCommand, PmListPacksFlag};
// Check if package is enabled
if let Ok(enabled_packages) = AdbCommand::new()
@@ -535,11 +525,23 @@ pub fn verify_package_state(
None
}
+/// Verify the current state of a package on a device.
+/// Returns the package state, or `None` if the package doesn't exist.
+#[must_use]
+pub fn verify_package_state(
+ package_name: &str,
+ device_serial: &str,
+ user_id: Option,
+) -> Option {
+ get_package_state(device_serial, package_name, user_id)
+}
+
/// Check if a package exists on any other users besides the target user.
/// This helps detect OEM-specific cross-user restoration behavior.
///
/// Only includes users where the package exists in a non-uninstalled state
/// (i.e., Enabled or Disabled).
+#[must_use]
pub fn check_cross_user_package_existence(
package_name: &str,
device_serial: &str,
@@ -561,9 +563,29 @@ pub fn check_cross_user_package_existence(
other_user_states
}
+/// Creates a `CorePackage` with the specified state, preserving other fields from the original.
+fn package_with_state(package: &CorePackage, state: PackageState) -> CorePackage {
+ CorePackage {
+ state,
+ ..package.clone()
+ }
+}
+
+/// Executes the first available command and returns the result.
+fn execute_first_command(commands: &[String], phone: &Phone) -> Result<(), String> {
+ if commands.is_empty() {
+ return Err("No command available".to_string());
+ }
+ AdbCommand::new()
+ .shell(&phone.adb_id)
+ .raw(&commands[0])
+ .map(|_| ())
+ .map_err(|err| err.clone())
+}
+
/// Attempt fallback action when package state verification fails
pub fn attempt_fallback(
- package: &crate::gui::widgets::package_row::PackageRow,
+ package: &CorePackage,
wanted_state: PackageState,
actual_state: PackageState,
user: User,
@@ -572,101 +594,49 @@ pub fn attempt_fallback(
match (wanted_state, actual_state) {
// Case 1: Tried to uninstall but package was reinstalled -> disable it
(PackageState::Uninstalled, PackageState::Enabled) => {
- let core_package = CorePackage {
- name: package.name.clone(),
- state: PackageState::Enabled,
- };
- let commands =
- apply_pkg_state_commands(&core_package, PackageState::Disabled, user, phone);
-
- if commands.is_empty() {
- Err("No disable command available for this Android version".to_string())
- } else {
- // Execute the disable command
- let action = commands[0].clone();
- match AdbCommand::new().shell(&phone.adb_id).raw(&action) {
- Ok(_) => Ok("disabled package instead of uninstalling".to_string()),
- Err(err) => Err(format!("Failed to disable package: {err}")),
- }
- }
+ let pkg = package_with_state(package, PackageState::Enabled);
+ let commands = apply_pkg_state_commands(&pkg, PackageState::Disabled, user, phone);
+ execute_first_command(&commands, phone)
+ .map(|()| "disabled package instead of uninstalling".to_string())
+ .map_err(|e| format!("Failed to disable package: {e}"))
}
// Case 2: Tried to disable but package re-enabled itself -> try uninstall
(PackageState::Disabled, PackageState::Enabled) => {
- let core_package = CorePackage {
- name: package.name.clone(),
- state: PackageState::Enabled,
- };
- let commands =
- apply_pkg_state_commands(&core_package, PackageState::Uninstalled, user, phone);
+ let pkg = package_with_state(package, PackageState::Enabled);
+ let commands = apply_pkg_state_commands(&pkg, PackageState::Uninstalled, user, phone);
+ execute_first_command(&commands, phone)
+ .map_err(|e| format!("Failed to uninstall: {e}"))?;
- if commands.is_empty() {
- Err("No uninstall command available for this Android version".to_string())
- } else {
- // Execute the uninstall command
- let action = commands[0].clone();
- match AdbCommand::new().shell(&phone.adb_id).raw(&action) {
- Ok(_) => {
- // Verify the package was actually uninstalled
- match verify_package_state(&package.name, &phone.adb_id, Some(user.id)) {
- Some(PackageState::Uninstalled) | None => {
- Ok("uninstalled package instead of disabling".to_string())
- }
- _ => Err("Package still exists after uninstall attempt".to_string()),
- }
- }
- Err(err) => Err(format!("Failed to uninstall package: {err}")),
+ // Verify the package was actually uninstalled
+ match verify_package_state(&package.name, &phone.adb_id, Some(user.id)) {
+ Some(PackageState::Uninstalled) | None => {
+ Ok("uninstalled package instead of disabling".to_string())
}
+ _ => Err("Package still exists after uninstall attempt".to_string()),
}
}
// Case 3: Tried to enable but package was disabled -> try uninstall then reinstall
(PackageState::Enabled, PackageState::Disabled) => {
- // First try to uninstall
- let core_package = CorePackage {
- name: package.name.clone(),
- state: PackageState::Disabled,
- };
- let uninstall_commands =
- apply_pkg_state_commands(&core_package, PackageState::Uninstalled, user, phone);
+ let pkg = package_with_state(package, PackageState::Disabled);
+ let uninstall_cmds =
+ apply_pkg_state_commands(&pkg, PackageState::Uninstalled, user, phone);
+ execute_first_command(&uninstall_cmds, phone)
+ .map_err(|e| format!("Failed to uninstall for reinstall: {e}"))?;
- if uninstall_commands.is_empty() {
- Err("No uninstall command available for reinstall attempt".to_string())
- } else {
- let uninstall_action = uninstall_commands[0].clone();
- match AdbCommand::new()
- .shell(&phone.adb_id)
- .raw(&uninstall_action)
- {
- Ok(_) => {
- // Now try to reinstall/enable
- let core_package_uninstalled = CorePackage {
- name: package.name.clone(),
- state: PackageState::Uninstalled,
- };
- let enable_commands = apply_pkg_state_commands(
- &core_package_uninstalled,
- PackageState::Enabled,
- user,
- phone,
- );
+ // Now try to reinstall/enable
+ let pkg_uninstalled = package_with_state(package, PackageState::Uninstalled);
+ let enable_cmds =
+ apply_pkg_state_commands(&pkg_uninstalled, PackageState::Enabled, user, phone);
- if enable_commands.is_empty() {
- Ok("uninstalled package but couldn't reinstall".to_string())
- } else {
- let enable_action = enable_commands[0].clone();
- match AdbCommand::new().shell(&phone.adb_id).raw(&enable_action) {
- Ok(_) => {
- Ok("uninstalled and reinstalled package to enable it"
- .to_string())
- }
- Err(err) => Err(format!("Failed to reinstall package: {err}")),
- }
- }
- }
- Err(err) => Err(format!("Failed to uninstall package for reinstall: {err}")),
- }
+ if enable_cmds.is_empty() {
+ return Ok("uninstalled package but couldn't reinstall".to_string());
}
+
+ execute_first_command(&enable_cmds, phone)
+ .map(|()| "uninstalled and reinstalled package to enable it".to_string())
+ .map_err(|e| format!("Failed to reinstall package: {e}"))
}
// Other cases - no fallback available
diff --git a/src/core/theme.rs b/crates/uad-core/src/theme.rs
similarity index 92%
rename from src/core/theme.rs
rename to crates/uad-core/src/theme.rs
index 9dfcbb4..71a8cfe 100644
--- a/src/core/theme.rs
+++ b/crates/uad-core/src/theme.rs
@@ -1,6 +1,10 @@
+#[cfg(feature = "gui")]
use dark_light;
+#[cfg(feature = "gui")]
use iced::theme::{self, Mode, Palette, Style};
+#[cfg(feature = "gui")]
use iced::{Color, color};
+#[cfg(feature = "gui")]
use std::sync::LazyLock;
/*
@@ -12,6 +16,7 @@ Coincidentally, this also ensures consistent colors across the GUI,
at the cost of requiring a restart to update the palette.
(this is just a patch, not a fix)
*/
+#[cfg(feature = "gui")]
pub static OS_COLOR_SCHEME: LazyLock =
LazyLock::new(|| dark_light::detect().unwrap_or(dark_light::Mode::Unspecified));
@@ -29,12 +34,14 @@ pub enum Theme {
Light,
}
+#[cfg(feature = "gui")]
#[derive(Debug, Clone, Copy)]
pub struct BaseColors {
pub background: Color,
pub foreground: Color,
}
+#[cfg(feature = "gui")]
#[derive(Debug, Clone, Copy)]
pub struct NormalColors {
pub primary: Color,
@@ -44,6 +51,7 @@ pub struct NormalColors {
pub error: Color,
}
+#[cfg(feature = "gui")]
#[derive(Debug, Clone, Copy)]
pub struct BrightColors {
pub primary: Color,
@@ -52,6 +60,7 @@ pub struct BrightColors {
pub error: Color,
}
+#[cfg(feature = "gui")]
#[derive(Debug, Clone, Copy)]
pub struct ColorPalette {
pub base: BaseColors,
@@ -69,6 +78,7 @@ impl Theme {
/// This `fn` _could_ be `const`,
/// but `deref`ing a lazy-`static` is non-`const`.
#[must_use]
+ #[cfg(feature = "gui")]
pub fn palette(self) -> ColorPalette {
const DARK: ColorPalette = ColorPalette {
base: BaseColors {
@@ -151,6 +161,18 @@ impl std::fmt::Display for Theme {
}
}
+/// Converts a string to the GUI's Theme type
+#[must_use]
+pub fn string_to_theme(theme: &str) -> Theme {
+ match theme {
+ "Lupin" => Theme::Lupin,
+ "Dark" => Theme::Dark,
+ "Light" => Theme::Light,
+ _ => Theme::Auto,
+ }
+}
+
+#[cfg(feature = "gui")]
impl theme::Base for Theme {
fn default(preference: Mode) -> Self {
match preference {
diff --git a/src/core/uad_lists.rs b/crates/uad-core/src/uad_lists.rs
similarity index 95%
rename from src/core/uad_lists.rs
rename to crates/uad-core/src/uad_lists.rs
index fb1833c..35cade9 100644
--- a/src/core/uad_lists.rs
+++ b/crates/uad-core/src/uad_lists.rs
@@ -1,5 +1,6 @@
use crate::CACHE_DIR;
-use crate::core::utils::{format_diff_time_from_now, last_modified_date};
+use crate::utils::{format_diff_time_from_now, last_modified_date};
+use log::warn;
use retry::{OperationResult, delay::Fixed, retry};
use serde::{Deserialize, Serialize};
use serde_json;
@@ -15,7 +16,7 @@ pub const LIST_FNAME: &str = "uad_lists.json";
reason = "https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/discussions/608"
)]
// not `const`, because it's too big
-pub static DATA: &str = include_str!("../../resources/assets/uad_lists.json");
+pub static DATA: &str = include_str!("../../../resources/assets/uad_lists.json");
#[derive(Deserialize, Debug, Clone, PartialEq, Hash, Eq)]
#[serde(rename_all = "camelCase")]
@@ -28,7 +29,7 @@ pub struct Package {
pub removal: Removal,
}
-#[derive(Default, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Default, Deserialize, Serialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UadList {
#[default]
All,
@@ -73,6 +74,7 @@ impl UadList {
Self::Unlisted,
];
+ #[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::All => "All lists",
@@ -148,7 +150,7 @@ impl Opposite for PackageState {
}
// Bad names. To be changed!
-#[derive(Default, Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Default, Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Removal {
#[default]
Recommended,
@@ -176,6 +178,7 @@ impl Removal {
Self::Unlisted,
];
+ #[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::All => "All removals",
diff --git a/src/core/update.rs b/crates/uad-core/src/update.rs
similarity index 99%
rename from src/core/update.rs
rename to crates/uad-core/src/update.rs
index c92b3a8..51e52e4 100644
--- a/src/core/update.rs
+++ b/crates/uad-core/src/update.rs
@@ -1,9 +1,9 @@
-use crate::core::utils::NAME;
-
use serde::Deserialize;
#[cfg(feature = "self-update")]
use {
+ crate::utils::NAME,
+ log::{debug, error},
retry::{OperationResult, delay::Fibonacci, retry},
std::fs,
std::io,
diff --git a/src/core/utils.rs b/crates/uad-core/src/utils.rs
similarity index 80%
rename from src/core/utils.rs
rename to crates/uad-core/src/utils.rs
index e6a3fe1..0a89cdd 100644
--- a/src/core/utils.rs
+++ b/crates/uad-core/src/utils.rs
@@ -1,14 +1,14 @@
#![warn(clippy::unwrap_used)]
-use crate::core::{
+use crate::{
adb::{ACommand as AdbCommand, PmListPacksFlag},
- sync::User,
+ sync::{CorePackage, User},
theme::Theme,
uad_lists::{PackageHashMap, PackageState, Removal, UadList},
};
-use crate::gui::widgets::package_row::PackageRow;
use chrono::{DateTime, offset::Utc};
use csv::Writer;
+use log::error;
use std::{
collections::HashSet,
fmt, fs,
@@ -66,11 +66,12 @@ pub enum Error {
DialogClosed,
}
+#[must_use]
pub fn fetch_packages(
uad_lists: &PackageHashMap,
device_serial: &str,
user_id: Option,
-) -> Vec {
+) -> Vec {
let all_sys_packs = AdbCommand::new()
.shell(device_serial)
.pm()
@@ -92,24 +93,24 @@ pub fn fetch_packages(
.collect();
let mut description;
- let mut uad_list;
- let mut state;
let mut removal;
- let mut user_package: Vec = Vec::new();
+ let mut state;
+ let mut list;
+ let mut user_package: Vec = Vec::new();
for pack_name in all_sys_packs {
let p_name = &pack_name;
- state = PackageState::Uninstalled;
- description = "[No description]: CONTRIBUTION WELCOMED";
- uad_list = UadList::Unlisted;
+ description = String::from("[No description]: CONTRIBUTION WELCOMED");
removal = Removal::Unlisted;
+ state = PackageState::Uninstalled;
+ list = UadList::Unlisted;
if let Some(package) = uad_lists.get(p_name) {
if !package.description.is_empty() {
- description = &package.description;
+ description = package.description.clone();
}
- uad_list = package.list;
removal = package.removal;
+ list = package.list;
}
if enabled_sys_packs.contains(p_name) {
@@ -118,14 +119,20 @@ pub fn fetch_packages(
state = PackageState::Disabled;
}
- let package_row =
- PackageRow::new(p_name, state, description, uad_list, removal, false, false);
- user_package.push(package_row);
+ let package = CorePackage {
+ name: p_name.clone(),
+ description,
+ removal,
+ state,
+ list,
+ };
+ user_package.push(package);
}
user_package.sort_by_key(|a| a.name.to_lowercase());
user_package
}
+#[must_use]
pub fn string_to_theme(theme: &str) -> Theme {
match theme {
"Dark" => Theme::Dark,
@@ -137,6 +144,7 @@ pub fn string_to_theme(theme: &str) -> Theme {
}
}
+#[must_use]
pub fn setup_uad_dir(dir: &Path) -> PathBuf {
let dir = dir.join("uad");
if let Err(e) = fs::create_dir_all(&dir) {
@@ -173,6 +181,7 @@ pub fn open_url(dir: PathBuf) {
}
#[rustfmt::skip]
+#[must_use]
pub fn last_modified_date(file: PathBuf) -> DateTime {
fs::metadata(file).map_or_else(|_| Utc::now(), |metadata| match metadata.modified() {
Ok(time) => time.into(),
@@ -180,6 +189,7 @@ pub fn last_modified_date(file: PathBuf) -> DateTime {
})
}
+#[must_use]
pub fn format_diff_time_from_now(date: DateTime) -> String {
let now: DateTime = Utc::now();
let last_update = now - date;
@@ -194,15 +204,10 @@ pub fn format_diff_time_from_now(date: DateTime) -> String {
}
}
-/// Export selected packages.
+/// Export selected package names.
/// File will be saved in same directory where UAD-ng is located.
-pub async fn export_selection(packages: Vec) -> Result {
- let selected = packages
- .iter()
- .filter(|p| p.selected)
- .map(|p| p.name.clone())
- .collect::>()
- .join("\n");
+pub fn export_selection(package_names: &[String]) -> Result {
+ let selected = package_names.join("\n");
match fs::write(EXPORT_FILE_NAME, selected) {
Ok(()) => Ok(true),
@@ -236,22 +241,9 @@ impl fmt::Display for DisplayablePath {
}
}
-/// Can be used to choose any folder.
-pub async fn open_folder() -> Result {
- let picked_folder = rfd::AsyncFileDialog::new()
- .pick_folder()
- .await
- .ok_or(Error::DialogClosed)?;
-
- Ok(picked_folder.path().to_owned())
-}
-
/// Export uninstalled packages in a csv file.
/// Exported information will contain package name and description.
-pub async fn export_packages(
- user: User,
- phone_packages: Vec>,
-) -> Result {
+pub fn export_packages(user: User, phone_packages: &[Vec]) -> Result {
let backup_file = generate_backup_name(chrono::Local::now());
let file = fs::File::create(backup_file).map_err(|err| err.to_string())?;
@@ -260,7 +252,7 @@ pub async fn export_packages(
wtr.write_record(["Package Name", "Description"])
.map_err(|err| err.to_string())?;
- let uninstalled_packages: Vec<&PackageRow> = phone_packages[user.index]
+ let uninstalled_packages: Vec<&CorePackage> = phone_packages[user.index]
.iter()
.filter(|p| p.state == PackageState::Uninstalled)
.collect();
@@ -275,6 +267,36 @@ pub async fn export_packages(
Ok(true)
}
+/// Truncate description to fit within max length, taking only the first line
+#[must_use]
+pub fn truncate_description(desc: &str, max_len: usize) -> String {
+ let first_line = desc.split('\n').next().unwrap_or("").trim_end();
+
+ if first_line.len() <= max_len {
+ first_line.to_string()
+ } else {
+ format!("{}...", &first_line[..max_len.saturating_sub(3)])
+ }
+}
+
+/// Check if package matches search term (checks name and description)
+#[must_use]
+pub fn matches_search(pkg_name: &str, search_term: &str, pkg_description: Option<&str>) -> bool {
+ let search_lower = search_term.to_lowercase();
+
+ if pkg_name.to_lowercase().contains(&search_lower) {
+ return true;
+ }
+
+ if let Some(description) = pkg_description {
+ if description.to_lowercase().contains(&search_lower) {
+ return true;
+ }
+ }
+
+ false
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/crates/uad-gui/Cargo.toml b/crates/uad-gui/Cargo.toml
new file mode 100644
index 0000000..abc4f42
--- /dev/null
+++ b/crates/uad-gui/Cargo.toml
@@ -0,0 +1,63 @@
+[package]
+name = "uad-gui"
+version.workspace = true
+authors.workspace = true
+license.workspace = true
+homepage.workspace = true
+repository.workspace = true
+readme.workspace = true
+keywords.workspace = true
+categories = ["gui"]
+edition.workspace = true
+
+[[bin]]
+name = "uad-ng"
+path = "src/main.rs"
+
+[features]
+default = ["wgpu", "self-update", "img"]
+wgpu = [] # Iced/wgpu is default
+self-update = ["flate2", "tar"]
+no-self-update = []
+img = ["image", "iced/image"]
+
+[dependencies]
+uad-core = { path = "../uad-core", features = ["gui", "self-update"] }
+iced.workspace = true
+image = { workspace = true, optional = true }
+rfd.workspace = true
+dark-light.workspace = true
+fern.workspace = true
+chrono.workspace = true
+dirs.workspace = true
+log.workspace = true
+flate2 = { workspace = true, optional = true }
+tar = { workspace = true, optional = true }
+
+[target.'cfg(target_os = "windows")'.dependencies]
+win32console.workspace = true
+
+[build-dependencies]
+embed-resource = "3"
+
+[lints.rust]
+deprecated_safe = "warn"
+
+[lints.clippy]
+undocumented_unsafe_blocks = "forbid"
+exit = "deny"
+panic_in_result_fn = "warn"
+infinite_loop = "warn"
+mem_forget = "warn"
+implicit_clone = "warn"
+format_push_string = "warn"
+large_include_file = "warn"
+shadow_unrelated = "warn"
+struct_field_names = "allow" # annoying
+module_name_repetitions = "allow" # annoying
+
+disallowed_types = "deny"
+disallowed_methods = "deny"
+
+allow_attributes_without_reason = "warn"
+pedantic = { level = "warn", priority = -1 }
diff --git a/src/gui/mod.rs b/crates/uad-gui/src/gui.rs
similarity index 86%
rename from src/gui/mod.rs
rename to crates/uad-gui/src/gui.rs
index c88fd08..e171552 100644
--- a/src/gui/mod.rs
+++ b/crates/uad-gui/src/gui.rs
@@ -1,35 +1,32 @@
-pub mod style;
-pub mod views;
-pub mod widgets;
-
-use crate::core::adb;
-use crate::core::sync::{Phone, get_devices_list, initial_load};
+use crate::theme::string_to_theme;
#[cfg(feature = "img")]
-use crate::core::theme::OS_COLOR_SCHEME;
-use crate::core::theme::Theme;
-use crate::core::uad_lists::UadListState;
-use crate::core::update::{Release, SelfUpdateState, SelfUpdateStatus, get_latest_release};
-use crate::core::utils::{FULL_NAME, NAME, string_to_theme};
-
+use crate::theme::OS_COLOR_SCHEME;
+use crate::theme::Theme;
+use crate::views::about::{About as AboutView, Message as AboutMessage};
+use crate::views::list::{
+ List as AppsView, LoadingState as ListLoadingState, Message as AppsMessage,
+};
+use crate::views::settings::{Message as SettingsMessage, Settings as SettingsView};
+use crate::widgets::navigation_menu::nav_menu;
use iced::font;
#[cfg(feature = "img")]
use iced::window::icon;
#[cfg(feature = "img")]
use image::ImageFormat;
-use views::about::{About as AboutView, Message as AboutMessage};
-use views::list::{List as AppsView, LoadingState as ListLoadingState, Message as AppsMessage};
-use views::settings::{Message as SettingsMessage, Settings as SettingsView};
-use widgets::navigation_menu::nav_menu;
-
use iced::widget::column;
use iced::{Alignment, Element, Length, Settings, Task, window::Settings as Window};
use iced::{Subscription, event, keyboard};
-
+use log::{debug, error, info};
#[cfg(feature = "self-update")]
use std::path::PathBuf;
+use uad_core::adb;
+use uad_core::sync::{Phone, get_devices_list, initial_load};
+use uad_core::uad_lists::UadListState;
+use uad_core::update::{Release, SelfUpdateState, SelfUpdateStatus, get_latest_release};
+use uad_core::utils::{FULL_NAME, NAME};
#[cfg(feature = "self-update")]
-use crate::core::update::{BIN_NAME, download_update_to_temp_file, remove_file};
+use uad_core::update::{BIN_NAME, download_update_to_temp_file, remove_file};
#[derive(Default, Debug, Clone)]
enum View {
@@ -41,8 +38,8 @@ enum View {
#[derive(Default, Clone)]
pub struct UpdateState {
- self_update: SelfUpdateState,
- uad_list: UadListState,
+ pub self_update: SelfUpdateState,
+ pub uad_list: UadListState,
}
#[derive(Default)]
@@ -86,18 +83,21 @@ impl UadGui {
reason = "required by iced's Application trait interface"
)]
fn title(&self) -> String {
- FULL_NAME.to_string()
+ self.selected_device.as_ref().map_or_else(
+ || FULL_NAME.to_string(),
+ |device| format!("{FULL_NAME} - {}", device.model),
+ )
}
fn new() -> (Self, Task) {
(
Self::default(),
Task::batch([
- // Used in crate::gui::widgets::navigation_menu::ICONS. Name is `icomoon`.
- font::load(include_bytes!("../../resources/assets/icons.ttf").as_slice())
+ // Used in crate::widgets::navigation_menu::ICONS. Name is `icomoon`.
+ font::load(include_bytes!("../../../resources/assets/icons.ttf").as_slice())
.map(Message::FontLoaded),
- Task::perform(initial_load(), Message::ADBSatisfied),
- Task::perform(get_devices_list(), Message::LoadDevices),
+ Task::perform(async { initial_load() }, Message::ADBSatisfied),
+ Task::perform(async { get_devices_list() }, Message::LoadDevices),
Task::perform(
async move { get_latest_release() },
Message::GetLatestRelease,
@@ -111,21 +111,45 @@ impl UadGui {
reason = "required by iced's Application trait interface"
)]
fn subscription(&self) -> Subscription {
- event::listen_with(|event, _status, _env| match event {
+ if self.selected_device.is_some() {
+ event::listen_with(Self::keyboard_shortcuts_with_device)
+ } else {
+ event::listen_with(Self::keyboard_shortcuts_without_device)
+ }
+ }
+
+ fn keyboard_shortcuts_with_device(
+ event: iced::Event,
+ _status: iced::event::Status,
+ _window: iced::window::Id,
+ ) -> Option {
+ Self::keyboard_shortcuts(event, true)
+ }
+
+ fn keyboard_shortcuts_without_device(
+ event: iced::Event,
+ _status: iced::event::Status,
+ _window: iced::window::Id,
+ ) -> Option {
+ Self::keyboard_shortcuts(event, false)
+ }
+
+ fn keyboard_shortcuts(event: iced::Event, can_control_device: bool) -> Option {
+ match event {
iced::Event::Keyboard(keyboard::Event::KeyPressed {
key: keyboard::Key::Character(c),
modifiers,
..
}) if modifiers.control() && modifiers.shift() => match c.as_str() {
- "r" => Some(Message::RebootButtonPressed),
- "5" => Some(Message::RefreshButtonPressed),
+ "r" if can_control_device => Some(Message::RebootButtonPressed),
+ "5" if can_control_device => Some(Message::RefreshButtonPressed),
"a" => Some(Message::AppsPress),
"i" => Some(Message::AboutPressed),
"s" => Some(Message::SettingsPressed),
_ => None,
},
_ => None,
- })
+ }
}
#[allow(
@@ -178,7 +202,7 @@ impl UadGui {
self.adb_satisfied,
)));
}
- Task::perform(get_devices_list(), Message::LoadDevices)
+ Task::perform(async { get_devices_list() }, Message::LoadDevices)
}
Message::RebootButtonPressed => {
self.apps_view = AppsView::default();
@@ -412,10 +436,10 @@ impl UadGui {
let logo: &[u8] = match *OS_COLOR_SCHEME {
// remember to keep `Unspecified` in sync with `src/core/theme`
dark_light::Mode::Dark | dark_light::Mode::Unspecified => {
- include_bytes!("../../resources/assets/logo-dark.png")
+ include_bytes!("../../../resources/assets/logo-dark.png")
}
dark_light::Mode::Light => {
- include_bytes!("../../resources/assets/logo-light.png")
+ include_bytes!("../../../resources/assets/logo-light.png")
}
};
diff --git a/crates/uad-gui/src/helpers.rs b/crates/uad-gui/src/helpers.rs
new file mode 100644
index 0000000..25c06f1
--- /dev/null
+++ b/crates/uad-gui/src/helpers.rs
@@ -0,0 +1,23 @@
+use crate::style;
+use crate::theme::Theme;
+use iced::Element;
+use iced::widget::button::Button;
+
+/// Wrapper function for `iced::widget::button` with padding and style applied
+pub fn button_primary<'a, Message>(
+ content: impl Into>,
+) -> Button<'a, Message, Theme> {
+ iced::widget::button(content)
+ .padding([5, 10])
+ .style(style::Button::Primary)
+}
+
+/// Opens a file picker dialog to select a folder
+pub async fn open_folder() -> Result {
+ rfd::AsyncFileDialog::new()
+ .set_title("Choose a backup location")
+ .pick_folder()
+ .await
+ .ok_or(uad_core::utils::Error::DialogClosed)
+ .map(|f| f.path().to_path_buf())
+}
diff --git a/crates/uad-gui/src/lib.rs b/crates/uad-gui/src/lib.rs
new file mode 100644
index 0000000..ede5da8
--- /dev/null
+++ b/crates/uad-gui/src/lib.rs
@@ -0,0 +1,11 @@
+#![allow(
+ clippy::missing_errors_doc,
+ reason = "Short-circuit doc lint to keep CI green"
+)]
+
+pub mod gui;
+pub mod helpers;
+pub mod style;
+pub mod theme;
+pub mod views;
+pub mod widgets;
diff --git a/src/main.rs b/crates/uad-gui/src/main.rs
similarity index 90%
rename from src/main.rs
rename to crates/uad-gui/src/main.rs
index 1c197d8..07608a5 100644
--- a/src/main.rs
+++ b/crates/uad-gui/src/main.rs
@@ -1,8 +1,5 @@
#![windows_subsystem = "windows"]
-#[macro_use]
-extern crate log;
-use crate::core::utils::setup_uad_dir;
use fern::{
FormatCallback,
colors::{Color, ColoredLevelConfig},
@@ -10,12 +7,10 @@ use fern::{
use log::Record;
use std::sync::LazyLock;
use std::{fmt::Arguments, fs::OpenOptions, path::PathBuf};
+use uad_core::utils::setup_uad_dir;
-mod core;
-mod gui;
+use uad_gui::gui::UadGui;
-static CONFIG_DIR: LazyLock =
- LazyLock::new(|| setup_uad_dir(&dirs::config_dir().expect("Can't detect config dir")));
static CACHE_DIR: LazyLock =
LazyLock::new(|| setup_uad_dir(&dirs::cache_dir().expect("Can't detect cache dir")));
@@ -30,7 +25,7 @@ fn main() -> iced::Result {
}
setup_logger().expect("setup logging");
- gui::UadGui::start()
+ UadGui::start()
}
/// Sets up logging to a new file in `CACHE_DIR"/uadng.log"`
@@ -74,14 +69,14 @@ fn setup_logger() -> Result<(), fern::InitError> {
.format(make_formatter(false))
.level(default_log_level)
// Rust compiler makes module names use _ instead of -
- .level_for("uad_ng", log::LevelFilter::Debug)
+ .level_for("uad_gui", log::LevelFilter::Debug)
.chain(log_file);
let stdout_dispatcher = fern::Dispatch::new()
.format(make_formatter(true))
.level(default_log_level)
// Rust compiler makes module names use _ instead of -
- .level_for("uad_ng", log::LevelFilter::Warn)
+ .level_for("uad_gui", log::LevelFilter::Warn)
.chain(std::io::stdout());
fern::Dispatch::new()
diff --git a/src/gui/style.rs b/crates/uad-gui/src/style.rs
similarity index 98%
rename from src/gui/style.rs
rename to crates/uad-gui/src/style.rs
index 09f2a56..9eeba68 100644
--- a/src/gui/style.rs
+++ b/crates/uad-gui/src/style.rs
@@ -4,7 +4,7 @@
clippy::wildcard_imports,
reason = "Iced style modules use PascalCase and &Theme; wildcard for local convenience"
)]
-use crate::core::theme::{ColorPalette, Theme};
+use crate::theme::{ColorPalette, Theme};
use iced::widget::{
button, checkbox, container, overlay, pick_list, radio, scrollable, text, text_editor,
text_input,
@@ -321,10 +321,12 @@ pub mod Container {
use super::*;
#[allow(dead_code, reason = "Used by other themes or future styles")]
+ #[must_use]
pub fn Invisible(_: &Theme) -> container::Style {
container::Style::default()
}
+ #[must_use]
pub fn Frame(theme: &Theme) -> container::Style {
let p = theme.palette();
container::Style {
@@ -340,6 +342,7 @@ pub mod Container {
}
}
+ #[must_use]
pub fn BorderedFrame(theme: &Theme) -> container::Style {
let p = theme.palette();
container::Style {
@@ -356,6 +359,7 @@ pub mod Container {
}
#[allow(dead_code, reason = "Currently unused in some views")]
+ #[must_use]
pub fn Tooltip(theme: &Theme) -> container::Style {
let p = theme.palette();
container::Style {
@@ -371,6 +375,7 @@ pub mod Container {
}
}
+ #[must_use]
pub fn Background(theme: &Theme) -> container::Style {
let p = theme.palette();
container::Style {
@@ -408,6 +413,7 @@ pub mod Button {
}
}
+ #[must_use]
pub fn Primary(theme: &Theme, status: button::Status) -> button::Style {
let p = theme.palette();
let mut style = style_active_hover_disabled(p.bright.primary, p.bright.primary, status);
@@ -421,10 +427,12 @@ pub mod Button {
dead_code,
reason = "Alias kept for semantic clarity in some call-sites"
)]
+ #[must_use]
pub fn SelfUpdate(theme: &Theme, status: button::Status) -> button::Style {
Primary(theme, status)
}
+ #[must_use]
pub fn RestorePackage(theme: &Theme, status: button::Status) -> button::Style {
let p = theme.palette();
let mut style = style_active_hover_disabled(p.bright.secondary, p.bright.secondary, status);
@@ -441,6 +449,7 @@ pub mod Button {
style
}
+ #[must_use]
pub fn UninstallPackage(theme: &Theme, status: button::Status) -> button::Style {
let p = theme.palette();
let mut style = style_active_hover_disabled(p.bright.error, p.bright.error, status);
@@ -454,10 +463,12 @@ pub mod Button {
dead_code,
reason = "Style exposed for disabled state buttons in some contexts"
)]
+ #[must_use]
pub fn Unavailable(theme: &Theme, status: button::Status) -> button::Style {
UninstallPackage(theme, status)
}
+ #[must_use]
pub fn NormalPackage(theme: &Theme, status: button::Status) -> button::Style {
let p = theme.palette();
match status {
@@ -489,6 +500,7 @@ pub mod Button {
}
}
+ #[must_use]
pub fn SelectedPackage(theme: &Theme, _status: button::Status) -> button::Style {
let p = theme.palette();
button::Style {
@@ -508,6 +520,7 @@ pub mod Button {
}
#[allow(dead_code, reason = "Used in views where buttons must be invisible")]
+ #[must_use]
pub fn Hidden(_: &Theme, _: button::Status) -> button::Style {
button::Style {
background: Some(Background::Color(Color::TRANSPARENT)),
@@ -605,6 +618,7 @@ pub mod Scrollable {
}
}
+ #[must_use]
pub fn Description(theme: &Theme, _status: scrollable::Status) -> scrollable::Style {
let p = theme.palette();
let (v, h) = rails(p.normal.surface);
@@ -617,6 +631,7 @@ pub mod Scrollable {
}
}
+ #[must_use]
pub fn Packages(theme: &Theme, _status: scrollable::Status) -> scrollable::Style {
let p = theme.palette();
let (v, h) = rails(p.base.foreground);
@@ -633,6 +648,7 @@ pub mod Scrollable {
pub mod CheckBox {
use super::*;
+ #[must_use]
pub fn PackageEnabled(theme: &Theme, _status: checkbox::Status) -> checkbox::Style {
let p = theme.palette();
checkbox::Style {
@@ -647,6 +663,7 @@ pub mod CheckBox {
}
}
+ #[must_use]
pub fn PackageDisabled(theme: &Theme, _status: checkbox::Status) -> checkbox::Style {
let p = theme.palette();
checkbox::Style {
@@ -664,6 +681,7 @@ pub mod CheckBox {
}
}
+ #[must_use]
pub fn SettingsEnabled(theme: &Theme, _status: checkbox::Status) -> checkbox::Style {
let p = theme.palette();
checkbox::Style {
@@ -678,6 +696,7 @@ pub mod CheckBox {
}
}
+ #[must_use]
pub fn SettingsDisabled(theme: &Theme, _status: checkbox::Status) -> checkbox::Style {
let p = theme.palette();
checkbox::Style {
@@ -696,11 +715,13 @@ pub mod CheckBox {
pub mod Text {
use super::*;
+ #[must_use]
pub fn Default(theme: &Theme) -> text::Style {
let _ = theme;
text::Style::default()
}
+ #[must_use]
pub fn Ok(theme: &Theme) -> text::Style {
let p = theme.palette();
text::Style {
@@ -708,6 +729,7 @@ pub mod Text {
}
}
+ #[must_use]
pub fn Danger(theme: &Theme) -> text::Style {
let p = theme.palette();
text::Style {
@@ -715,6 +737,7 @@ pub mod Text {
}
}
+ #[must_use]
pub fn Commentary(theme: &Theme) -> text::Style {
let p = theme.palette();
text::Style {
@@ -738,7 +761,7 @@ mod tests {
#[test]
fn test_palette() {
- let palette = Theme::default().palette();
+ let palette = Theme::Dark.palette();
assert_ne!(palette.base.background, palette.base.foreground);
assert_ne!(palette.normal.primary, Color::BLACK);
diff --git a/crates/uad-gui/src/theme.rs b/crates/uad-gui/src/theme.rs
new file mode 100644
index 0000000..3c4c263
--- /dev/null
+++ b/crates/uad-gui/src/theme.rs
@@ -0,0 +1,72 @@
+use iced::theme::{self, Mode, Palette, Style};
+
+pub use uad_core::theme::{BaseColors, BrightColors, ColorPalette, NormalColors, OS_COLOR_SCHEME};
+
+/// GUI-local wrapper around the core Theme to satisfy orphan rules for
+/// iced's Catalog traits.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Theme(pub uad_core::theme::Theme);
+
+#[allow(
+ non_upper_case_globals,
+ reason = "Keep variant-like names matching core Theme"
+)]
+impl Theme {
+ pub const Auto: Self = Self(uad_core::theme::Theme::Auto);
+ pub const Lupin: Self = Self(uad_core::theme::Theme::Lupin);
+ pub const Dark: Self = Self(uad_core::theme::Theme::Dark);
+ pub const Light: Self = Self(uad_core::theme::Theme::Light);
+
+ pub const ALL: [Self; 4] = [Self::Auto, Self::Lupin, Self::Dark, Self::Light];
+
+ #[must_use]
+ pub fn palette(self) -> ColorPalette {
+ self.0.palette()
+ }
+}
+
+impl From for Theme {
+ fn from(value: uad_core::theme::Theme) -> Self {
+ Self(value)
+ }
+}
+
+impl From for uad_core::theme::Theme {
+ fn from(value: Theme) -> Self {
+ value.0
+ }
+}
+
+/// Converts a string to the GUI's Theme type
+#[must_use]
+pub fn string_to_theme(theme: &str) -> Theme {
+ Theme(uad_core::theme::string_to_theme(theme))
+}
+
+impl theme::Base for Theme {
+ fn default(preference: Mode) -> Self {
+ Self(::default(preference))
+ }
+
+ fn mode(&self) -> Mode {
+ ::mode(&self.0)
+ }
+
+ fn base(&self) -> Style {
+ ::base(&self.0)
+ }
+
+ fn palette(&self) -> Option {
+ ::palette(&self.0)
+ }
+
+ fn name(&self) -> &str {
+ ::name(&self.0)
+ }
+}
+
+impl std::fmt::Display for Theme {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.0, f)
+ }
+}
diff --git a/src/gui/views/about.rs b/crates/uad-gui/src/views/about.rs
similarity index 94%
rename from src/gui/views/about.rs
rename to crates/uad-gui/src/views/about.rs
index 56d73ca..42cb723 100644
--- a/src/gui/views/about.rs
+++ b/crates/uad-gui/src/views/about.rs
@@ -1,16 +1,17 @@
-use crate::CACHE_DIR;
-use crate::core::adb;
-use crate::core::helpers::button_primary;
-use crate::core::theme::Theme;
-use crate::core::uad_lists::LIST_FNAME;
-use crate::core::utils::{FULL_NAME, NAME, last_modified_date, open_url};
-use crate::gui::{UpdateState, style, widgets::text};
+use crate::helpers::button_primary;
+use crate::theme::Theme;
+use crate::{gui::UpdateState, style, widgets::text};
use iced::widget::{Space, column, container, row};
use iced::{Alignment, Element, Length, Renderer};
+use log::error;
use std::path::PathBuf;
+use uad_core::CACHE_DIR;
+use uad_core::adb;
+use uad_core::uad_lists::LIST_FNAME;
+use uad_core::utils::{FULL_NAME, NAME, last_modified_date, open_url};
#[cfg(feature = "self-update")]
-use crate::core::update::SelfUpdateStatus;
+use uad_core::update::SelfUpdateStatus;
#[derive(Default, Debug, Clone)]
pub struct About {}
diff --git a/src/gui/views/list.rs b/crates/uad-gui/src/views/list.rs
similarity index 92%
rename from src/gui/views/list.rs
rename to crates/uad-gui/src/views/list.rs
index 3402fc7..a9792dd 100644
--- a/src/gui/views/list.rs
+++ b/crates/uad-gui/src/views/list.rs
@@ -1,19 +1,22 @@
-use crate::core::config::DeviceSettings;
-use crate::core::helpers::button_primary;
-use crate::core::sync::{AdbError, Phone, User, apply_pkg_state_commands, run_adb_action};
-use crate::core::theme::Theme;
-use crate::core::uad_lists::{
+use crate::helpers::button_primary;
+use crate::style;
+use crate::theme::Theme;
+use crate::widgets::navigation_menu::ICONS;
+use log::{error, info, warn};
+use std::path::PathBuf;
+use uad_core::config::DeviceSettings;
+use uad_core::sync::{AdbError, Phone, User, apply_pkg_state_commands};
+use uad_core::uad_lists::{
Opposite, PackageHashMap, PackageState, Removal, UadList, UadListState, load_debloat_lists,
};
-use crate::core::utils::{EXPORT_FILE_NAME, NAME, export_selection, fetch_packages, open_url};
-use crate::gui::style;
-use crate::gui::widgets::navigation_menu::ICONS;
-use std::path::PathBuf;
+use uad_core::utils::{
+ EXPORT_FILE_NAME, NAME, export_selection, fetch_packages, matches_search, open_url,
+};
-use crate::gui::views::settings::Settings;
-use crate::gui::widgets::modal::Modal;
-use crate::gui::widgets::package_row::{Message as RowMessage, PackageRow};
-use crate::gui::widgets::text;
+use crate::views::settings::Settings;
+use crate::widgets::modal::Modal;
+use crate::widgets::package_row::{Message as RowMessage, PackageRow};
+use crate::widgets::text;
use iced::widget::scrollable::{Direction, Scrollbar};
use iced::widget::{
Column, Space, button, checkbox, column, container, pick_list, radio, row, rule, scrollable,
@@ -52,8 +55,8 @@ pub struct List {
filtered_packages: Vec,
/// Vec of `(user_index, pkg_index)`
selected_packages: Vec<(usize, usize)>,
- selected_package_state: Option,
selected_removal: Option,
+ selected_package_state: Option,
selected_list: Option,
pub selected_user: Option,
all_selected: bool,
@@ -81,8 +84,8 @@ pub enum Message {
ToggleAllSelected(bool),
ListSelected(UadList),
UserSelected(User),
- PackageStateSelected(PackageState),
RemovalSelected(Removal),
+ PackageStateSelected(PackageState),
ApplyActionOnSelection,
List(usize, RowMessage),
VerifyAndFallback(Result),
@@ -149,8 +152,8 @@ impl List {
}
Message::SearchInputChanged(letter) => self.on_search_input_changed(letter),
Message::ListSelected(list) => self.on_list_selected(list),
- Message::PackageStateSelected(state) => self.on_package_state_selected(state),
Message::RemovalSelected(removal) => self.on_removal_selected(removal),
+ Message::PackageStateSelected(state) => self.on_package_state_selected(state),
Message::List(i, row_msg) => self.on_list_row(i, &row_msg, settings, selected_device),
Message::ApplyActionOnSelection => self.on_apply_action_on_selection(),
Message::UserSelected(user) => self.on_user_selected(user),
@@ -635,7 +638,7 @@ impl List {
.width(120),
row![text(
self.phone_packages[selection.0][selection.1]
- .uad_list
+ .list
.to_string()
)]
.width(55),
@@ -752,12 +755,11 @@ impl List {
// that's why `enumerate` is before `filter`.
.enumerate()
.filter(|(_, p)| {
- (list_filter == UadList::All || p.uad_list == list_filter)
+ (list_filter == UadList::All || p.list == list_filter)
&& (package_filter == PackageState::All || p.state == package_filter)
&& (removal_filter == Removal::All || p.removal == removal_filter)
&& (self.input_value.is_empty()
- || p.name.contains(&self.input_value)
- || p.description.contains(&self.input_value))
+ || matches_search(&p.name, &self.input_value, Some(&p.description)))
})
.map(|(i, _)| i)
.collect();
@@ -771,11 +773,21 @@ impl List {
) -> Vec> {
let serial = device_serial.as_ref();
if user_list.len() <= 1 {
- vec![fetch_packages(&uad_list, serial, None)]
+ vec![
+ fetch_packages(&uad_list, serial, None)
+ .into_iter()
+ .map(PackageRow::from)
+ .collect(),
+ ]
} else {
user_list
.iter()
- .map(|user| fetch_packages(&uad_list, serial, Some(user.id)))
+ .map(|user| {
+ fetch_packages(&uad_list, serial, Some(user.id))
+ .into_iter()
+ .map(PackageRow::from)
+ .collect()
+ })
.collect()
}
}
@@ -877,8 +889,8 @@ impl List {
let i_user = self.selected_user.unwrap_or_default().index;
self.phone_packages = packages;
self.filtered_packages = (0..self.phone_packages[i_user].len()).collect();
- self.selected_package_state = Some(PackageState::Enabled);
self.selected_removal = Some(Removal::Recommended);
+ self.selected_package_state = Some(PackageState::Enabled);
self.selected_list = Some(UadList::All);
self.selected_user = Some(User::default());
self.fallback_notifications.clear();
@@ -1053,7 +1065,7 @@ impl List {
Task::perform(
async move {
// Blocking ADB calls happen here (off UI thread)
- let actual_state_opt = crate::core::sync::verify_package_state(
+ let actual_state_opt = uad_core::sync::verify_package_state(
&pkg_name,
device.adb_id.as_str(),
Some(user_id),
@@ -1062,7 +1074,7 @@ impl List {
match actual_state_opt {
Some(actual_state) if actual_state == wanted_state => {
// Check cross-user behavior
- let error_modal = crate::core::sync::detect_cross_user_behavior(
+ let error_modal = uad_core::sync::detect_cross_user_behavior(
&pkg_name,
device.adb_id.as_str(),
user_id,
@@ -1091,16 +1103,16 @@ impl List {
// Package doesn't exist (None) or has wrong state - try fallback
let actual_state =
actual_state_opt.unwrap_or(PackageState::Uninstalled);
- let fallback_result = crate::core::sync::attempt_fallback(
- &crate::gui::widgets::package_row::PackageRow::new(
- &pkg_name,
- current_state,
- "",
- UadList::All,
- Removal::All,
- false,
- false,
- ),
+ // Create CorePackage for fallback
+ let core_package = uad_core::sync::CorePackage {
+ name: pkg_name.clone(),
+ description: String::new(),
+ removal: Removal::All,
+ state: current_state,
+ list: UadList::Unlisted,
+ };
+ let fallback_result = uad_core::sync::attempt_fallback(
+ &core_package,
wanted_state,
actual_state,
device.user_list[i_user],
@@ -1195,14 +1207,17 @@ impl List {
// fallback task
return Task::perform(
async move {
- let temp_pkg = crate::core::sync::CorePackage {
+ let temp_pkg = uad_core::sync::CorePackage {
name: pkg_name.clone(),
+ description: String::new(),
+ removal: Removal::All,
state: PackageState::Disabled,
+ list: UadList::Unlisted,
};
// get uninstall command
let uninstall_cmds =
- crate::core::sync::apply_pkg_state_commands(
+ uad_core::sync::apply_pkg_state_commands(
&temp_pkg,
PackageState::Uninstalled,
user,
@@ -1210,24 +1225,24 @@ impl List {
);
if let Some(cmd) = uninstall_cmds.first() {
- let dummy_info = PackageInfo::default();
- let _ = crate::core::sync::run_adb_action(
- device.adb_id.clone(),
- cmd.clone(),
- dummy_info,
- )
- .await;
+ let _ = uad_core::sync::run_adb_shell_action(
+ &device.adb_id,
+ cmd,
+ );
}
// reinstall/enable
let temp_pkg_uninstalled =
- crate::core::sync::CorePackage {
+ uad_core::sync::CorePackage {
name: pkg_name.clone(),
+ description: String::new(),
+ removal: Removal::All,
state: PackageState::Uninstalled,
+ list: UadList::Unlisted,
};
let enable_cmds =
- crate::core::sync::apply_pkg_state_commands(
+ uad_core::sync::apply_pkg_state_commands(
&temp_pkg_uninstalled,
PackageState::Enabled,
user,
@@ -1236,18 +1251,15 @@ impl List {
// lets enable the new package
if let Some(cmd) = enable_cmds.first() {
- let dummy_info = PackageInfo::default();
- let _ = crate::core::sync::run_adb_action(
- device.adb_id.clone(),
- cmd.clone(),
- dummy_info,
- )
- .await;
+ let _ = uad_core::sync::run_adb_shell_action(
+ &device.adb_id,
+ cmd,
+ );
}
//verifies the final state for thread confirmation
let actual_state =
- crate::core::sync::verify_package_state(
+ uad_core::sync::verify_package_state(
&pkg_name,
&device.adb_id,
Some(user.id),
@@ -1316,8 +1328,13 @@ impl List {
fn on_export_selection(&mut self) -> Task {
let i_user = self.selected_user.unwrap_or_default().index;
+ let package_names: Vec = self.phone_packages[i_user]
+ .iter()
+ .filter(|p| p.selected)
+ .map(|p| p.name.clone())
+ .collect();
Task::perform(
- export_selection(self.phone_packages[i_user].clone()),
+ async move { export_selection(&package_names) },
Message::SelectionExported,
)
}
@@ -1483,17 +1500,24 @@ fn build_action_pkg_commands(
// Will be filled asynchronously before running the adb action
before_cross_user_states: vec![],
};
+ // Clone data before async block to avoid borrowing issues
+ let device_serial = device.adb_id.clone();
+ let package_name = u_pkg.name.clone();
+ let user_id = u.id;
+ let phone = device.clone();
// In the end there is only one package state change
// even if we run multiple adb commands
commands.push(Task::perform(
- run_adb_action_with_before_states(
- device.adb_id.clone(),
- action,
- p_info,
- u_pkg.name.clone(),
- u.id,
- device.clone(),
- ),
+ async move {
+ run_adb_action_with_before_states(
+ &device_serial,
+ &action,
+ p_info,
+ &package_name,
+ user_id,
+ &phone,
+ )
+ },
if j == 0 {
Message::VerifyAndFallback
} else {
@@ -1505,23 +1529,25 @@ fn build_action_pkg_commands(
commands
}
-async fn run_adb_action_with_before_states(
- device_serial: String,
- action: String,
+fn run_adb_action_with_before_states(
+ device_serial: &str,
+ action: &str,
mut p_info: PackageInfo,
- package_name: String,
+ package_name: &str,
target_user_id: u16,
- phone: Phone,
+ phone: &Phone,
) -> Result {
// Capture before-state in background to avoid blocking UI thread
- let before_states = crate::core::sync::capture_cross_user_states(
- &package_name,
- &device_serial,
+ let before_states = uad_core::sync::capture_cross_user_states(
+ package_name,
+ device_serial,
target_user_id,
- &phone,
+ phone,
);
p_info.before_cross_user_states = before_states;
- run_adb_action(device_serial, action, p_info).await
+ // Run the ADB action
+ uad_core::sync::run_adb_shell_action(device_serial, action)?;
+ Ok(p_info)
}
fn recap<'a>(settings: &Settings, recap: &SummaryEntry) -> Element<'a, Message, Theme, Renderer> {
diff --git a/src/gui/views/mod.rs b/crates/uad-gui/src/views/mod.rs
similarity index 100%
rename from src/gui/views/mod.rs
rename to crates/uad-gui/src/views/mod.rs
diff --git a/src/gui/views/settings.rs b/crates/uad-gui/src/views/settings.rs
similarity index 88%
rename from src/gui/views/settings.rs
rename to crates/uad-gui/src/views/settings.rs
index 01ff22f..c19b999 100644
--- a/src/gui/views/settings.rs
+++ b/crates/uad-gui/src/views/settings.rs
@@ -1,15 +1,7 @@
-use crate::core::{
- config::{BackupSettings, Config, DeviceSettings, GeneralSettings},
- helpers::button_primary,
- save::{backup_phone, list_available_backup_user, list_available_backups, restore_backup},
- sync::{AdbError, Phone, User, get_android_sdk, run_adb_action, supports_multi_user},
- theme::Theme,
- utils::{
- DisplayablePath, Error, NAME, export_packages, generate_backup_name, open_folder, open_url,
- string_to_theme,
- },
-};
-use crate::gui::{
+use crate::helpers::{button_primary, open_folder};
+use crate::theme::Theme;
+use crate::theme::string_to_theme;
+use crate::{
style,
views::list::{List as AppsView, PackageInfo},
widgets::modal::Modal,
@@ -17,9 +9,20 @@ use crate::gui::{
widgets::package_row::PackageRow,
widgets::text,
};
+use chrono;
use iced::widget::{Space, button, checkbox, column, container, pick_list, radio, row, scrollable};
use iced::{Alignment, Element, Length, Renderer, Task, alignment};
+use log::{debug, error, info};
use std::path::PathBuf;
+use uad_core::{
+ config::{BackupSettings, Config, DeviceSettings, GeneralSettings},
+ save::{backup_phone, list_available_backup_user, list_available_backups, restore_backup},
+ sync::{
+ AdbError, CorePackage, Phone, User, get_android_sdk, run_adb_shell_action,
+ supports_multi_user,
+ },
+ utils::{DisplayablePath, Error, NAME, export_packages, generate_backup_name, open_url},
+};
#[derive(Debug, Clone)]
pub enum PopUpModal {
@@ -101,10 +104,11 @@ impl Settings {
Task::none()
}
- fn handle_expert_mode(&mut self, phone: &Phone, toggled: bool) -> Task {
+ fn handle_expert_mode(&mut self, _phone: &Phone, toggled: bool) -> Task {
self.general.expert_mode = toggled;
debug!("Config change: {self:?}");
- Config::save_changes(self, &phone.adb_id);
+ let mut config = Config::load_configuration_file();
+ config.save_device_settings(self.device.clone(), self.general.clone());
Task::none()
}
@@ -112,22 +116,25 @@ impl Settings {
if phone.android_sdk >= 23 {
self.device.disable_mode = toggled;
debug!("Config change: {self:?}");
- Config::save_changes(self, &phone.adb_id);
+ let mut config = Config::load_configuration_file();
+ config.save_device_settings(self.device.clone(), self.general.clone());
}
Task::none()
}
- fn handle_multi_user_mode(&mut self, phone: &Phone, toggled: bool) -> Task {
+ fn handle_multi_user_mode(&mut self, _phone: &Phone, toggled: bool) -> Task {
self.device.multi_user_mode = toggled;
debug!("Config change: {self:?}");
- Config::save_changes(self, &phone.adb_id);
+ let mut config = Config::load_configuration_file();
+ config.save_device_settings(self.device.clone(), self.general.clone());
Task::none()
}
- fn handle_apply_theme(&mut self, phone: &Phone, theme: Theme) -> Task {
+ fn handle_apply_theme(&mut self, _phone: &Phone, theme: Theme) -> Task {
self.general.theme = theme.to_string();
debug!("Config change: {self:?}");
- Config::save_changes(self, &phone.adb_id);
+ let mut config = Config::load_configuration_file();
+ config.save_device_settings(self.device.clone(), self.general.clone());
Task::none()
}
@@ -182,12 +189,16 @@ impl Settings {
phone: &Phone,
packages: &[Vec],
) -> Task {
+ let core_packages: Vec> = packages
+ .iter()
+ .map(|user_packages| user_packages.iter().map(CorePackage::from).collect())
+ .collect();
+ // Avoid capturing &self and &phone in the future; clone owned data first.
+ let user_list = phone.user_list.clone();
+ let device_id = self.device.device_id.clone();
+ let packages_owned = core_packages;
Task::perform(
- backup_phone(
- phone.user_list.clone(),
- self.device.device_id.clone(),
- packages.to_vec(),
- ),
+ async move { backup_phone(user_list, device_id, &packages_owned) },
Message::DeviceBackedUp,
)
}
@@ -217,7 +228,11 @@ impl Settings {
packages: &[Vec],
nb_running_async_adb_commands: &mut u32,
) -> Task {
- match restore_backup(phone, packages, &self.device) {
+ let core_packages: Vec> = packages
+ .iter()
+ .map(|user_packages| user_packages.iter().map(CorePackage::from).collect())
+ .collect();
+ match restore_backup(phone, &core_packages, &self.device) {
Ok(restore_result) => {
let mut commands = vec![];
*nb_running_async_adb_commands = 0;
@@ -230,8 +245,13 @@ impl Settings {
};
for command in p.commands.clone() {
*nb_running_async_adb_commands += 1;
+ let p_info_clone = p_info.clone();
+ let phone_id = phone.adb_id.clone();
commands.push(Task::perform(
- run_adb_action(phone.adb_id.clone(), command, p_info.clone()),
+ async move {
+ run_adb_shell_action(phone_id, command.as_str())
+ .map(|_| p_info_clone)
+ },
Message::RestoringDevice,
));
}
@@ -274,7 +294,8 @@ impl Settings {
if let Ok(path) = result {
self.general.backup_folder = path;
- Config::save_changes(self, &phone.adb_id);
+ let mut config = Config::load_configuration_file();
+ config.save_device_settings(self.device.clone(), self.general.clone());
self.load_device_settings(phone);
}
Task::none()
@@ -293,8 +314,12 @@ impl Settings {
selected_user: Option,
packages: &[Vec],
) -> Task {
+ let core_packages: Vec> = packages
+ .iter()
+ .map(|user_packages| user_packages.iter().map(CorePackage::from).collect())
+ .collect();
Task::perform(
- export_packages(selected_user.unwrap_or_default(), packages.to_vec()),
+ async move { export_packages(selected_user.unwrap_or_default(), &core_packages) },
Message::PackagesExported,
)
}
diff --git a/src/gui/widgets/mod.rs b/crates/uad-gui/src/widgets/mod.rs
similarity index 100%
rename from src/gui/widgets/mod.rs
rename to crates/uad-gui/src/widgets/mod.rs
diff --git a/src/gui/widgets/modal.rs b/crates/uad-gui/src/widgets/modal.rs
similarity index 99%
rename from src/gui/widgets/modal.rs
rename to crates/uad-gui/src/widgets/modal.rs
index a48e5d9..86278a7 100644
--- a/src/gui/widgets/modal.rs
+++ b/crates/uad-gui/src/widgets/modal.rs
@@ -25,6 +25,7 @@ impl<'a, Message, Theme, Renderer> Modal<'a, Message, Theme, Renderer> {
/// Sets the message that will be produces when the background
/// of the [`Modal`] is pressed
+ #[must_use]
pub fn on_blur(self, on_blur: Message) -> Self {
Self {
on_blur: Some(on_blur),
diff --git a/src/gui/widgets/navigation_menu.rs b/crates/uad-gui/src/widgets/navigation_menu.rs
similarity index 90%
rename from src/gui/widgets/navigation_menu.rs
rename to crates/uad-gui/src/widgets/navigation_menu.rs
index f0f9dd9..d26f1b4 100644
--- a/src/gui/widgets/navigation_menu.rs
+++ b/crates/uad-gui/src/widgets/navigation_menu.rs
@@ -1,19 +1,22 @@
-use crate::core::helpers::button_primary;
-pub use crate::core::sync::Phone;
-use crate::core::theme::Theme;
-use crate::core::update::{SelfUpdateState, SelfUpdateStatus};
-pub use crate::gui::views::about::Message as AboutMessage;
-pub use crate::gui::views::list::{List as AppsView, LoadingState as ListLoadingState};
-use crate::gui::{Message, style, widgets::text};
+use crate::helpers::button_primary;
+use crate::theme::Theme;
+pub use crate::views::about::Message as AboutMessage;
+pub use crate::views::list::{List as AppsView, LoadingState as ListLoadingState};
+use crate::{gui::Message, style, widgets::text};
use iced::widget::{Space, button, container, pick_list, row, tooltip};
use iced::{Alignment, Element, Font, Length, Renderer, alignment, font};
+pub use uad_core::sync::Phone;
+use uad_core::update::{SelfUpdateState, SelfUpdateStatus};
/// resources/assets/icons.ttf, loaded in [`crate::gui::UadGui`]
pub const ICONS: Font = Font {
family: font::Family::Name("icomoon"),
..Font::DEFAULT
};
-#[allow(clippy::too_many_lines)]
+#[allow(
+ clippy::too_many_lines,
+ reason = "Navigation layout composes many widgets inline"
+)]
pub fn nav_menu<'a>(
device_list: &'a [Phone],
selected_device: Option,
diff --git a/src/gui/widgets/package_row.rs b/crates/uad-gui/src/widgets/package_row.rs
similarity index 71%
rename from src/gui/widgets/package_row.rs
rename to crates/uad-gui/src/widgets/package_row.rs
index 7d43bb2..9c9c1cd 100644
--- a/src/gui/widgets/package_row.rs
+++ b/crates/uad-gui/src/widgets/package_row.rs
@@ -1,9 +1,10 @@
-use crate::core::sync::Phone;
-use crate::core::theme::Theme;
-use crate::core::uad_lists::{PackageState, Removal, UadList};
-use crate::gui::style;
-use crate::gui::views::settings::Settings;
-use crate::gui::widgets::text;
+use crate::style;
+use crate::theme::Theme;
+use crate::views::settings::Settings;
+use crate::widgets::text;
+use log::warn;
+use uad_core::sync::{CorePackage, Phone};
+use uad_core::uad_lists::{PackageState, Removal, UadList};
use iced::widget::{Space, button, checkbox, row};
use iced::{Alignment, Element, Length, Renderer, Task, alignment};
@@ -11,10 +12,10 @@ use iced::{Alignment, Element, Length, Renderer, Task, alignment};
#[derive(Clone, Debug)]
pub struct PackageRow {
pub name: String,
- pub state: PackageState,
pub description: String,
- pub uad_list: UadList,
pub removal: Removal,
+ pub state: PackageState,
+ pub list: UadList,
pub selected: bool,
pub current: bool,
}
@@ -27,21 +28,22 @@ pub enum Message {
}
impl PackageRow {
+ #[must_use]
pub fn new(
name: &str,
- state: PackageState,
description: &str,
- uad_list: UadList,
removal: Removal,
+ state: PackageState,
+ list: UadList,
selected: bool,
current: bool,
) -> Self {
Self {
name: name.to_string(),
- state,
description: description.to_string(),
- uad_list,
removal,
+ state,
+ list,
selected,
current,
}
@@ -143,3 +145,56 @@ impl PackageRow {
.into()
}
}
+
+// Conversions between PackageRow and CorePackage
+impl From for PackageRow {
+ fn from(core: CorePackage) -> Self {
+ Self {
+ name: core.name.clone(),
+ description: core.description,
+ removal: core.removal,
+ state: core.state,
+ list: core.list,
+ selected: false, // Default to not selected
+ current: false, // Default to not current
+ }
+ }
+}
+
+impl From<&CorePackage> for PackageRow {
+ fn from(core: &CorePackage) -> Self {
+ Self {
+ name: core.name.clone(),
+ description: core.description.clone(),
+ removal: core.removal,
+ state: core.state,
+ list: core.list,
+ selected: false,
+ current: false,
+ }
+ }
+}
+
+impl From<&PackageRow> for CorePackage {
+ fn from(row: &PackageRow) -> Self {
+ Self {
+ name: row.name.clone(),
+ description: row.description.clone(),
+ removal: row.removal,
+ state: row.state,
+ list: row.list,
+ }
+ }
+}
+
+impl From for CorePackage {
+ fn from(row: PackageRow) -> Self {
+ Self {
+ name: row.name,
+ description: row.description,
+ removal: row.removal,
+ state: row.state,
+ list: row.list,
+ }
+ }
+}
diff --git a/src/gui/widgets/text.rs b/crates/uad-gui/src/widgets/text.rs
similarity index 92%
rename from src/gui/widgets/text.rs
rename to crates/uad-gui/src/widgets/text.rs
index da6a3c2..1fdc7c1 100644
--- a/src/gui/widgets/text.rs
+++ b/crates/uad-gui/src/widgets/text.rs
@@ -3,10 +3,11 @@
reason = "this is the replacement that enforces advanced shaping for disallowed [`iced::widget::Text`]"
)]
+use crate::theme::Theme;
use iced::advanced::text::IntoFragment;
use iced::widget;
// Creates a new Text widget with advanced shaping.
-pub fn text<'a>(text: impl IntoFragment<'a>) -> widget::Text<'a, crate::core::theme::Theme> {
+pub fn text<'a>(text: impl IntoFragment<'a>) -> widget::Text<'a, Theme> {
widget::Text::new(text).shaping(iced::widget::text::Shaping::Advanced)
}
diff --git a/src/core/helpers.rs b/src/core/helpers.rs
deleted file mode 100644
index 0bad3d0..0000000
--- a/src/core/helpers.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use crate::core::theme::Theme;
-use crate::gui::style;
-use iced::Element;
-use iced::widget::button;
-use iced::widget::button::Button;
-
-/// Wrapper function for `iced::widget::button` with padding and style applied
-pub fn button_primary<'a, Message>(
- content: impl Into>,
-) -> Button<'a, Message, Theme> {
- button(content)
- .padding([5, 10])
- .style(style::Button::Primary)
-}
diff --git a/src/core/mod.rs b/src/core/mod.rs
deleted file mode 100644
index 68c584e..0000000
--- a/src/core/mod.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod adb;
-pub mod config;
-pub mod helpers;
-pub mod save;
-pub mod sync;
-pub mod theme;
-pub mod uad_lists;
-pub mod update;
-pub mod utils;
From da7482601e2312b51a1724076276f89eebd2ac48 Mon Sep 17 00:00:00 2001
From: Angel J <78835633+iamanaws@users.noreply.github.com>
Date: Tue, 24 Mar 2026 19:47:02 -0700
Subject: [PATCH 087/111] fix(cli): improve package verification, and output
robustness
---
crates/uad-cli/src/commands.rs | 34 +++++++++++++++++++++++-----------
crates/uad-cli/src/main.rs | 12 ++++++++++--
crates/uad-cli/src/repl.rs | 33 +++++++++++++++++++--------------
3 files changed, 52 insertions(+), 27 deletions(-)
diff --git a/crates/uad-cli/src/commands.rs b/crates/uad-cli/src/commands.rs
index 3d0f13d..25b5bc0 100644
--- a/crates/uad-cli/src/commands.rs
+++ b/crates/uad-cli/src/commands.rs
@@ -16,7 +16,7 @@ use crate::{Cli, print_or_exit, println_or_exit};
/// List all connected Android devices
pub fn list_devices() -> Result<(), Box> {
- println!("Scanning for connected devices...");
+ println_or_exit!("Scanning for connected devices...");
let devices = get_devices_list();
if devices.is_empty() {
@@ -24,20 +24,20 @@ pub fn list_devices() -> Result<(), Box> {
return Err("No devices found".into());
}
- println!("\nFound {} device(s):\n", devices.len());
+ println_or_exit!("\nFound {} device(s):\n", devices.len());
for device in &devices {
- println!(" Model: {}", device.model);
- println!(" Serial: {}", device.adb_id);
- println!(" Android SDK: {}", device.android_sdk);
+ println_or_exit!(" Model: {}", device.model);
+ println_or_exit!(" Serial: {}", device.adb_id);
+ println_or_exit!(" Android SDK: {}", device.android_sdk);
if !device.user_list.is_empty() {
- println!(" Users: {} user(s)", device.user_list.len());
+ println_or_exit!(" Users: {} user(s)", device.user_list.len());
for user in &device.user_list {
let protected = if user.protected { " (protected)" } else { "" };
- println!(" - User ID: {}{}", user.id, protected);
+ println_or_exit!(" - User ID: {}{}", user.id, protected);
}
}
- println!();
+ println_or_exit!();
}
Ok(())
@@ -372,8 +372,17 @@ pub fn execute_with_fallback(
}
// Verify package state and attempt fallback if needed
- let actual_state =
- get_package_state(&device.adb_id, package, Some(user.id)).unwrap_or(PackageState::Enabled);
+ let actual_state = match get_package_state(&device.adb_id, package, Some(user.id)) {
+ Some(state) => state,
+ None if target_state == PackageState::Uninstalled => PackageState::Uninstalled,
+ None => {
+ return Err(format!(
+ "Package '{package}' was not found on device for user {}",
+ user.id
+ )
+ .into());
+ }
+ };
if actual_state != target_state {
println!(
@@ -413,6 +422,7 @@ pub fn execute_with_fallback(
pub fn show_package_info(
package: &str,
device: Option,
+ user_id: Option,
) -> Result<(), Box> {
println!("Package: {}\n", package);
@@ -430,9 +440,11 @@ pub fn show_package_info(
if let Some(device_id) = device {
let target_device = get_target_device(Some(device_id))?;
+ let user = get_user(&target_device, user_id)?;
println!("Device: {} ({})", target_device.model, target_device.adb_id);
+ println!("User: {}", user.id);
- let state = get_package_state(&target_device.adb_id, package, None)
+ let state = get_package_state(&target_device.adb_id, package, Some(user.id))
.ok_or("Package not found on device")?;
println!(" State: {}", state);
}
diff --git a/crates/uad-cli/src/main.rs b/crates/uad-cli/src/main.rs
index e849e68..d2e4bd4 100644
--- a/crates/uad-cli/src/main.rs
+++ b/crates/uad-cli/src/main.rs
@@ -126,6 +126,10 @@ enum Commands {
/// Device serial number (optional, uses first device if not specified)
#[arg(short, long)]
device: Option,
+
+ /// User ID (defaults to 0)
+ #[arg(short, long)]
+ user: Option,
},
/// Update UAD package lists from remote repository
@@ -214,8 +218,12 @@ async fn main() -> Result<(), Box> {
"Disabling",
)?;
}
- Commands::Info { package, device } => {
- commands::show_package_info(&package, device)?;
+ Commands::Info {
+ package,
+ device,
+ user,
+ } => {
+ commands::show_package_info(&package, device, user)?;
}
Commands::Update => {
commands::update_lists()?;
diff --git a/crates/uad-cli/src/repl.rs b/crates/uad-cli/src/repl.rs
index 0e78b6c..eeee0c6 100644
--- a/crates/uad-cli/src/repl.rs
+++ b/crates/uad-cli/src/repl.rs
@@ -11,6 +11,11 @@ use crate::device::{get_target_device, get_user};
use crate::filters::StateFilter;
use crate::println_or_exit;
+enum ReplAction {
+ Continue,
+ Exit,
+}
+
/// Start interactive REPL mode
pub fn repl_mode(
device: Option,
@@ -41,13 +46,12 @@ pub fn repl_mode(
let readline = rl.readline("uad> ");
match readline {
Ok(line) => {
- if let Err(e) =
- handle_repl_line(&line, &mut rl, &target_device, user, user_id, &uad_lists)
- {
- if e.to_string() == "exit" {
- break;
+ match handle_repl_line(&line, &mut rl, &target_device, user, user_id, &uad_lists) {
+ Ok(ReplAction::Continue) => {}
+ Ok(ReplAction::Exit) => break,
+ Err(e) => {
+ eprintln!("Error: {}", e);
}
- eprintln!("Error: {}", e);
}
}
Err(ReadlineError::Interrupted) => {
@@ -84,30 +88,30 @@ fn handle_repl_line(
user: User,
user_id: Option,
uad_lists: &HashMap,
-) -> Result<(), Box> {
+) -> Result> {
let line = line.trim();
if line.is_empty() {
- return Ok(());
+ return Ok(ReplAction::Continue);
}
let _ = rl.add_history_entry(line);
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.is_empty() {
- return Ok(());
+ return Ok(ReplAction::Continue);
}
match parts[0] {
"help" => print_repl_help(),
"exit" | "quit" => {
println!("Goodbye!");
- return Err("exit".into());
+ return Ok(ReplAction::Exit);
}
"list" | "ls" => {
handle_list_command(&parts[1..], device, user_id, uad_lists)?;
}
"info" => {
- handle_info_command(&parts[1..], device, uad_lists)?;
+ handle_info_command(&parts[1..], device, user.id, uad_lists)?;
}
"uninstall" | "rm" => {
handle_state_change_command(
@@ -156,7 +160,7 @@ fn handle_repl_line(
}
}
- Ok(())
+ Ok(ReplAction::Continue)
}
/// Parse REPL arguments into filters
@@ -249,6 +253,7 @@ fn handle_list_command(
fn handle_info_command(
args: &[&str],
device: &Phone,
+ user_id: u16,
uad_lists: &HashMap,
) -> Result<(), Box> {
if args.is_empty() {
@@ -267,8 +272,8 @@ fn handle_info_command(
println!(" Not found in UAD lists (unlisted package)");
}
- let state =
- get_package_state(&device.adb_id, package, None).ok_or("Package not found on device")?;
+ let state = get_package_state(&device.adb_id, package, Some(user_id))
+ .ok_or("Package not found on device")?;
println!(" State: {}", state);
Ok(())
From 02ba6e2cca0a019165151311d283738c5e081170 Mon Sep 17 00:00:00 2001
From: Angel J <78835633+iamanaws@users.noreply.github.com>
Date: Sat, 25 Apr 2026 10:21:16 -0700
Subject: [PATCH 088/111] refactor: move theme to uad-gui; drop core gui deps;
mark PmCommand must-use
---
Cargo.lock | 2 -
crates/uad-cli/Cargo.toml | 1 -
crates/uad-cli/README.md | 2 +-
crates/uad-core/Cargo.toml | 4 -
crates/uad-core/src/adb.rs | 2 +-
crates/uad-core/src/config.rs | 10 +-
crates/uad-core/src/lib.rs | 1 -
crates/uad-core/src/theme.rs | 231 ----------------------------------
crates/uad-core/src/utils.rs | 15 +--
crates/uad-gui/Cargo.toml | 3 +-
crates/uad-gui/src/gui.rs | 10 +-
crates/uad-gui/src/theme.rs | 219 ++++++++++++++++++++++++++------
flake.lock | 6 +-
flake.nix | 8 +-
14 files changed, 205 insertions(+), 309 deletions(-)
delete mode 100644 crates/uad-core/src/theme.rs
diff --git a/Cargo.lock b/Cargo.lock
index 63ccf02..8a0a55e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4558,10 +4558,8 @@ version = "1.2.0"
dependencies = [
"chrono",
"csv",
- "dark-light",
"dirs",
"flate2",
- "iced",
"log",
"retry",
"serde",
diff --git a/crates/uad-cli/Cargo.toml b/crates/uad-cli/Cargo.toml
index d0118ae..6045f95 100644
--- a/crates/uad-cli/Cargo.toml
+++ b/crates/uad-cli/Cargo.toml
@@ -44,7 +44,6 @@ format_push_string = "warn"
large_include_file = "warn"
shadow_unrelated = "warn"
struct_field_names = "allow" # annoying
-module_name_repetitions = "allow" # annoying
disallowed_types = "deny"
disallowed_methods = "deny"
diff --git a/crates/uad-cli/README.md b/crates/uad-cli/README.md
index 86a2a77..5376342 100644
--- a/crates/uad-cli/README.md
+++ b/crates/uad-cli/README.md
@@ -191,7 +191,7 @@ uad completions powershell > uad.ps1
## Examples
-### Remove all Facebook packages
+### Remove Facebook packages
```bash
uad list --search facebook
diff --git a/crates/uad-core/Cargo.toml b/crates/uad-core/Cargo.toml
index b73d746..f7d3a43 100644
--- a/crates/uad-core/Cargo.toml
+++ b/crates/uad-core/Cargo.toml
@@ -12,7 +12,6 @@ edition.workspace = true
[features]
default = []
-gui = ["dep:iced", "dep:dark-light"]
self-update = ["dep:flate2", "dep:tar"]
[dependencies]
@@ -25,8 +24,6 @@ dirs.workspace = true
ureq.workspace = true
retry.workspace = true
csv.workspace = true
-iced = { workspace = true, optional = true }
-dark-light = { workspace = true, optional = true }
flate2 = { workspace = true, optional = true }
tar = { workspace = true, optional = true }
@@ -47,7 +44,6 @@ format_push_string = "warn"
large_include_file = "warn"
shadow_unrelated = "warn"
struct_field_names = "allow" # annoying
-module_name_repetitions = "allow" # annoying
disallowed_types = "deny"
disallowed_methods = "deny"
diff --git a/crates/uad-core/src/adb.rs b/crates/uad-core/src/adb.rs
index 8d06268..1104b61 100644
--- a/crates/uad-core/src/adb.rs
+++ b/crates/uad-core/src/adb.rs
@@ -229,7 +229,6 @@ impl Default for ACommand {
pub struct ShellCommand(ACommand);
impl ShellCommand {
/// `pm` command builder
- #[must_use]
pub fn pm(mut self) -> PmCommand {
self.0.0.arg("pm");
PmCommand(self)
@@ -335,6 +334,7 @@ pub const PM_CLEAR_PACK: &str = "pm clear";
/// Builder object for an Android Package Manager command.
///
#[derive(Debug)]
+#[must_use]
pub struct PmCommand(ShellCommand);
impl PmCommand {
/// `list packages -s` sub-command, [`PACK_PREFIX`] stripped.
diff --git a/crates/uad-core/src/config.rs b/crates/uad-core/src/config.rs
index eebfc63..5522b16 100644
--- a/crates/uad-core/src/config.rs
+++ b/crates/uad-core/src/config.rs
@@ -1,13 +1,15 @@
use crate::CACHE_DIR;
use crate::CONFIG_DIR;
+use crate::sync::User;
use crate::utils::DisplayablePath;
-use crate::{sync::User, theme::Theme};
use log::error;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
use std::sync::LazyLock;
+const DEFAULT_THEME: &str = "Auto (follow system theme)";
+
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
pub struct Config {
pub general: GeneralSettings,
@@ -44,7 +46,7 @@ pub struct DeviceSettings {
impl Default for GeneralSettings {
fn default() -> Self {
Self {
- theme: Theme::default().to_string(),
+ theme: DEFAULT_THEME.to_string(),
expert_mode: false,
backup_folder: CACHE_DIR.join("backups"),
}
@@ -114,7 +116,7 @@ mod tests {
let config = Config::load_configuration_file();
// non-deterministic
//assert_eq!(config.devices.len(), 0);
- assert_eq!(config.general.theme, Theme::default().to_string());
+ assert_eq!(config.general.theme, DEFAULT_THEME);
assert!(!config.general.expert_mode);
assert_eq!(config.general.backup_folder, CACHE_DIR.join("backups"));
}
@@ -136,7 +138,7 @@ mod tests {
fn test_default_config() {
let config = Config::default();
assert_eq!(config.devices.len(), 0);
- assert_eq!(config.general.theme, Theme::default().to_string());
+ assert_eq!(config.general.theme, DEFAULT_THEME);
assert!(!config.general.expert_mode);
assert_eq!(config.general.backup_folder, CACHE_DIR.join("backups"));
}
diff --git a/crates/uad-core/src/lib.rs b/crates/uad-core/src/lib.rs
index 76b1271..be3e5b4 100644
--- a/crates/uad-core/src/lib.rs
+++ b/crates/uad-core/src/lib.rs
@@ -11,7 +11,6 @@ pub mod adb;
pub mod config;
pub mod save;
pub mod sync;
-pub mod theme;
pub mod uad_lists;
pub mod update;
pub mod utils;
diff --git a/crates/uad-core/src/theme.rs b/crates/uad-core/src/theme.rs
deleted file mode 100644
index 71a8cfe..0000000
--- a/crates/uad-core/src/theme.rs
+++ /dev/null
@@ -1,231 +0,0 @@
-#[cfg(feature = "gui")]
-use dark_light;
-#[cfg(feature = "gui")]
-use iced::theme::{self, Mode, Palette, Style};
-#[cfg(feature = "gui")]
-use iced::{Color, color};
-#[cfg(feature = "gui")]
-use std::sync::LazyLock;
-
-/*
-In-memory caching.
-This fixes the perf bug
-caused by Iced repeatedly calling `palette`.
-
-Coincidentally, this also ensures consistent colors across the GUI,
-at the cost of requiring a restart to update the palette.
-(this is just a patch, not a fix)
-*/
-#[cfg(feature = "gui")]
-pub static OS_COLOR_SCHEME: LazyLock =
- LazyLock::new(|| dark_light::detect().unwrap_or(dark_light::Mode::Unspecified));
-
-#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
-/// Color scheme
-pub enum Theme {
- #[default]
- /// `Dark` or `Light`, according to `dark_light`
- Auto,
- /// `Dark`-ish and purple
- Lupin,
- /// white on black
- Dark,
- /// black on white
- Light,
-}
-
-#[cfg(feature = "gui")]
-#[derive(Debug, Clone, Copy)]
-pub struct BaseColors {
- pub background: Color,
- pub foreground: Color,
-}
-
-#[cfg(feature = "gui")]
-#[derive(Debug, Clone, Copy)]
-pub struct NormalColors {
- pub primary: Color,
- #[allow(dead_code, reason = "Reserved for future palette updates")]
- pub secondary: Color,
- pub surface: Color,
- pub error: Color,
-}
-
-#[cfg(feature = "gui")]
-#[derive(Debug, Clone, Copy)]
-pub struct BrightColors {
- pub primary: Color,
- pub secondary: Color,
- pub surface: Color,
- pub error: Color,
-}
-
-#[cfg(feature = "gui")]
-#[derive(Debug, Clone, Copy)]
-pub struct ColorPalette {
- pub base: BaseColors,
- pub normal: NormalColors,
- pub bright: BrightColors,
-}
-
-impl Theme {
- pub const ALL: [Self; 4] = [Self::Auto, Self::Lupin, Self::Dark, Self::Light];
-
- #[allow(
- clippy::unreadable_literal,
- reason = "https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/pull/578#discussion_r1759653408"
- )]
- /// This `fn` _could_ be `const`,
- /// but `deref`ing a lazy-`static` is non-`const`.
- #[must_use]
- #[cfg(feature = "gui")]
- pub fn palette(self) -> ColorPalette {
- const DARK: ColorPalette = ColorPalette {
- base: BaseColors {
- background: color!(0x111111),
- foreground: color!(0x1C1C1C),
- },
- normal: NormalColors {
- primary: color!(0x5E4266),
- secondary: color!(0x386E50),
- surface: color!(0x828282),
- error: color!(0x992B2B),
- },
- bright: BrightColors {
- primary: color!(0xBA84FC),
- secondary: color!(0x49EB7A),
- surface: color!(0xE0E0E0),
- error: color!(0xC13047),
- },
- };
- const LIGHT: ColorPalette = ColorPalette {
- base: BaseColors {
- background: color!(0xEEEEEE),
- foreground: color!(0xE0E0E0),
- },
- normal: NormalColors {
- primary: color!(0x818181),
- secondary: color!(0xF9D659),
- surface: color!(0x818181),
- error: color!(0x992B2B),
- },
- bright: BrightColors {
- primary: color!(0x673AB7),
- secondary: color!(0x3797A4),
- surface: color!(0x000000),
- error: color!(0xC13047),
- },
- };
- const LUPIN: ColorPalette = ColorPalette {
- base: BaseColors {
- background: color!(0x282A36),
- foreground: color!(0x353746),
- },
- normal: NormalColors {
- primary: color!(0x58406F),
- secondary: color!(0x386E50),
- surface: color!(0xA2A4A3),
- error: color!(0xA13034),
- },
- bright: BrightColors {
- primary: color!(0xBD94F9),
- secondary: color!(0x49EB7A),
- surface: color!(0xF4F8F3),
- error: color!(0xE63E6D),
- },
- };
- match self {
- Self::Dark => DARK,
- Self::Light => LIGHT,
- Self::Lupin => LUPIN,
- Self::Auto => match *OS_COLOR_SCHEME {
- dark_light::Mode::Light => LIGHT,
- dark_light::Mode::Dark | dark_light::Mode::Unspecified => DARK,
- },
- }
- }
-}
-
-impl std::fmt::Display for Theme {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(
- f,
- "{}",
- match self {
- Self::Dark => "Dark",
- Self::Light => "Light",
- Self::Lupin => "Lupin",
- Self::Auto => "Auto (follow system theme)",
- }
- )
- }
-}
-
-/// Converts a string to the GUI's Theme type
-#[must_use]
-pub fn string_to_theme(theme: &str) -> Theme {
- match theme {
- "Lupin" => Theme::Lupin,
- "Dark" => Theme::Dark,
- "Light" => Theme::Light,
- _ => Theme::Auto,
- }
-}
-
-#[cfg(feature = "gui")]
-impl theme::Base for Theme {
- fn default(preference: Mode) -> Self {
- match preference {
- Mode::Light => Self::Light,
- Mode::Dark => Self::Dark,
- Mode::None => match *OS_COLOR_SCHEME {
- dark_light::Mode::Light => Self::Light,
- dark_light::Mode::Dark | dark_light::Mode::Unspecified => Self::Dark,
- },
- }
- }
-
- fn mode(&self) -> Mode {
- let resolved = match self {
- Self::Auto => match *OS_COLOR_SCHEME {
- dark_light::Mode::Light => Self::Light,
- dark_light::Mode::Dark | dark_light::Mode::Unspecified => Self::Dark,
- },
- other => *other,
- };
-
- match resolved {
- Self::Light => Mode::Light,
- _ => Mode::Dark,
- }
- }
-
- fn base(&self) -> Style {
- let p = Self::palette(*self);
- Style {
- background_color: p.base.background,
- text_color: p.bright.surface,
- }
- }
-
- fn palette(&self) -> Option {
- let p = Self::palette(*self);
- Some(Palette {
- background: p.base.background,
- text: p.bright.surface,
- primary: p.normal.primary,
- success: p.bright.secondary,
- warning: p.normal.surface,
- danger: p.normal.error,
- })
- }
-
- fn name(&self) -> &str {
- match self {
- Self::Dark => "Dark",
- Self::Light => "Light",
- Self::Lupin => "Lupin",
- Self::Auto => "Auto",
- }
- }
-}
diff --git a/crates/uad-core/src/utils.rs b/crates/uad-core/src/utils.rs
index 0a89cdd..3569162 100644
--- a/crates/uad-core/src/utils.rs
+++ b/crates/uad-core/src/utils.rs
@@ -3,7 +3,6 @@
use crate::{
adb::{ACommand as AdbCommand, PmListPacksFlag},
sync::{CorePackage, User},
- theme::Theme,
uad_lists::{PackageHashMap, PackageState, Removal, UadList},
};
use chrono::{DateTime, offset::Utc};
@@ -128,22 +127,10 @@ pub fn fetch_packages(
};
user_package.push(package);
}
- user_package.sort_by_key(|a| a.name.to_lowercase());
+ user_package.sort_by_key(|package| package.name.to_lowercase());
user_package
}
-#[must_use]
-pub fn string_to_theme(theme: &str) -> Theme {
- match theme {
- "Dark" => Theme::Dark,
- "Light" => Theme::Light,
- "Lupin" => Theme::Lupin,
- // Auto uses `Display`, so it doesn't have a canonical repr
- t if t.starts_with("Auto") => Theme::Auto,
- _ => Theme::default(),
- }
-}
-
#[must_use]
pub fn setup_uad_dir(dir: &Path) -> PathBuf {
let dir = dir.join("uad");
diff --git a/crates/uad-gui/Cargo.toml b/crates/uad-gui/Cargo.toml
index abc4f42..4a50636 100644
--- a/crates/uad-gui/Cargo.toml
+++ b/crates/uad-gui/Cargo.toml
@@ -22,7 +22,7 @@ no-self-update = []
img = ["image", "iced/image"]
[dependencies]
-uad-core = { path = "../uad-core", features = ["gui", "self-update"] }
+uad-core = { path = "../uad-core", features = ["self-update"] }
iced.workspace = true
image = { workspace = true, optional = true }
rfd.workspace = true
@@ -54,7 +54,6 @@ format_push_string = "warn"
large_include_file = "warn"
shadow_unrelated = "warn"
struct_field_names = "allow" # annoying
-module_name_repetitions = "allow" # annoying
disallowed_types = "deny"
disallowed_methods = "deny"
diff --git a/crates/uad-gui/src/gui.rs b/crates/uad-gui/src/gui.rs
index e171552..925aedf 100644
--- a/crates/uad-gui/src/gui.rs
+++ b/crates/uad-gui/src/gui.rs
@@ -1,7 +1,7 @@
-use crate::theme::string_to_theme;
#[cfg(feature = "img")]
use crate::theme::OS_COLOR_SCHEME;
use crate::theme::Theme;
+use crate::theme::string_to_theme;
use crate::views::about::{About as AboutView, Message as AboutMessage};
use crate::views::list::{
List as AppsView, LoadingState as ListLoadingState, Message as AppsMessage,
@@ -9,13 +9,13 @@ use crate::views::list::{
use crate::views::settings::{Message as SettingsMessage, Settings as SettingsView};
use crate::widgets::navigation_menu::nav_menu;
use iced::font;
+use iced::widget::column;
#[cfg(feature = "img")]
use iced::window::icon;
-#[cfg(feature = "img")]
-use image::ImageFormat;
-use iced::widget::column;
use iced::{Alignment, Element, Length, Settings, Task, window::Settings as Window};
use iced::{Subscription, event, keyboard};
+#[cfg(feature = "img")]
+use image::ImageFormat;
use log::{debug, error, info};
#[cfg(feature = "self-update")]
use std::path::PathBuf;
@@ -434,7 +434,7 @@ impl UadGui {
pub fn start() -> iced::Result {
#[cfg(feature = "img")]
let logo: &[u8] = match *OS_COLOR_SCHEME {
- // remember to keep `Unspecified` in sync with `src/core/theme`
+ // remember to keep `Unspecified` in sync with `src/theme`
dark_light::Mode::Dark | dark_light::Mode::Unspecified => {
include_bytes!("../../../resources/assets/logo-dark.png")
}
diff --git a/crates/uad-gui/src/theme.rs b/crates/uad-gui/src/theme.rs
index 3c4c263..e18a428 100644
--- a/crates/uad-gui/src/theme.rs
+++ b/crates/uad-gui/src/theme.rs
@@ -1,72 +1,219 @@
use iced::theme::{self, Mode, Palette, Style};
+use iced::{Color, color};
+use std::sync::LazyLock;
-pub use uad_core::theme::{BaseColors, BrightColors, ColorPalette, NormalColors, OS_COLOR_SCHEME};
+/*
+In-memory caching.
+This fixes the perf bug
+caused by Iced repeatedly calling `palette`.
-/// GUI-local wrapper around the core Theme to satisfy orphan rules for
-/// iced's Catalog traits.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct Theme(pub uad_core::theme::Theme);
+Coincidentally, this also ensures consistent colors across the GUI,
+at the cost of requiring a restart to update the palette.
+(this is just a patch, not a fix)
+*/
+pub static OS_COLOR_SCHEME: LazyLock =
+ LazyLock::new(|| dark_light::detect().unwrap_or(dark_light::Mode::Unspecified));
+
+#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
+/// Color scheme
+pub enum Theme {
+ #[default]
+ /// `Dark` or `Light`, according to `dark_light`
+ Auto,
+ /// `Dark`-ish and purple
+ Lupin,
+ /// white on black
+ Dark,
+ /// black on white
+ Light,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct BaseColors {
+ pub background: Color,
+ pub foreground: Color,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct NormalColors {
+ pub primary: Color,
+ #[allow(dead_code, reason = "Reserved for future palette updates")]
+ pub secondary: Color,
+ pub surface: Color,
+ pub error: Color,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct BrightColors {
+ pub primary: Color,
+ pub secondary: Color,
+ pub surface: Color,
+ pub error: Color,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct ColorPalette {
+ pub base: BaseColors,
+ pub normal: NormalColors,
+ pub bright: BrightColors,
+}
-#[allow(
- non_upper_case_globals,
- reason = "Keep variant-like names matching core Theme"
-)]
impl Theme {
- pub const Auto: Self = Self(uad_core::theme::Theme::Auto);
- pub const Lupin: Self = Self(uad_core::theme::Theme::Lupin);
- pub const Dark: Self = Self(uad_core::theme::Theme::Dark);
- pub const Light: Self = Self(uad_core::theme::Theme::Light);
-
pub const ALL: [Self; 4] = [Self::Auto, Self::Lupin, Self::Dark, Self::Light];
+ #[allow(
+ clippy::unreadable_literal,
+ reason = "https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/pull/578#discussion_r1759653408"
+ )]
+ /// This `fn` _could_ be `const`,
+ /// but `deref`ing a lazy-`static` is non-`const`.
#[must_use]
pub fn palette(self) -> ColorPalette {
- self.0.palette()
+ const DARK: ColorPalette = ColorPalette {
+ base: BaseColors {
+ background: color!(0x111111),
+ foreground: color!(0x1C1C1C),
+ },
+ normal: NormalColors {
+ primary: color!(0x5E4266),
+ secondary: color!(0x386E50),
+ surface: color!(0x828282),
+ error: color!(0x992B2B),
+ },
+ bright: BrightColors {
+ primary: color!(0xBA84FC),
+ secondary: color!(0x49EB7A),
+ surface: color!(0xE0E0E0),
+ error: color!(0xC13047),
+ },
+ };
+ const LIGHT: ColorPalette = ColorPalette {
+ base: BaseColors {
+ background: color!(0xEEEEEE),
+ foreground: color!(0xE0E0E0),
+ },
+ normal: NormalColors {
+ primary: color!(0x818181),
+ secondary: color!(0xF9D659),
+ surface: color!(0x818181),
+ error: color!(0x992B2B),
+ },
+ bright: BrightColors {
+ primary: color!(0x673AB7),
+ secondary: color!(0x3797A4),
+ surface: color!(0x000000),
+ error: color!(0xC13047),
+ },
+ };
+ const LUPIN: ColorPalette = ColorPalette {
+ base: BaseColors {
+ background: color!(0x282A36),
+ foreground: color!(0x353746),
+ },
+ normal: NormalColors {
+ primary: color!(0x58406F),
+ secondary: color!(0x386E50),
+ surface: color!(0xA2A4A3),
+ error: color!(0xA13034),
+ },
+ bright: BrightColors {
+ primary: color!(0xBD94F9),
+ secondary: color!(0x49EB7A),
+ surface: color!(0xF4F8F3),
+ error: color!(0xE63E6D),
+ },
+ };
+ match self {
+ Self::Dark => DARK,
+ Self::Light => LIGHT,
+ Self::Lupin => LUPIN,
+ Self::Auto => match *OS_COLOR_SCHEME {
+ dark_light::Mode::Light => LIGHT,
+ dark_light::Mode::Dark | dark_light::Mode::Unspecified => DARK,
+ },
+ }
}
}
-impl From for Theme {
- fn from(value: uad_core::theme::Theme) -> Self {
- Self(value)
- }
-}
-
-impl From for uad_core::theme::Theme {
- fn from(value: Theme) -> Self {
- value.0
+impl std::fmt::Display for Theme {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ Self::Dark => "Dark",
+ Self::Light => "Light",
+ Self::Lupin => "Lupin",
+ Self::Auto => "Auto (follow system theme)",
+ }
+ )
}
}
/// Converts a string to the GUI's Theme type
#[must_use]
pub fn string_to_theme(theme: &str) -> Theme {
- Theme(uad_core::theme::string_to_theme(theme))
+ match theme {
+ "Lupin" => Theme::Lupin,
+ "Dark" => Theme::Dark,
+ "Light" => Theme::Light,
+ _ => Theme::Auto,
+ }
}
impl theme::Base for Theme {
fn default(preference: Mode) -> Self {
- Self(::default(preference))
+ match preference {
+ Mode::Light => Self::Light,
+ Mode::Dark => Self::Dark,
+ Mode::None => match *OS_COLOR_SCHEME {
+ dark_light::Mode::Light => Self::Light,
+ dark_light::Mode::Dark | dark_light::Mode::Unspecified => Self::Dark,
+ },
+ }
}
fn mode(&self) -> Mode {
- ::mode(&self.0)
+ let resolved = match self {
+ Self::Auto => match *OS_COLOR_SCHEME {
+ dark_light::Mode::Light => Self::Light,
+ dark_light::Mode::Dark | dark_light::Mode::Unspecified => Self::Dark,
+ },
+ other => *other,
+ };
+
+ match resolved {
+ Self::Light => Mode::Light,
+ _ => Mode::Dark,
+ }
}
fn base(&self) -> Style {
- ::base(&self.0)
+ let p = Self::palette(*self);
+ Style {
+ background_color: p.base.background,
+ text_color: p.bright.surface,
+ }
}
fn palette(&self) -> Option {
- ::palette(&self.0)
+ let p = Self::palette(*self);
+ Some(Palette {
+ background: p.base.background,
+ text: p.bright.surface,
+ primary: p.normal.primary,
+ success: p.bright.secondary,
+ warning: p.normal.surface,
+ danger: p.normal.error,
+ })
}
fn name(&self) -> &str {
- ::name(&self.0)
- }
-}
-
-impl std::fmt::Display for Theme {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- std::fmt::Display::fmt(&self.0, f)
+ match self {
+ Self::Dark => "Dark",
+ Self::Light => "Light",
+ Self::Lupin => "Lupin",
+ Self::Auto => "Auto",
+ }
}
}
diff --git a/flake.lock b/flake.lock
index 4822d9d..b3b5542 100644
--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
- "lastModified": 1765270179,
- "narHash": "sha256-g2a4MhRKu4ymR4xwo+I+auTknXt/+j37Lnf0Mvfl1rE=",
+ "lastModified": 1776949667,
+ "narHash": "sha256-GMSVw35Q+294GlrTUKlx087E31z7KurReQ1YHSKp5iw=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "677fbe97984e7af3175b6c121f3c39ee5c8d62c9",
+ "rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index b468be1..c86de56 100644
--- a/flake.nix
+++ b/flake.nix
@@ -27,10 +27,10 @@
with pkgs;
[
libglvnd
- xorg.libX11
- xorg.libXcursor
- xorg.libXi
- xorg.libXrandr
+ libX11
+ libXcursor
+ libXi
+ libXrandr
libxkbcommon
wayland
]
From 1f561b8d2d31573f457d849808511606cc6768d5 Mon Sep 17 00:00:00 2001
From: Forero-0 <175985207+Forero-0@users.noreply.github.com>
Date: Tue, 16 Jun 2026 18:22:28 -0500
Subject: [PATCH 089/111] Update uad_lists.json
---
resources/assets/uad_lists.json | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 323c7d3..4dd9076 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -11660,7 +11660,7 @@
},
"com.sec.android.smartfpsadjuster": {
"list": "Oem",
- "description": "SmartFPSAdjuster\nAdjusts FPS automatically in Samsung phones? Safe to delete.\nhttps://docs.samsungknox.com/CCMode/G985F_Q.pdf",
+ "description": "SmartFPSAdjuster\nResponsible for thermal camera adjustment and dynamic FPS control based on device temperature and hardware conditions\nLogging this data to feed an optimization algorithm using Q‑learning.\nSafe to delete.\nhttps://docs.samsungknox.com/CCMode/G985F_Q.pdf",
"dependencies": [],
"neededBy": [],
"labels": [],
@@ -43115,5 +43115,21 @@
"neededBy": [],
"labels": [],
"removal": "Recommended"
+ },
+ "com.samsung.android.messageguardsync": {
+ "list": "Oem",
+ "description": "Handles synchronizing and updating Samsung Message Guard policies.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Advanced"
+ },
+ "com.samsung.android.mcf.autohotspot": {
+ "list": "Oem",
+ "description": "I believe this is not the Auto Hotspot feature itself, but a system module that manages the internal logic behind it.\nIts role is to coordinate automatic hotspot connections and handle the user‑facing network experience.",
+ "dependencies": [],
+ "neededBy": [],
+ "labels": [],
+ "removal": "Expert"
}
}
From ddd9b16cedd49ad6f1ed8bee6bd34b640868c30f Mon Sep 17 00:00:00 2001
From: W1Z00 <84945798+W1Z00@users.noreply.github.com>
Date: Wed, 17 Jun 2026 18:38:00 +0800
Subject: [PATCH 090/111] update desc for com.mi.appfinder
---
resources/assets/uad_lists.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json
index 323c7d3..b9304fd 100644
--- a/resources/assets/uad_lists.json
+++ b/resources/assets/uad_lists.json
@@ -1011,7 +1011,7 @@
},
"com.mi.appfinder": {
"list": "Oem",
- "description": "HyperOs 2.0.202.0, it didn't break the system or ui search function or poco launcher search app function. Havent heard of it breaking stuff for others so dont think it's of much concern\n has 15 trackers",
+ "description": "HyperOS 2.0.202.0, it didn't break the system or ui search function or poco launcher search app function. Havent heard of it breaking stuff for others so dont think it's of much concern\n has 15 trackers\nNeeded for poco launcher search function in HyperOS 3.0",
"dependencies": [],
"neededBy": [],
"labels": [],
From bd1ed7ea766b0a9def0122994897461fde55359f Mon Sep 17 00:00:00 2001
From: aeonframework
Date: Mon, 22 Jun 2026 10:54:06 -0400
Subject: [PATCH 091/111] harden: validate package-name charset in
request_builder
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
`request_builder` interpolates `package` verbatim into a device-shell
action string. Every current caller reconciles the name against the live
device package list first, so this is safe today — but the safety lives in
the callers, not the sink. Add a local charset guard (Android app-ID set
`[A-Za-z0-9_.]`) so a future caller passing an unreconciled or file-sourced
name can't produce an injectable device-shell command. Rejects nothing
legitimate; fails closed (emits no command) on a malformed name.
Co-Authored-By: Claude Opus 4.8 (1M context)
---
crates/uad-core/src/sync.rs | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/crates/uad-core/src/sync.rs b/crates/uad-core/src/sync.rs
index fe83788..eb3f7e5 100644
--- a/crates/uad-core/src/sync.rs
+++ b/crates/uad-core/src/sync.rs
@@ -206,6 +206,22 @@ pub fn apply_pkg_state_commands(
/// which act on a common `package` and `user`.
#[must_use]
pub fn request_builder(commands: &[&str], package: &str, user: Option) -> Vec {
+ // Defense-in-depth: `package` is interpolated verbatim into a device-shell
+ // action, so refuse any name carrying a character that can't appear in a valid
+ // Android application-ID (`[A-Za-z0-9_.]`). Every current caller already
+ // reconciles the name against the live device package list before reaching
+ // here, so this rejects nothing legitimate — it just keeps the no-injection
+ // guarantee local to the sink instead of relying on each caller to sanitise.
+ // Fail closed: emit no command for a malformed name rather than an injectable
+ // device-shell string.
+ if package.is_empty()
+ || !package
+ .bytes()
+ .all(|b| b.is_ascii_alphanumeric() || b == b'.' || b == b'_')
+ {
+ error!("request_builder: refusing package name with invalid characters: {package:?}");
+ return Vec::new();
+ }
let maybe_user_flag = user_flag(user);
commands
.iter()
From ded17cf91d360b3391fdd9ccad450bfc5d197e86 Mon Sep 17 00:00:00 2001
From: Rudxain <76864299+Rudxain@users.noreply.github.com>
Date: Wed, 1 Jul 2026 18:40:31 -0400
Subject: [PATCH 092/111] refactor(core): allow "android" `PackageId`
---
crates/uad-core/src/adb.rs | 27 +++++++++++++++------------
crates/uad-core/src/sync.rs | 15 +++++----------
2 files changed, 20 insertions(+), 22 deletions(-)
diff --git a/crates/uad-core/src/adb.rs b/crates/uad-core/src/adb.rs
index 1104b61..e7d223c 100644
--- a/crates/uad-core/src/adb.rs
+++ b/crates/uad-core/src/adb.rs
@@ -38,7 +38,7 @@
//! For comprehensive info about ADB,
//! [see this](https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/master/docs/)
-use serde::{Deserialize, Serialize};
+use std::rc::Rc;
#[cfg(target_os = "windows")]
use std::os::windows::process::CommandExt;
@@ -275,14 +275,17 @@ pub const fn is_pkg_component(s: &[u8]) -> bool {
/// String with the invariant of being a valid package-name.
/// See [`PackageId::new`] for validation details.
-#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash)]
-pub struct PackageId(Box);
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct PackageId(Rc);
impl PackageId {
- /// Creates a package-ID if it's valid according to:
+ /// Creates a package-ID if it's `"android"` or valid according to:
/// -
/// -
#[must_use]
- pub fn new(p_id: Box) -> Option {
+ pub fn new(p_id: &str) -> Option {
+ if p_id == "android" {
+ return Some(Self(p_id.into()));
+ }
let mut components = p_id.split('.');
for _ in 0..2 {
if !components
@@ -293,7 +296,7 @@ impl PackageId {
}
}
if components.all(|comp| is_pkg_component(comp.as_bytes())) {
- Some(Self(p_id))
+ Some(Self(p_id.into()))
} else {
None
}
@@ -337,11 +340,11 @@ pub const PM_CLEAR_PACK: &str = "pm clear";
#[must_use]
pub struct PmCommand(ShellCommand);
impl PmCommand {
- /// `list packages -s` sub-command, [`PACK_PREFIX`] stripped.
+ /// `list packages -s` sub-command, [`PACK_PREFIX`] stripped from each element.
///
/// `Ok` variant:
- /// - isn't guaranteed to contain valid pack-IDs,
- /// as "android" can be printed but it's invalid
+ /// - isn't 100% guaranteed to contain valid pack-IDs
+ /// but you can assume it does (except in `unsafe {}` blocks)
/// - isn't sorted
/// - duplicates never _seem_ to happen, but don't assume uniqueness
pub fn list_packages_sys(
@@ -366,7 +369,7 @@ impl PmCommand {
.map(|p_ln| {
debug_assert!(p_ln.starts_with(PACK_PREFIX));
let p = &p_ln[PACK_PREFIX.len()..];
- debug_assert!(PackageId::new(p.into()).is_some() || p == "android");
+ debug_assert!(PackageId::new(p).is_some());
String::from(p)
})
.collect()
@@ -473,7 +476,7 @@ mod tests {
"the.🎂.is.a.lie",
"EXCLAMATION!!!!",
] {
- assert_eq!(PackageId::new(p_id.into()), None);
+ assert_eq!(PackageId::new(p_id), None);
}
}
@@ -490,7 +493,7 @@ mod tests {
"com.github.w1nst0n",
"this_.String_.is_.not_.real_",
] {
- assert_ne!(PackageId::new(p_id.into()), None);
+ assert_ne!(PackageId::new(p_id), None);
}
}
}
diff --git a/crates/uad-core/src/sync.rs b/crates/uad-core/src/sync.rs
index eb3f7e5..9bdd7cc 100644
--- a/crates/uad-core/src/sync.rs
+++ b/crates/uad-core/src/sync.rs
@@ -1,5 +1,5 @@
use crate::{
- adb::{ACommand as AdbCommand, PM_CLEAR_PACK},
+ adb::{ACommand as AdbCommand, PM_CLEAR_PACK, PackageId},
uad_lists::PackageState,
};
use log::{error, info};
@@ -207,19 +207,14 @@ pub fn apply_pkg_state_commands(
#[must_use]
pub fn request_builder(commands: &[&str], package: &str, user: Option) -> Vec {
// Defense-in-depth: `package` is interpolated verbatim into a device-shell
- // action, so refuse any name carrying a character that can't appear in a valid
- // Android application-ID (`[A-Za-z0-9_.]`). Every current caller already
+ // action, so refuse any invalid name/ID. Every current caller already
// reconciles the name against the live device package list before reaching
// here, so this rejects nothing legitimate — it just keeps the no-injection
// guarantee local to the sink instead of relying on each caller to sanitise.
// Fail closed: emit no command for a malformed name rather than an injectable
// device-shell string.
- if package.is_empty()
- || !package
- .bytes()
- .all(|b| b.is_ascii_alphanumeric() || b == b'.' || b == b'_')
- {
- error!("request_builder: refusing package name with invalid characters: {package:?}");
+ if PackageId::new(package).is_some() {
+ error!("request_builder: refusing invalid package name: {package:?}");
return Vec::new();
}
let maybe_user_flag = user_flag(user);
@@ -300,7 +295,7 @@ pub fn capture_cross_user_states(
/// Detect cross-user behavior and return appropriate notification message.
/// This handles unexpected cross-user behavior:
/// - Case A: Uninstall → Restore (package appears on other users)
-/// - Case B: Uninstall → Uninstall (package disappears from other users that previously had it)
+/// - Case B: Uninstall → Uninstall (package disappears from other users that previously had it)
/// - Case C: Restore → Restore (package appears on other users)
#[must_use]
pub fn detect_cross_user_behavior(
From 1623d39b55eb2c01f4ab10f17921a883d08127cc Mon Sep 17 00:00:00 2001
From: Angel J <78835633+iamanaws@users.noreply.github.com>
Date: Wed, 17 Jun 2026 22:04:25 -0700
Subject: [PATCH 093/111] chore(deps): bump clap to 4.6.1
---
Cargo.lock | 28 ++++++++++++++--------------
Cargo.toml | 2 +-
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 8a0a55e..35591e2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -102,9 +102,9 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.21"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
+checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -123,9 +123,9 @@ checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
-version = "0.2.7"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
dependencies = [
"utf8parse",
]
@@ -716,9 +716,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.58"
+version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806"
+checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
dependencies = [
"clap_builder",
"clap_derive",
@@ -726,9 +726,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.58"
+version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2"
+checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [
"anstream",
"anstyle",
@@ -747,9 +747,9 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.5.55"
+version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
+checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
dependencies = [
"heck",
"proc-macro2",
@@ -3457,9 +3457,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.44"
+version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
@@ -4202,9 +4202,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.115"
+version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12"
+checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index 3529c3e..b245c46 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,7 +37,7 @@ dark-light = "2"
fern = { version = "^0", features = ["colored"] }
# CLI dependencies
-clap = { version = "4.5", features = ["derive"] }
+clap = { version = "4.6.1", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
# Platform-specific dependencies
From f9e4f141c0eca5494027e4d71491b7f5a52dce03 Mon Sep 17 00:00:00 2001
From: Angel J <78835633+iamanaws@users.noreply.github.com>
Date: Wed, 17 Jun 2026 22:05:25 -0700
Subject: [PATCH 094/111] chore(deps): bump tokio to 1.52.3
---
Cargo.lock | 98 +++++++-----------------------------------------------
Cargo.toml | 2 +-
2 files changed, 13 insertions(+), 87 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 35591e2..e40c813 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2366,9 +2366,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
[[package]]
name = "libc"
-version = "0.2.181"
+version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "libfuzzer-sys"
@@ -2549,9 +2549,9 @@ dependencies = [
[[package]]
name = "mio"
-version = "1.1.1"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
+checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
dependencies = [
"libc",
"wasi",
@@ -4105,12 +4105,12 @@ dependencies = [
[[package]]
name = "socket2"
-version = "0.6.2"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
+checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
dependencies = [
"libc",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -4414,9 +4414,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.49.0"
+version = "1.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
+checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
dependencies = [
"bytes",
"libc",
@@ -4431,9 +4431,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
-version = "2.6.0"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
+checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [
"proc-macro2",
"quote",
@@ -5488,15 +5488,6 @@ dependencies = [
"windows-targets 0.52.6",
]
-[[package]]
-name = "windows-sys"
-version = "0.60.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
-dependencies = [
- "windows-targets 0.53.5",
-]
-
[[package]]
name = "windows-sys"
version = "0.61.2"
@@ -5545,30 +5536,13 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm 0.52.6",
+ "windows_i686_gnullvm",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
-[[package]]
-name = "windows-targets"
-version = "0.53.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
-dependencies = [
- "windows-link",
- "windows_aarch64_gnullvm 0.53.1",
- "windows_aarch64_msvc 0.53.1",
- "windows_i686_gnu 0.53.1",
- "windows_i686_gnullvm 0.53.1",
- "windows_i686_msvc 0.53.1",
- "windows_x86_64_gnu 0.53.1",
- "windows_x86_64_gnullvm 0.53.1",
- "windows_x86_64_msvc 0.53.1",
-]
-
[[package]]
name = "windows-threading"
version = "0.2.1"
@@ -5596,12 +5570,6 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
-
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@@ -5620,12 +5588,6 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
-
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@@ -5644,24 +5606,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-[[package]]
-name = "windows_i686_gnu"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
-
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
-
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@@ -5680,12 +5630,6 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-[[package]]
-name = "windows_i686_msvc"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
-
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@@ -5704,12 +5648,6 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
-
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -5728,12 +5666,6 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
-
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@@ -5752,12 +5684,6 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
-
[[package]]
name = "winit"
version = "0.30.12"
diff --git a/Cargo.toml b/Cargo.toml
index b245c46..0464938 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -38,7 +38,7 @@ fern = { version = "^0", features = ["colored"] }
# CLI dependencies
clap = { version = "4.6.1", features = ["derive"] }
-tokio = { version = "1.0", features = ["full"] }
+tokio = { version = "1.52.3", features = ["full"] }
# Platform-specific dependencies
flate2 = "^1"
From 81291e0655be268dd2abfd0d68cf3b9ec68d0cf9 Mon Sep 17 00:00:00 2001
From: Angel J <78835633+iamanaws@users.noreply.github.com>
Date: Wed, 17 Jun 2026 22:14:41 -0700
Subject: [PATCH 095/111] fix(cli): avoid duplicate error output
---
crates/uad-cli/src/commands.rs | 14 ++++----------
crates/uad-cli/src/device.rs | 6 ++++--
crates/uad-cli/src/main.rs | 13 ++++++++++++-
3 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/crates/uad-cli/src/commands.rs b/crates/uad-cli/src/commands.rs
index 25b5bc0..62286bd 100644
--- a/crates/uad-cli/src/commands.rs
+++ b/crates/uad-cli/src/commands.rs
@@ -10,7 +10,7 @@ use uad_core::sync::{
use uad_core::uad_lists::{Package, PackageState, Removal, UadList, load_debloat_lists};
use uad_core::utils::{matches_search, truncate_description};
-use crate::device::{get_target_device, get_user};
+use crate::device::{NO_DEVICES_FOUND, get_target_device, get_user};
use crate::filters::{ListFilter, RemovalFilter, StateFilter};
use crate::{Cli, print_or_exit, println_or_exit};
@@ -20,8 +20,7 @@ pub fn list_devices() -> Result<(), Box> {
let devices = get_devices_list();
if devices.is_empty() {
- eprintln!("No devices found. Make sure ADB is installed and devices are connected.");
- return Err("No devices found".into());
+ return Err(NO_DEVICES_FOUND.into());
}
println_or_exit!("\nFound {} device(s):\n", devices.len());
@@ -250,7 +249,6 @@ pub fn change_package_state(
action_name: &str,
) -> Result<(), Box> {
if packages.is_empty() {
- eprintln!("Error: No packages specified");
return Err("No packages specified".into());
}
@@ -365,8 +363,7 @@ pub fn execute_with_fallback(
match run_adb_shell_action(&device.adb_id, cmd.as_str()) {
Ok(_) => println!("{}✓ {}", indent, cmd),
Err(e) => {
- eprintln!("{}✗ Failed: {:?}", indent, e);
- return Err(format!("Failed to execute: {}", cmd).into());
+ return Err(format!("{indent}✗ Failed to execute `{cmd}`: {e:?}").into());
}
}
}
@@ -461,10 +458,7 @@ pub fn update_lists() -> Result<(), Box> {
println!("✓ Successfully updated package lists");
Ok(())
}
- Err(_lists) => {
- eprintln!("✗ Failed to update lists from remote, using cached version");
- Err("Failed to update lists".into())
- }
+ Err(_lists) => Err("Failed to update lists from remote, using cached version".into()),
}
}
diff --git a/crates/uad-cli/src/device.rs b/crates/uad-cli/src/device.rs
index ddc23a9..54fee8c 100644
--- a/crates/uad-cli/src/device.rs
+++ b/crates/uad-cli/src/device.rs
@@ -1,12 +1,14 @@
use uad_core::sync::{Phone, User, get_devices_list};
+pub const NO_DEVICES_FOUND: &str =
+ "No devices found. Make sure ADB is installed and devices are connected.";
+
/// Get target device, either by serial or first available
pub fn get_target_device(device: Option) -> Result