1919//!
2020//! Despite being "low-level", we can still "have cake and eat it too";
2121//! After all, what's the point of an abstraction if it doesn't come with goodies?:
22- //! We can take some freedoms, such as:
23- //! - pre-parsing or validanting output, to provide types with invariants.
22+ //! We can reserve some artistic license, such as:
23+ //! - shorter names, complemented by context
24+ //! - pre-parsing or validanting output, to provide types with invariants
2425//! - strongly-typed rather than "stringly-typed" APIs
2526//! - nicer IDE support
2627//! - compile-time prevention of malformed cmds
@@ -77,14 +78,31 @@ impl Cmd {
7778 self . 0 . arg ( "shell" ) ;
7879 ShCmd ( self )
7980 }
80- /// List all detected devices:
81+ /// List attached devices (as serials) and their status :
8182 /// - USB
8283 /// - TCP/IP: WIFI, Ethernet, etc...
8384 /// - Local emulators
84- /// Some may not be authorized by the user (yet)
85- pub fn devices ( mut self ) -> Result < String , String > {
85+ /// Status can be (but not limited to):
86+ /// - "unauthorized"
87+ /// - "device"
88+ pub fn devices ( mut self ) -> Result < Vec < ( String , String ) > , String > {
8689 self . 0 . arg ( "devices" ) ;
87- self . run ( )
90+ Ok ( self
91+ . run ( ) ?
92+ . lines ( )
93+ . skip ( 1 ) // header
94+ . map ( |dev_stat| {
95+ let tab_idx = dev_stat
96+ . find ( '\t' )
97+ . expect ( "There must be 1 tab after serial" ) ;
98+ (
99+ // serial
100+ dev_stat[ ..tab_idx] . to_string ( ) ,
101+ // status
102+ dev_stat[ ( tab_idx + 1 ) ..] . to_string ( ) ,
103+ )
104+ } )
105+ . collect ( ) )
88106 }
89107 /// Reboots default device
90108 pub fn reboot ( mut self ) -> Result < String , String > {
@@ -182,9 +200,9 @@ impl ToString for PmLsPackFlag {
182200 }
183201}
184202
185- pub const PACK_URI_SCHEME : & str = "package:" ;
203+ pub const PACK_PREFIX : & str = "package:" ;
186204#[ expect( clippy:: cast_possible_truncation, reason = "" ) ]
187- pub const PACK_URI_LEN : u8 = PACK_URI_SCHEME . len ( ) as _ ;
205+ pub const PACK_URI_LEN : u8 = PACK_PREFIX . len ( ) as _ ;
188206
189207pub const PM_LIST_PACKS : & str = "pm list packages" ;
190208pub const PM_CLEAR_PACK : & str = "pm clear" ;
@@ -195,7 +213,8 @@ pub const PM_CLEAR_PACK: &str = "pm clear";
195213#[ derive( Debug ) ]
196214pub struct PmCmd ( ShCmd ) ;
197215impl PmCmd {
198- /// `list packages` sub-command
216+ /// `list packages` sub-command,
217+ /// stripped of "package:" prefix
199218 pub fn ls_packs (
200219 mut self ,
201220 f : Option < PmLsPackFlag > ,
@@ -214,13 +233,14 @@ impl PmCmd {
214233 pack_ls
215234 . lines ( )
216235 . map ( |p_ln| {
217- debug_assert ! ( p_ln. starts_with( PACK_URI_SCHEME ) ) ;
236+ debug_assert ! ( p_ln. starts_with( PACK_PREFIX ) ) ;
218237 String :: from ( & p_ln[ PACK_URI_LEN as usize ..] )
219238 } )
220239 . collect ( )
221240 } )
222241 }
223- /// `list packages` sub-command, but pre-validated
242+ /// `list packages` sub-command, pre-validated.
243+ /// This is strongly-typed, at the cost of regex overhead.
224244 pub fn ls_packs_valid (
225245 self ,
226246 f : Option < PmLsPackFlag > ,
@@ -230,9 +250,12 @@ impl PmCmd {
230250 . into_iter ( )
231251 . map ( |p| PackId :: new ( p) . expect ( "One of these is wrong: `PackId` regex, ADB implementation. Or the spec now allows a wider char-set" ) ) . collect ( ) )
232252 }
233- /// `list users` sub-command
234- pub fn ls_users ( mut self ) -> Result < String , String > {
253+ #[ allow( clippy:: doc_markdown, reason = "Multi URL" ) ]
254+ /// `list users` sub-command.
255+ /// - https://source.android.com/docs/devices/admin/multi-user-testing
256+ /// - https://stackoverflow.com/questions/37495126/android-get-list-of-users-and-profile-name
257+ pub fn ls_users ( mut self ) -> Result < Vec < String > , String > {
235258 self . 0 . 0 . 0 . args ( [ "list" , "users" ] ) ;
236- self . 0 . 0 . run ( )
259+ Ok ( self . 0 . 0 . run ( ) ? . lines ( ) . skip ( 1 ) . map ( String :: from ) . collect ( ) )
237260 }
238261}
0 commit comments