Skip to main content

tauri_plugin_android_fs/api/
picker.rs

1use sync_async::sync_async;
2use crate::*;
3use super::*;
4
5
6/// API of File/Directory Picker.
7/// 
8/// # Examples
9/// ```no_run
10/// use tauri_plugin_android_fs::{AndroidFsExt, Entry, ImageFormat, PublicImageDir, Result, Size};
11///
12/// async fn file_picker_example(app: &tauri::AppHandle<impl tauri::Runtime>) -> Result<()> {
13///     let api = app.android_fs_async();
14///
15///     let selected_files = api
16///         .picker()
17///         .pick_files(
18///             None, // Initial location
19///             &["*/*"], // Target MIME types
20///             false, // If true, only local files can be selected
21///         )
22///         .await?;
23///
24///     if !selected_files.is_empty() {
25///         for uri in selected_files {
26///             let file: std::fs::File = api.open_file_readable(&uri).await?;
27///             let file_path: tauri_plugin_fs::FilePath = uri.clone().into();
28///
29///             let file_type = api.get_mime_type(&uri).await?;
30///             let file_name = api.get_name(&uri).await?;
31///             let file_thumbnail = api.get_thumbnail(
32///                 &uri,
33///                 Size { width: 200, height: 200 },
34///                 ImageFormat::Jpeg,
35///             ).await?;
36///         }
37///     }
38///     else {
39///         // User cancelled the picker.
40///     }
41///
42///     Ok(())
43/// }
44///
45/// async fn file_saver_example(app: &tauri::AppHandle<impl tauri::Runtime>) -> Result<()> {
46///     let api = app.android_fs_async();
47///
48///     // Initial directory when the file saver opens.
49///     // Resolves to `~/Pictures/MyApp/2025-10-22/`.
50///     let initial_location = api
51///         .picker()
52///         .resolve_public_storage_initial_location(
53///             None, // Storage volume (e.g. internal storage or SD card). If `None`, uses the primary volume
54///             PublicImageDir::Pictures, // Base directory
55///             "MyApp/2025-10-22", // Relative path
56///             true, // Creates missing directories
57///         )
58///         .await?;
59///
60///     let selected_file = api
61///         .picker()
62///         .save_file(
63///             Some(&initial_location), // Initial location
64///             "my-image.jpg", // Initial file name
65///             Some("image/jpeg"), // MIME type
66///             false, // If true, only local files can be selected
67///         )
68///         .await?;
69///
70///     if let Some(uri) = selected_file {
71///         // Open the file for writing.
72///         // 
73///         // NOTE:
74///         // Existing contents will be truncated.
75///         let file: std::fs::File = api.open_file_writable(&uri).await?;
76///     }
77///     else {
78///         // User cancelled the picker.
79///     }
80///
81///     Ok(())
82/// }
83///
84/// async fn dir_picker_example(app: &tauri::AppHandle<impl tauri::Runtime>) -> Result<()> {
85///     let api = app.android_fs_async();
86///
87///     let selected = api
88///         .picker()
89///         .pick_dir(
90///             None, // Initial location
91///             false, // If true, restricts selection to directories on the local device
92///         )
93///         .await?;
94///
95///     if let Some(dir_uri) = selected {
96///         // Persist access permission across app/device restarts.
97///         api.picker().persist_uri_permission(&dir_uri).await?;
98///
99///         // Read the directory.
100///         for entry in api.read_dir(&dir_uri).await? {
101///             match entry {
102///                 Entry::File { uri, name, .. } => {
103///                     // Handle a file.
104///                 }
105///                 Entry::Dir { uri, name, .. } => {
106///                     // Handle a directory.
107///                 }
108///             }
109///         }
110///
111///         // Create a new file.
112///         // Parent directories are created recursively if necessary.
113///         let file_uri = api
114///             .create_new_file(
115///                 &dir_uri,
116///                 "MyApp/2025-1021/file.txt",
117///                 Some("text/plain"),
118///             )
119///             .await?;
120///     }
121///     else {
122///         // User cancelled the picker.
123///     }
124///
125///     Ok(())
126/// }
127/// ```
128#[sync_async]
129pub struct Picker<'a, R: tauri::Runtime> {
130    #[cfg(target_os = "android")]
131    pub(crate) handle: &'a tauri::plugin::PluginHandle<R>,
132
133    #[cfg(not(target_os = "android"))]
134    #[allow(unused)]
135    pub(crate) handle: &'a std::marker::PhantomData<fn() -> R>,
136}
137
138#[cfg(target_os = "android")]
139#[sync_async(
140    use(if_sync) impls::SyncImpls as Impls;
141    use(if_async) impls::AsyncImpls as Impls;
142)]
143impl<'a, R: tauri::Runtime> Picker<'a, R> {
144    
145    #[always_sync]
146    fn impls(&self) -> Impls<'_, R> {
147        Impls { handle: &self.handle }
148    }
149}
150
151#[sync_async(
152    use(if_async) api_async::{AndroidFs, Opener, PrivateStorage, PublicStorage};
153    use(if_sync) api_sync::{AndroidFs, Opener, PrivateStorage, PublicStorage};
154)]
155impl<'a, R: tauri::Runtime> Picker<'a, R> {
156
157    /// Opens a system file picker and returns a **read-write** URIs.  
158    /// If no file is selected or the user cancels, an empty vec is returned.  
159    /// 
160    /// By default, returned URI is valid until the app or device is terminated. 
161    /// If you want to persist it across app or device restarts, use [`Picker::persist_uri_permission`].
162    /// 
163    /// This provides a standardized file explorer-style interface, 
164    /// and also allows file selection from part of third-party apps or cloud storage.
165    ///
166    /// Removing the returned files is also supported in most cases, 
167    /// but note that files provided by third-party apps may not be removable.  
168    ///  
169    /// # Args  
170    /// - ***initial_location*** :  
171    /// Indicate the initial location of dialog.  
172    /// This URI works even without any permissions.  
173    /// There is no need to use this if there is no special reason.  
174    /// System will do its best to launch the dialog in the specified entry 
175    /// if it's a directory, or the directory that contains the specified file if not.  
176    /// If this is missing or failed to resolve the desired initial location, the initial location is system specific.  
177    /// This must be a URI taken from following or it's derivative :   
178    ///     - [`Picker::resolve_public_storage_initial_location`]
179    ///     - [`Picker::resolve_initial_location`]
180    ///     - [`Picker::pick_files`]
181    ///     - [`Picker::pick_file`]
182    ///     - [`Picker::pick_dir`]
183    ///     - [`Picker::save_file`]
184    /// 
185    /// - ***mime_types*** :  
186    /// The MIME types of the file to be selected.  
187    /// However, there is no guarantee that the returned file will match the specified types.  
188    /// If left empty, all file types will be available (equivalent to `["*/*"]`).  
189    ///  
190    /// - ***local_only*** :
191    /// Indicates whether only entry located on the local device should be selectable, without requiring it to be downloaded from a remote service when opened.
192    ///  
193    /// # Support
194    /// All Android versions supported by Tauri.
195    /// 
196    /// # References
197    /// - <https://developer.android.com/reference/android/content/Intent#ACTION_OPEN_DOCUMENT>
198    #[maybe_async]
199    pub fn pick_files(
200        &self,
201        initial_location: Option<&FsUri>,
202        mime_types: &[&str],
203        local_only: bool,
204    ) -> Result<Vec<FsUri>> {
205
206        #[cfg(not(target_os = "android"))] {
207            Err(Error::NOT_ANDROID)
208        }
209        #[cfg(target_os = "android")] {
210            self.impls().show_pick_file_dialog(initial_location, mime_types, true, local_only).await
211        }
212    }
213
214    /// Opens a system file picker and returns a **read-write** URI.  
215    /// If no file is selected or the user cancels, None is returned.  
216    /// 
217    /// By default, returned URI is valid until the app or device is terminated. 
218    /// If you want to persist it across app or device restarts, use [`Picker::persist_uri_permission`].
219    /// 
220    /// This provides a standardized file explorer-style interface, 
221    /// and also allows file selection from part of third-party apps or cloud storage.
222    ///
223    /// Removing the returned files is also supported in most cases, 
224    /// but note that files provided by third-party apps may not be removable.  
225    ///  
226    /// # Args  
227    /// - ***initial_location*** :  
228    /// Indicate the initial location of dialog.  
229    /// This URI works even without any permissions.  
230    /// There is no need to use this if there is no special reason.  
231    /// System will do its best to launch the dialog in the specified entry 
232    /// if it's a directory, or the directory that contains the specified file if not.  
233    /// If this is missing or failed to resolve the desired initial location, the initial location is system specific.  
234    /// This must be a URI taken from following or it's derivative :   
235    ///     - [`Picker::resolve_public_storage_initial_location`]
236    ///     - [`Picker::resolve_initial_location`]
237    ///     - [`Picker::pick_files`]
238    ///     - [`Picker::pick_file`]
239    ///     - [`Picker::pick_dir`]
240    ///     - [`Picker::save_file`]
241    /// 
242    /// - ***mime_types*** :  
243    /// The MIME types of the file to be selected.  
244    /// However, there is no guarantee that the returned file will match the specified types.  
245    /// If left empty, all file types will be available (equivalent to `["*/*"]`).  
246    ///  
247    /// - ***local_only*** :
248    /// Indicates whether only entry located on the local device should be selectable, without requiring it to be downloaded from a remote service when opened.
249    ///  
250    /// # Support
251    /// All Android versions supported by Tauri.
252    /// 
253    /// # References
254    /// - <https://developer.android.com/reference/android/content/Intent#ACTION_OPEN_DOCUMENT>
255    #[maybe_async]
256    pub fn pick_file(
257        &self,
258        initial_location: Option<&FsUri>,
259        mime_types: &[&str],
260        local_only: bool
261    ) -> Result<Option<FsUri>> {
262
263        #[cfg(not(target_os = "android"))] {
264            Err(Error::NOT_ANDROID)
265        }
266        #[cfg(target_os = "android")] {
267            self.impls().show_pick_file_dialog(initial_location, mime_types, false, local_only)
268                .await
269                .map(|mut i| i.pop())
270        }
271    }
272
273    /// Opens a media picker and returns a **readonly** URIs.  
274    /// If no file is selected or the user cancels, an empty vec is returned.  
275    ///  
276    /// By default, returned URI is valid until the app or device is terminated. 
277    /// If you want to persist it across app or device restarts, use [`Picker::persist_uri_permission`].
278    ///  
279    /// This media picker provides a gallery, 
280    /// sorted by date from newest to oldest. 
281    /// 
282    /// # Args  
283    /// - ***target*** :  
284    /// The media type of the file to be selected.  
285    /// Images or videos, or both.  
286    ///  
287    /// - ***local_only*** :
288    /// Indicates whether only entry located on the local device should be selectable, without requiring it to be downloaded from a remote service when opened.
289    ///  
290    /// # Note
291    /// The file obtained from this function cannot retrieve the correct file name using [`AndroidFs::get_name`].  
292    /// Instead, it will be assigned a sequential number, such as `1000091523.png`. 
293    /// And this is marked intended behavior, not a bug.
294    /// - <https://issuetracker.google.com/issues/268079113>  
295    ///  
296    /// # Support
297    /// This feature is available on devices that meet the following criteria:  
298    /// - Running Android 11 (API level 30) or higher  
299    /// - Receive changes to Modular System Components through Google System Updates  
300    ///  
301    /// Availability on a given device can be verified by calling [`Picker::is_visual_media_picker_available`].  
302    /// If not supported, this function behaves the same as [`Picker::pick_files`].  
303    /// 
304    /// # References
305    /// - <https://developer.android.com/training/data-storage/shared/photopicker>
306    #[maybe_async]
307    pub fn pick_visual_medias(
308        &self,
309        target: VisualMediaTarget<'_>,
310        local_only: bool
311    ) -> Result<Vec<FsUri>> {
312
313        #[cfg(not(target_os = "android"))] {
314            Err(Error::NOT_ANDROID)
315        }
316        #[cfg(target_os = "android")] {
317            self.impls().show_pick_visual_media_dialog(target, true, local_only).await
318        }
319    }
320
321    /// Opens a media picker and returns a **readonly** URI.  
322    /// If no file is selected or the user cancels, None is returned.  
323    ///  
324    /// By default, returned URI is valid until the app or device is terminated. 
325    /// If you want to persist it across app or device restarts, use [`Picker::persist_uri_permission`].
326    ///  
327    /// This media picker provides a gallery, 
328    /// sorted by date from newest to oldest. 
329    /// 
330    /// # Args  
331    /// - ***target*** :  
332    /// The media type of the file to be selected.  
333    /// Images or videos, or both.  
334    /// 
335    /// - ***local_only*** :
336    /// Indicates whether only entry located on the local device should be selectable, without requiring it to be downloaded from a remote service when opened.
337    ///  
338    /// # Note
339    /// The file obtained from this function cannot retrieve the correct file name using [`AndroidFs::get_name`].  
340    /// Instead, it will be assigned a sequential number, such as `1000091523.png`. 
341    /// And this is marked intended behavior, not a bug.
342    /// - <https://issuetracker.google.com/issues/268079113>  
343    ///  
344    /// # Support
345    /// This feature is available on devices that meet the following criteria:  
346    /// - Running Android 11 (API level 30) or higher  
347    /// - Receive changes to Modular System Components through Google System Updates  
348    ///  
349    /// Availability on a given device can be verified by calling [`Picker::is_visual_media_picker_available`].  
350    /// If not supported, this function behaves the same as [`Picker::pick_file`].  
351    /// 
352    /// # References
353    /// - <https://developer.android.com/training/data-storage/shared/photopicker>
354    #[maybe_async]
355    pub fn pick_visual_media(
356        &self,
357        target: VisualMediaTarget<'_>,
358        local_only: bool
359    ) -> Result<Option<FsUri>> {
360
361        #[cfg(not(target_os = "android"))] {
362            Err(Error::NOT_ANDROID)
363        }
364        #[cfg(target_os = "android")] {
365            self.impls().show_pick_visual_media_dialog(target, false, local_only)
366                .await
367                .map(|mut i| i.pop())
368        }
369    }
370
371    /// Opens a file picker and returns a **readonly** URIs.  
372    /// If no file is selected or the user cancels, an empty vec is returned.  
373    ///  
374    /// Returned URI is valid until the app or device is terminated. Can not persist it.
375    /// 
376    /// This works differently depending on the model and version.  
377    /// Recent devices often have the similar behaviour as [`Picker::pick_visual_medias`] or [`Picker::pick_files`].  
378    /// In older versions, third-party apps often handle request instead.
379    /// 
380    /// # Args  
381    /// - ***mime_types*** :  
382    /// The MIME types of the file to be selected.  
383    /// However, there is no guarantee that the returned file will match the specified types.  
384    /// If left empty, all file types will be available (equivalent to `["*/*"]`).  
385    ///  
386    /// # Support
387    /// All Android versions supported by Tauri.
388    /// 
389    /// # References
390    /// - <https://developer.android.com/reference/android/content/Intent#ACTION_GET_CONTENT>
391    #[maybe_async]
392    #[deprecated = "This may not support operations other than opening files."]
393    pub fn pick_contents(
394        &self,
395        mime_types: &[&str],
396    ) -> Result<Vec<FsUri>> {
397
398        #[cfg(not(target_os = "android"))] {
399            Err(Error::NOT_ANDROID)
400        }
401        #[cfg(target_os = "android")] {
402            self.impls().show_pick_content_dialog(mime_types, true).await
403        }
404    }
405
406    /// Opens a file picker and returns a **readonly** URI.  
407    /// If no file is selected or the user cancels, None is returned.  
408    ///  
409    /// Returned URI is valid until the app or device is terminated. Can not persist it.
410    /// 
411    /// This works differently depending on the model and version.  
412    /// Recent devices often have the similar behaviour as [`Picker::pick_visual_media`] or [`Picker::pick_file`].  
413    /// In older versions, third-party apps often handle request instead.
414    /// 
415    /// # Args  
416    /// - ***mime_types*** :  
417    /// The MIME types of the file to be selected.  
418    /// However, there is no guarantee that the returned file will match the specified types.  
419    /// If left empty, all file types will be available (equivalent to `["*/*"]`).  
420    ///  
421    /// # Support
422    /// All Android versions supported by Tauri.
423    /// 
424    /// # References
425    /// - <https://developer.android.com/reference/android/content/Intent#ACTION_GET_CONTENT>
426    #[maybe_async]
427    #[deprecated = "This may not support operations other than opening files."]
428    pub fn pick_content(
429        &self,
430        mime_types: &[&str],
431    ) -> Result<Option<FsUri>> {
432
433        #[cfg(not(target_os = "android"))] {
434            Err(Error::NOT_ANDROID)
435        }
436        #[cfg(target_os = "android")] {
437            self.impls().show_pick_content_dialog(mime_types, false)
438                .await
439                .map(|mut i| i.pop())
440        }
441    }
442
443    /// Opens a system directory picker, allowing the creation of a new directory or the selection of an existing one, 
444    /// and returns a **read-write** directory URI. 
445    /// App can fully manage entries within the returned directory.  
446    /// If no directory is selected or the user cancels, `None` is returned. 
447    /// 
448    /// By default, returned URI is valid until the app or device is terminated. 
449    /// If you want to persist it across app or device restarts, use [`Picker::persist_uri_permission`].
450    /// 
451    /// This provides a standardized file explorer-style interface,
452    /// and also allows directory selection from part of third-party apps or cloud storage.
453    /// 
454    /// # Args  
455    /// - ***initial_location*** :  
456    /// Indicate the initial location of dialog.    
457    /// This URI works even without any permissions.  
458    /// There is no need to use this if there is no special reason.  
459    /// System will do its best to launch the dialog in the specified entry 
460    /// if it's a directory, or the directory that contains the specified file if not.  
461    /// If this is missing or failed to resolve the desired initial location, the initial location is system specific.   
462    /// This must be a URI taken from following or it's derivative :   
463    ///     - [`Picker::resolve_public_storage_initial_location`]
464    ///     - [`Picker::resolve_initial_location`]
465    ///     - [`Picker::pick_files`]
466    ///     - [`Picker::pick_file`]
467    ///     - [`Picker::pick_dir`]
468    ///     - [`Picker::save_file`]
469    /// 
470    /// - ***local_only*** :
471    /// Indicates whether only entry located on the local device should be selectable, without requiring it to be downloaded from a remote service when opened.
472    ///  
473    /// # Support
474    /// All Android versions supported by Tauri.
475    /// 
476    /// # References
477    /// - <https://developer.android.com/reference/android/content/Intent#ACTION_OPEN_DOCUMENT_TREE>
478    #[maybe_async]
479    pub fn pick_dir(
480        &self,
481        initial_location: Option<&FsUri>,
482        local_only: bool
483    ) -> Result<Option<FsUri>> {
484
485        #[cfg(not(target_os = "android"))] {
486            Err(Error::NOT_ANDROID)
487        }
488        #[cfg(target_os = "android")] {
489            self.impls().show_pick_dir_dialog(initial_location, local_only).await
490        }
491    }
492
493    /// Opens a system file saver and returns a **writeonly** URI.  
494    /// The returned file may be a newly created file with no content,
495    /// or it may be an existing file with the requested MIME type.  
496    /// If the user cancels, `None` is returned. 
497    /// 
498    /// By default, returned URI is valid until the app or device is terminated. 
499    /// If you want to persist it across app or device restarts, use [`Picker::persist_uri_permission`].
500    /// 
501    /// This provides a standardized file explorer-style interface, 
502    /// and also allows file selection from part of third-party apps or cloud storage.
503    /// 
504    /// Removing and reading the returned files is also supported in most cases, 
505    /// but note that files provided by third-party apps may not.  
506    ///  
507    /// # Args  
508    /// - ***initial_location*** :  
509    /// Indicate the initial location of dialog.    
510    /// This URI works even without any permissions.  
511    /// There is no need to use this if there is no special reason.  
512    /// System will do its best to launch the dialog in the specified entry 
513    /// if it's a directory, or the directory that contains the specified file if not.  
514    /// If this is missing or failed to resolve the desired initial location, the initial location is system specific.   
515    /// This must be a URI taken from following or it's derivative :   
516    ///     - [`Picker::resolve_public_storage_initial_location`]
517    ///     - [`Picker::resolve_initial_location`]
518    ///     - [`Picker::pick_files`]
519    ///     - [`Picker::pick_file`]
520    ///     - [`Picker::pick_dir`]
521    ///     - [`Picker::save_file`]
522    /// 
523    /// - ***initial_file_name*** :  
524    /// An initial file name.  
525    /// The user may change this value before creating the file.  
526    /// If no extension is present, 
527    /// the system may infer one from ***mime_type*** and may append it to the file name. 
528    /// But this append-extension operation depends on the model and version.
529    /// 
530    /// - ***mime_type*** :  
531    /// The MIME type of the file to be saved.  
532    /// If this is None, MIME type is inferred from the extension of ***initial_file_name*** (not file name by user input)
533    /// and if that fails, `application/octet-stream` is used.  
534    /// 
535    /// - ***local_only*** :
536    /// Indicates whether only entry located on the local device should be selectable.
537    ///  
538    /// # Support
539    /// All Android versions supported by Tauri.
540    /// 
541    /// # References
542    /// - <https://developer.android.com/reference/android/content/Intent#ACTION_CREATE_DOCUMENT>
543    #[maybe_async]
544    pub fn save_file(
545        &self,
546        initial_location: Option<&FsUri>,
547        initial_file_name: impl AsRef<str>,
548        mime_type: Option<&str>,
549        local_only: bool
550    ) -> Result<Option<FsUri>> {
551        
552        #[cfg(not(target_os = "android"))] {
553            Err(Error::NOT_ANDROID)
554        }
555        #[cfg(target_os = "android")] {
556           self.impls().show_save_file_dialog(initial_location, initial_file_name, mime_type, local_only).await 
557        }
558    }
559
560    /// Builds the specified directory URI.  
561    /// 
562    /// This should only be used as `initial_location` in the file picker, such as [`Picker::pick_files`]. 
563    /// It must not be used for any other purpose.  
564    /// 
565    /// This is useful when selecting save location, 
566    /// but when selecting existing entries, `initial_location` is often better with None.
567    /// 
568    /// # Args  
569    /// - ***volume_id*** :  
570    /// ID of the storage volume, such as internal storage, SD card, etc.  
571    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
572    /// 
573    /// - ***base_dir*** :  
574    /// The base directory.  
575    ///  
576    /// - ***relative_path*** :  
577    /// The directory path relative to the base directory.  
578    /// 
579    /// - ***create_dir_all*** :  
580    /// Creates directories if missing.  
581    /// See [`PublicStorage::create_dir_all`].
582    /// If error occurs, it will be ignored.
583    ///  
584    /// # Support
585    /// All Android versions supported by Tauri.
586    ///
587    /// Note :  
588    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
589    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
590    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
591    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
592    /// - Others dirs are available in all Android versions.
593    #[maybe_async]
594    pub fn resolve_public_storage_initial_location(
595        &self,
596        volume_id: Option<&StorageVolumeId>,
597        base_dir: impl Into<PublicDir>,
598        relative_path: impl AsRef<std::path::Path>,
599        create_dir_all: bool
600    ) -> Result<FsUri> {
601
602        #[cfg(not(target_os = "android"))] {
603            Err(Error::NOT_ANDROID)
604        }
605        #[cfg(target_os = "android")] {
606            self.impls().resolve_initial_location_in_public_storage(volume_id, base_dir, relative_path, create_dir_all).await
607        }
608    }
609
610    /// Builds the storage volume root URI.  
611    /// 
612    /// This should only be used as `initial_location` in the file picker, such as [`Picker::pick_files`]. 
613    /// It must not be used for any other purpose.  
614    /// 
615    /// This is useful when selecting save location, 
616    /// but when selecting existing entries, `initial_location` is often better with None.
617    /// 
618    /// # Args  
619    /// - ***volume_id*** :  
620    /// ID of the storage volume, such as internal storage, SD card, etc.  
621    /// If `None` is provided, [`the primary storage volume`](AndroidFs::get_primary_volume) will be used.  
622    /// 
623    /// # Support
624    /// All Android versions supported by Tauri.
625    #[maybe_async]
626    pub fn resolve_initial_location(&self, volume_id: Option<&StorageVolumeId>) -> Result<FsUri> {
627        #[cfg(not(target_os = "android"))] {
628            Err(Error::NOT_ANDROID)
629        }
630        #[cfg(target_os = "android")] {
631            self.impls().resolve_root_initial_location(volume_id).await
632        }
633    }
634
635    /// Verify whether [`Picker::pick_visual_medias`] is available on a given device.
636    /// 
637    /// # Support
638    /// All Android versions supported by Tauri.
639    #[maybe_async]
640    pub fn is_visual_media_picker_available(&self) -> Result<bool> {
641        #[cfg(not(target_os = "android"))] {
642            Err(Error::NOT_ANDROID)
643        }
644        #[cfg(target_os = "android")] {
645            self.impls().is_visual_media_picker_available().await
646        }
647    }
648
649    /// Check a URI permission granted by the file picker.  
650    /// Returns false if there are no permissions.
651    /// 
652    /// # Args
653    /// - **uri** :  
654    /// URI of the target file or directory.  
655    ///
656    /// - **permission** :  
657    /// The permission you want to check.  
658    /// 
659    /// 
660    /// # Support
661    /// All Android versions supported by Tauri.
662    #[maybe_async]
663    pub fn check_uri_permission(
664        &self, 
665        uri: &FsUri, 
666        permission: UriPermission
667    ) -> Result<bool> {
668        
669        #[cfg(not(target_os = "android"))] {
670            Err(Error::NOT_ANDROID)
671        }
672        #[cfg(target_os = "android")] {
673            self.impls().check_picker_uri_permission(uri, permission).await
674        }
675    }
676
677    /// Take persistent permission to access the file, directory and its descendants.  
678    /// This is a prolongation of an already acquired permission, not the acquisition of a new one.  
679    /// 
680    /// This works by just calling, without displaying any confirmation to the user.
681    /// 
682    /// Note that [there is a limit to the total number of URI that can be made persistent by this function.](https://stackoverflow.com/questions/71099575/should-i-release-persistableuripermission-when-a-new-storage-location-is-chosen/71100621#71100621)  
683    /// Therefore, it is recommended to relinquish the unnecessary persisted URI by [`Picker::release_persisted_uri_permission`] or [`Picker::release_all_persisted_uri_permissions`].  
684    /// Persisted permissions may be relinquished by other apps, user, or by moving/removing entries.
685    /// So check by [`Picker::check_persisted_uri_permission`].  
686    /// And you can retrieve the list of persisted uris using [`Picker::get_all_persisted_uri_permissions`].
687    /// 
688    /// # Args
689    /// - **uri** :  
690    /// URI of the target file or directory.   
691    /// This must be a URI taken from following :  
692    ///     - [`Picker::pick_files`]  
693    ///     - [`Picker::pick_file`]  
694    ///     - [`Picker::pick_visual_medias`]  
695    ///     - [`Picker::pick_visual_media`]  
696    ///     - [`Picker::pick_dir`]  
697    ///     - [`Picker::save_file`]  
698    ///     - [`AndroidFs::resolve_file_uri`], [`AndroidFs::resolve_dir_uri`], [`AndroidFs::read_dir`], [`AndroidFs::create_new_file`], [`AndroidFs::create_dir_all`] :  
699    ///     If use URI from thoese fucntions, the permissions of the origin directory URI is persisted, not an entry iteself by this function. 
700    ///     Because the permissions and validity period of the descendant entry URIs depend on the origin directory.   
701    /// 
702    /// # Support
703    /// All Android versions supported by Tauri. 
704    #[maybe_async]
705    pub fn persist_uri_permission(&self, uri: &FsUri) -> Result<()> {
706        #[cfg(not(target_os = "android"))] {
707            Err(Error::NOT_ANDROID)
708        }
709        #[cfg(target_os = "android")] {
710            self.impls().persist_picker_uri_permission(uri).await
711        }
712    }
713
714    /// Check a persisted URI permission grant by [`Picker::persist_uri_permission`].  
715    /// Returns false if there are only non-persistent permissions or no permissions.
716    /// 
717    /// # Args
718    /// - **uri** :  
719    /// URI of the target file or directory.  
720    /// This must be a URI taken from following :  
721    ///     - [`Picker::pick_files`]  
722    ///     - [`Picker::pick_file`]  
723    ///     - [`Picker::pick_visual_medias`]  
724    ///     - [`Picker::pick_visual_media`]  
725    ///     - [`Picker::pick_dir`]  
726    ///     - [`Picker::save_file`]  
727    ///     - [`AndroidFs::resolve_file_uri`], [`AndroidFs::resolve_dir_uri`], [`AndroidFs::read_dir`], [`AndroidFs::create_new_file`], [`AndroidFs::create_dir_all`] :  
728    ///     If use URI from those functions, the permissions of the origin directory URI is checked, not an entry iteself by this function. 
729    ///     Because the permissions and validity period of the descendant entry URIs depend on the origin directory.   
730    /// 
731    /// - **permission** :  
732    /// The permission you want to check.  
733    /// 
734    /// # Support
735    /// All Android versions supported by Tauri.
736    #[maybe_async]
737    pub fn check_persisted_uri_permission(
738        &self, 
739        uri: &FsUri, 
740        permission: UriPermission
741    ) -> Result<bool> {
742
743        #[cfg(not(target_os = "android"))] {
744            Err(Error::NOT_ANDROID)
745        }
746        #[cfg(target_os = "android")] {
747            self.impls().check_persisted_picker_uri_permission(uri, permission).await
748        }
749    }
750
751    /// Return list of all persisted URIs that have been persisted by [`Picker::persist_uri_permission`] and currently valid.   
752    /// 
753    /// # Support
754    /// All Android versions supported by Tauri.
755    #[maybe_async]
756    pub fn get_all_persisted_uri_permissions(&self) -> Result<Vec<PersistedUriPermissionState>> {
757        #[cfg(not(target_os = "android"))] {
758            Err(Error::NOT_ANDROID)
759        }
760        #[cfg(target_os = "android")] {
761            self.impls()
762                .get_all_persisted_picker_uri_permissions().await
763                .map(|v| v.collect())
764        }
765    }
766
767    /// Relinquish a persisted URI permission grant by [`Picker::persist_uri_permission`].   
768    /// Non-persistent permissions are not released.  
769    /// 
770    /// Returns true if a persisted permission exists for the specified URI and was successfully released; 
771    /// otherwise, returns false if no persisted permission existed in the first place.
772    /// 
773    /// # Args
774    /// - ***uri*** :  
775    /// URI of the target file or directory.  
776    ///
777    /// # Support
778    /// All Android versions supported by Tauri.
779    #[maybe_async]
780    pub fn release_persisted_uri_permission(&self, uri: &FsUri) -> Result<bool> {
781        #[cfg(not(target_os = "android"))] {
782            Err(Error::NOT_ANDROID)
783        }
784        #[cfg(target_os = "android")] {
785            self.impls().release_persisted_picker_uri_permission(uri).await
786        }
787    }
788
789    /// Relinquish a all persisted uri permission grants by [`Picker::persist_uri_permission`].   
790    /// Non-persistent permissions are not released.   
791    /// 
792    /// # Support
793    /// All Android versions supported by Tauri.
794    #[maybe_async]
795    pub fn release_all_persisted_uri_permissions(&self) -> Result<()> {
796        #[cfg(not(target_os = "android"))] {
797            Err(Error::NOT_ANDROID)
798        }
799        #[cfg(target_os = "android")] {
800            self.impls().release_all_persisted_picker_uri_permissions().await
801        }
802    }
803}