mirror of
https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation.git
synced 2026-08-26 23:44:18 +02:00
Feature/Multi-device support (#49)
This commit is contained in:
parent
1dc0c02f51
commit
e49df41534
3 changed files with 119 additions and 37 deletions
|
|
@ -4,28 +4,37 @@ use crate::gui::widgets::package_row::PackageRow;
|
|||
use regex::Regex;
|
||||
use static_init::dynamic;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Phone {
|
||||
pub model: String,
|
||||
pub android_sdk: u8,
|
||||
pub user_list: Vec<User>,
|
||||
pub adb_id: String,
|
||||
}
|
||||
|
||||
impl Default for Phone {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
model: get_phone_brand(),
|
||||
android_sdk: get_android_sdk(),
|
||||
user_list: get_user_list(),
|
||||
model: "fetching devices...".to_string(),
|
||||
android_sdk: 0,
|
||||
user_list: vec![],
|
||||
adb_id: "".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Phone {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.model.to_string(),)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
pub struct User {
|
||||
pub id: u16,
|
||||
|
|
@ -37,18 +46,24 @@ impl std::fmt::Display for User {
|
|||
write!(f, "{}", format!("user {}", self.id),)
|
||||
}
|
||||
}
|
||||
pub fn adb_shell_command(args: &str) -> Result<String, String> {
|
||||
|
||||
pub fn adb_shell_command(shell: bool, args: &str) -> Result<String, String> {
|
||||
let adb_command = match shell {
|
||||
true => vec!["shell", args],
|
||||
false => vec![args],
|
||||
};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let output = Command::new("adb")
|
||||
.args(&["shell", args])
|
||||
.args(adb_command)
|
||||
.creation_flags(0x08000000) // do not open a cmd window
|
||||
.output();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let output = Command::new("adb").args(&["shell", args]).output();
|
||||
let output = Command::new("adb").args(adb_command).output();
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||
let output = Command::new("adb").args(&["shell", args]).output();
|
||||
let output = Command::new("adb").args(adb_command).output();
|
||||
|
||||
match output {
|
||||
Err(e) => {
|
||||
|
|
@ -76,7 +91,7 @@ pub fn list_all_system_packages(user_id: &Option<&User>) -> String {
|
|||
None => "pm list packages -s -u".to_string(),
|
||||
};
|
||||
|
||||
adb_shell_command(&action)
|
||||
adb_shell_command(true, &action)
|
||||
.unwrap_or_else(|_| "".to_string())
|
||||
.replace("package:", "")
|
||||
}
|
||||
|
|
@ -93,7 +108,7 @@ pub fn hashset_system_packages(state: PackageState, user_id: &Option<&User>) ->
|
|||
_ => "".to_string(), // You probably don't need to use this function for anything else
|
||||
};
|
||||
|
||||
adb_shell_command(&action)
|
||||
adb_shell_command(true, &action)
|
||||
.unwrap_or_default()
|
||||
.replace("package:", "")
|
||||
.lines()
|
||||
|
|
@ -197,7 +212,7 @@ pub fn action_handler(
|
|||
};
|
||||
|
||||
for action in actions {
|
||||
match adb_shell_command(&action) {
|
||||
match adb_shell_command(true, &action) {
|
||||
Ok(_) => {
|
||||
info!("[{}] {}", package.removal, action);
|
||||
}
|
||||
|
|
@ -214,7 +229,7 @@ pub fn action_handler(
|
|||
}
|
||||
|
||||
pub fn get_phone_model() -> String {
|
||||
match adb_shell_command("getprop ro.product.model") {
|
||||
match adb_shell_command(true, "getprop ro.product.model") {
|
||||
Ok(model) => model,
|
||||
Err(err) => {
|
||||
println!("ERROR: {}", err);
|
||||
|
|
@ -228,7 +243,7 @@ pub fn get_phone_model() -> String {
|
|||
}
|
||||
|
||||
pub fn get_android_sdk() -> u8 {
|
||||
match adb_shell_command("getprop ro.build.version.sdk") {
|
||||
match adb_shell_command(true, "getprop ro.build.version.sdk") {
|
||||
Ok(sdk) => sdk.parse().unwrap(),
|
||||
Err(_) => 0,
|
||||
}
|
||||
|
|
@ -237,7 +252,7 @@ pub fn get_android_sdk() -> u8 {
|
|||
pub fn get_phone_brand() -> String {
|
||||
format!(
|
||||
"{} {}",
|
||||
adb_shell_command("getprop ro.product.brand")
|
||||
adb_shell_command(true, "getprop ro.product.brand")
|
||||
.unwrap_or_else(|_| "".to_string())
|
||||
.trim(),
|
||||
get_phone_model()
|
||||
|
|
@ -247,8 +262,7 @@ pub fn get_phone_brand() -> String {
|
|||
pub fn get_user_list() -> Vec<User> {
|
||||
#[dynamic]
|
||||
static RE: Regex = Regex::new(r"\{([0-9]+)").unwrap();
|
||||
|
||||
match adb_shell_command("pm list users") {
|
||||
match adb_shell_command(true, "pm list users") {
|
||||
Ok(users) => RE
|
||||
.find_iter(&users)
|
||||
.enumerate()
|
||||
|
|
@ -260,3 +274,30 @@ pub fn get_user_list() -> Vec<User> {
|
|||
Err(_) => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_device_list() -> Vec<Phone> {
|
||||
#[dynamic]
|
||||
static RE: Regex = Regex::new(r"\n([[:alnum:]]+)\s+device").unwrap();
|
||||
|
||||
match adb_shell_command(false, "devices") {
|
||||
Ok(devices) => {
|
||||
let mut device_list: Vec<Phone> = vec![];
|
||||
for device in RE.captures_iter(&devices) {
|
||||
env::set_var("ANDROID_SERIAL", device[1].to_string());
|
||||
|
||||
device_list.push(Phone {
|
||||
model: get_phone_brand(),
|
||||
android_sdk: get_android_sdk(),
|
||||
user_list: get_user_list(),
|
||||
adb_id: device[1].to_string(),
|
||||
});
|
||||
}
|
||||
device_list
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
warn!("get_device_list() -> {}", err);
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,17 @@ pub mod style;
|
|||
pub mod views;
|
||||
pub mod widgets;
|
||||
|
||||
pub use crate::core::sync::Phone;
|
||||
pub use crate::core::sync::{get_device_list, Phone};
|
||||
pub use crate::core::uad_lists::Package;
|
||||
use crate::core::utils::icon;
|
||||
use std::env;
|
||||
pub use views::about::About as AboutView;
|
||||
pub use views::list::{List as AppsView, Message as AppsMessage};
|
||||
pub use views::settings::{Message as SettingsMessage, Settings as SettingsView};
|
||||
|
||||
use iced::{
|
||||
button, window::Settings as Window, Alignment, Application, Button, Column, Command, Container,
|
||||
Element, Font, Length, Row, Settings, Space, Text,
|
||||
button, pick_list, window::Settings as Window, Alignment, Application, Button, Column, Command,
|
||||
Container, Element, Font, Length, PickList, Row, Settings, Space, Text
|
||||
};
|
||||
|
||||
pub const ICONS: Font = Font::External {
|
||||
|
|
@ -34,7 +35,6 @@ impl Default for View {
|
|||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct UadGui {
|
||||
phone: Phone,
|
||||
view: View,
|
||||
apps_view: AppsView,
|
||||
about_view: AboutView,
|
||||
|
|
@ -43,6 +43,9 @@ pub struct UadGui {
|
|||
settings_btn: button::State,
|
||||
apps_btn: button::State,
|
||||
apps_refresh_btn: button::State,
|
||||
device_picklist: pick_list::State<Phone>,
|
||||
device_list: Vec<Phone>,
|
||||
selected_device: Phone,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -50,12 +53,14 @@ pub enum Message {
|
|||
// Navigation Panel
|
||||
AboutPressed,
|
||||
SettingsPressed,
|
||||
AppsRefreshPress,
|
||||
LoadDevices(usize),
|
||||
AppsPress,
|
||||
|
||||
DeviceSelected(Phone),
|
||||
AppsAction(AppsMessage),
|
||||
SettingsAction(SettingsMessage),
|
||||
Init(AppsMessage),
|
||||
RefreshButtonPressed,
|
||||
Init,
|
||||
}
|
||||
|
||||
impl Application for UadGui {
|
||||
|
|
@ -66,7 +71,7 @@ impl Application for UadGui {
|
|||
fn new(_flags: ()) -> (Self, Command<Message>) {
|
||||
(
|
||||
Self::default(),
|
||||
Command::perform(Self::load_phone_packages(), Message::Init),
|
||||
Command::perform(Self::init(), |_| { Message::Init }),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -76,20 +81,28 @@ impl Application for UadGui {
|
|||
|
||||
fn update(&mut self, message: Message) -> Command<Message> {
|
||||
match message {
|
||||
Message::Init(_) => {
|
||||
info!(
|
||||
"ANDROID_SDK: {} | PHONE: {}",
|
||||
self.phone.android_sdk, self.phone.model
|
||||
);
|
||||
Command::perform(Self::load_phone_packages(), Message::AppsAction)
|
||||
Message::Init => {
|
||||
Command::perform(Self::refresh(10), Message::LoadDevices)
|
||||
}
|
||||
Message::AppsRefreshPress => {
|
||||
self.phone = Phone::default();
|
||||
Message::RefreshButtonPressed => {
|
||||
// Save the current selected device
|
||||
let i = self.device_list.iter().position(|phone| *phone == self.selected_device).unwrap();
|
||||
self.device_list = vec![Phone::default()];
|
||||
self.selected_device = self.device_list[0].clone();
|
||||
Command::perform(Self::refresh(i), Message::LoadDevices)
|
||||
}
|
||||
Message::LoadDevices(old_selected_device) => {
|
||||
self.settings_view = SettingsView::default();
|
||||
self.device_list = get_device_list();
|
||||
self.selected_device = match old_selected_device < self.device_list.len() {
|
||||
true => self.device_list[old_selected_device].clone(),
|
||||
false => self.device_list.last().unwrap().clone(),
|
||||
};
|
||||
env::set_var("ANDROID_SERIAL", self.selected_device.adb_id.clone());
|
||||
info!("{:-^65}", "-");
|
||||
info!(
|
||||
"ANDROID_SDK: {} | PHONE: {}",
|
||||
self.phone.android_sdk, self.phone.model
|
||||
self.selected_device.android_sdk, self.selected_device.model
|
||||
);
|
||||
self.apps_view = AppsView::default();
|
||||
self.view = View::List;
|
||||
|
|
@ -109,12 +122,24 @@ impl Application for UadGui {
|
|||
}
|
||||
Message::AppsAction(msg) => self
|
||||
.apps_view
|
||||
.update(&self.settings_view, &mut self.phone, msg)
|
||||
.update(&self.settings_view, &mut self.selected_device, msg)
|
||||
.map(Message::AppsAction),
|
||||
Message::SettingsAction(msg) => {
|
||||
self.settings_view.update(msg);
|
||||
Command::none()
|
||||
}
|
||||
Message::DeviceSelected(device) => {
|
||||
self.selected_device = device;
|
||||
env::set_var("ANDROID_SERIAL", self.selected_device.adb_id.clone());
|
||||
info!("{:-^65}", "-");
|
||||
info!(
|
||||
"ANDROID_SDK: {} | PHONE: {}",
|
||||
self.selected_device.android_sdk, self.selected_device.model
|
||||
);
|
||||
self.apps_view = AppsView::default();
|
||||
self.view = View::List;
|
||||
Command::perform(Self::load_phone_packages(), Message::AppsAction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,10 +150,18 @@ impl Application for UadGui {
|
|||
.style(style::PrimaryButton(self.settings_view.theme.palette));
|
||||
|
||||
let apps_refresh_btn = Button::new(&mut self.apps_refresh_btn, refresh_icon())
|
||||
.on_press(Message::AppsRefreshPress)
|
||||
.on_press(Message::RefreshButtonPressed)
|
||||
.padding(5)
|
||||
.style(style::RefreshButton(self.settings_view.theme.palette));
|
||||
|
||||
let device_picklist = PickList::new(
|
||||
&mut self.device_picklist,
|
||||
&self.device_list,
|
||||
Some(self.selected_device.clone()),
|
||||
Message::DeviceSelected,
|
||||
)
|
||||
.style(style::PickList(self.settings_view.theme.palette));
|
||||
|
||||
let uad_version = Text::new(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
let about_btn = Button::new(&mut self.about_btn, Text::new("About"))
|
||||
|
|
@ -146,7 +179,7 @@ impl Application for UadGui {
|
|||
.align_items(Alignment::Center)
|
||||
.spacing(10)
|
||||
.push(apps_refresh_btn)
|
||||
.push(Text::new("Device: ".to_string() + &self.phone.model))
|
||||
.push(device_picklist)
|
||||
.push(Space::new(Length::Fill, Length::Shrink))
|
||||
.push(uad_version)
|
||||
.push(apps_btn)
|
||||
|
|
@ -161,7 +194,7 @@ impl Application for UadGui {
|
|||
let main_container = match self.view {
|
||||
View::List => self
|
||||
.apps_view
|
||||
.view(&self.settings_view, &self.phone)
|
||||
.view(&self.settings_view, &self.selected_device)
|
||||
.map(Message::AppsAction),
|
||||
View::About => self.about_view.view(&self.settings_view),
|
||||
View::Settings => self.settings_view.view().map(Message::SettingsAction),
|
||||
|
|
@ -193,6 +226,14 @@ impl UadGui {
|
|||
pub async fn load_phone_packages() -> AppsMessage {
|
||||
AppsMessage::LoadPackages
|
||||
}
|
||||
|
||||
pub async fn init() -> Message {
|
||||
Message::Init
|
||||
}
|
||||
|
||||
pub async fn refresh(i: usize) -> usize {
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
fn refresh_icon() -> Text {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
pub mod about;
|
||||
pub mod list;
|
||||
pub mod settings;
|
||||
pub mod settings;
|
||||
Loading…
Add table
Add a link
Reference in a new issue