tauri_plugin_android_fs/api/
public_storage.rs

1use sync_async::sync_async;
2use crate::*;
3use super::*;
4
5
6/// API of file storage that is available to other applications and users.  
7/// 
8/// # Examples
9/// ```no_run
10/// fn example(app: &tauri::AppHandle) {
11///     use tauri_plugin_android_fs::AndroidFsExt as _;
12/// 
13///     let api = app.android_fs();
14///     let public_storage = api.public_storage();
15/// }
16/// ```
17#[sync_async]
18pub struct PublicStorage<'a, R: tauri::Runtime> {
19    #[cfg(target_os = "android")]
20    pub(crate) handle: &'a tauri::plugin::PluginHandle<R>,
21
22    #[cfg(not(target_os = "android"))]
23    #[allow(unused)]
24    pub(crate) handle: &'a std::marker::PhantomData<fn() -> R>,
25}
26
27#[cfg(target_os = "android")]
28#[sync_async(
29    use(if_sync) impls::SyncImpls as Impls;
30    use(if_async) impls::AsyncImpls as Impls;
31)]
32impl<'a, R: tauri::Runtime> PublicStorage<'a, R> {
33    
34    #[always_sync]
35    fn impls(&self) -> Impls<'_, R> {
36        Impls { handle: &self.handle }
37    }
38}
39
40#[sync_async(
41    use(if_async) api_async::{AndroidFs, FileOpener, FilePicker, AppStorage, PrivateStorage};
42    use(if_sync) api_sync::{AndroidFs, FileOpener, FilePicker, AppStorage, PrivateStorage};
43)]
44impl<'a, R: tauri::Runtime> PublicStorage<'a, R> {
45
46    /// Requests file access permission from the user if needed.
47    ///
48    /// When this function returns `true`,
49    /// the app is allowed to create files in `PublicStorage` and read/write the files it creates. 
50    /// Access to files created by other apps is not guaranteed.
51    /// Additionally, after the app is uninstalled and reinstalled, 
52    /// previously created files may become inaccessible.
53    ///
54    /// # Version behavior
55    /// ### Android 11 or higher
56    /// Requests no permission.   
57    /// This function always returns `true`.
58    /// 
59    /// ### Android 10
60    /// Selects either the behavior for Android 11 or higher or for Android 9 or lower, as needed.
61    ///
62    /// ### Android 9 or lower
63    /// Requests [`WRITE_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE) and [`READ_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE) permissions.   
64    /// To request the permissions, you must declare it in `AndroidManifest.xml`.
65    /// By enabling the `legacy_storage_permission` feature,
66    /// the permissions will be declared automatically only for Android 9 or lower.
67    ///
68    /// # Support
69    /// All Android versions
70    #[maybe_async]
71    pub fn request_permission(&self) -> Result<bool> {
72        #[cfg(not(target_os = "android"))] {
73            Err(Error::NOT_ANDROID)
74        }
75        #[cfg(target_os = "android")] {
76            self.impls().request_storage_permission_for_public_storage().await
77        }
78    }
79
80    /// Indicates whether the app has file access permission.
81    ///
82    /// When this function returns `true`,
83    /// the app is allowed to create files in `PublicStorage` and read/write the files it creates. 
84    /// Access to files created by other apps is not guaranteed.
85    /// Additionally, after the app is uninstalled and reinstalled, 
86    /// previously created files may become inaccessible.
87    ///
88    /// # Version behavior
89    /// ### Android 11 or higher
90    /// Always returns `true`.
91    ///
92    /// ### Android 10
93    /// Selects either the behavior for Android 11 or higher or for Android 9 or lower, as needed.
94    ///
95    /// ### Android 9 or lower
96    /// Returns `true` if the app has been granted [`WRITE_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE) and [`READ_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE) permissions.    
97    /// See [`PublicStorage::request_permission`] for requesting the permissions.
98    ///
99    /// # Support
100    /// All Android versions.
101    #[maybe_async]
102    pub fn has_permission(&self) -> Result<bool> {
103        #[cfg(not(target_os = "android"))] {
104            Err(Error::NOT_ANDROID)
105        }
106        #[cfg(target_os = "android")] {
107            self.impls().has_storage_permission_for_public_storage().await
108        }
109    }
110
111    /// Gets a list of currently available storage volumes (internal storage, SD card, USB drive, etc.).
112    /// Be aware of TOCTOU.
113    /// 
114    /// Since read-only SD cards and similar cases may be included, 
115    /// please use [`StorageVolume { is_readonly, .. }`](StorageVolume) for filtering as needed.
116    /// 
117    /// This typically includes [`primary storage volume`](PublicStorage::get_primary_volume),
118    /// but it may occasionally be absent if the primary volume is inaccessible 
119    /// (e.g., mounted on a computer, removed, or another issue).
120    ///
121    /// Primary storage volume is always listed first, if included. 
122    /// But the order of the others is not guaranteed.  
123    /// 
124    /// # Note
125    /// For Android 9 (API level 28) or lower, 
126    /// this does not include any storage volumes other than the primary one. 
127    /// 
128    /// The volume represents the logical view of a storage volume for an individual user:
129    /// each user may have a different view for the same physical volume.
130    /// In other words, it provides a separate area for each user in a multi-user environment.
131    /// 
132    /// # Support
133    /// All Android version.  
134    #[maybe_async]
135    pub fn get_volumes(&self) -> Result<Vec<StorageVolume>> {
136        #[cfg(not(target_os = "android"))] {
137            Err(Error::NOT_ANDROID)
138        }
139        #[cfg(target_os = "android")] {
140            self.impls().get_available_storage_volumes_for_public_storage().await
141        }
142    }
143
144    /// Gets a primary storage volume.  
145    /// This is the most common and recommended storage volume for placing files that can be accessed by other apps or user.
146    /// In many cases, it is device's built-in storage.  
147    /// 
148    /// A device always has one (and one only) primary storage volume.  
149    /// 
150    /// Primary volume may not currently be accessible 
151    /// if it has been mounted by the user on their computer, 
152    /// has been removed from the device, or some other problem has happened. 
153    /// If so, this returns `None`.
154    /// 
155    /// # Note
156    /// The volume represents the logical view of a storage volume for an individual user:
157    /// each user may have a different view for the same physical volume.
158    /// In other words, it provides a separate area for each user in a multi-user environment.
159    /// 
160    /// # Support
161    /// All Android version.
162    #[maybe_async]
163    pub fn get_primary_volume(&self) -> Result<Option<StorageVolume>> {
164        #[cfg(not(target_os = "android"))] {
165            Err(Error::NOT_ANDROID)
166        }
167        #[cfg(target_os = "android")] {
168            self.impls().get_primary_storage_volume_if_available_for_public_storage().await
169        }
170    }
171
172    /// Creates a new empty file in the specified public directory of the storage volume.  
173    /// This returns a **persistent read-write** URI.
174    ///
175    /// The app can read/write it until the app is uninstalled. 
176    /// And it is **not** removed when the app itself is uninstalled.  
177    /// 
178    /// # Note
179    /// ### Android 10 or higher. 
180    /// Files are automatically registered in the appropriate MediaStore as needed. 
181    /// Scanning is triggered when the file descriptor is closed
182    /// or as part of the [`pending`](PublicStorage::set_pending) lifecycle.
183    /// 
184    /// ### Android 9 or lower
185    /// [`WRITE_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE) and [`READ_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE) permissions are required.    
186    /// This needs two steps: 
187    /// 
188    /// 1. Declare :  
189    ///     By enabling the `legacy_storage_permission` feature,  
190    ///     you can declare the permissions only for Android 9 or lower automatically at build time.  
191    ///
192    /// 2. Runtime request :  
193    ///     By calling [`PublicStorage::request_permission`],
194    ///     you can request the permissions from the user at runtime.  
195    ///
196    /// After writing content to the file, call [`PublicStorage::scan`].  
197    /// Until then, the file may not appear in the gallery or other apps.
198    /// 
199    /// # Args
200    /// - ***volume_id*** :  
201    /// The ID of the storage volume, such as internal storage or an SD card.  
202    /// Usually, you don't need to specify this unless there is a special reason.  
203    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.
204    ///
205    /// - ***base_dir*** :  
206    /// The base directory for the file.  
207    /// When using [`PublicImageDir`], only image MIME types should be used for ***mime_type***; using other types may cause errors.  
208    /// Similarly, [`PublicVideoDir`] and [`PublicAudioDir`] should only be used with their respective media types.  
209    /// Only [`PublicGeneralPurposeDir`] supports all MIME types.
210    ///
211    /// - ***relative_path*** :  
212    /// The file path relative to the base directory.  
213    /// To keep files organized, it is recommended to place your app's name directory at the top level.  
214    /// Any missing parent directories will be created automatically.  
215    /// If a file with the same name already exists, a sequential number is appended to ensure uniqueness.  
216    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
217    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
218    /// Note that append-exntesion and sanitize-path operation may vary depending on the device model and Android version.  
219    ///
220    /// - ***mime_type*** :  
221    /// The MIME type of the file to be created.  
222    /// If `None`, the MIME type will be inferred from the extension of ***relative_path***.  
223    /// If that also fails, `application/octet-stream` will be used.
224    /// 
225    /// # Support
226    /// All Android version.
227    ///
228    /// Note :  
229    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
230    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
231    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
232    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
233    /// - Others dirs are available in all Android versions.
234    #[maybe_async]
235    pub fn create_new_file(
236        &self,
237        volume_id: Option<&StorageVolumeId>,
238        base_dir: impl Into<PublicDir>,
239        relative_path: impl AsRef<std::path::Path>, 
240        mime_type: Option<&str>
241    ) -> Result<FileUri> {
242
243        #[cfg(not(target_os = "android"))] {
244            Err(Error::NOT_ANDROID)
245        }
246        #[cfg(target_os = "android")] {
247            self.impls().create_new_file_in_public_storage(
248                volume_id, 
249                base_dir, 
250                relative_path, 
251                mime_type, 
252                false
253            ).await
254        }
255    }
256
257    /// Creates a new empty file in the specified public directory of the storage volume.  
258    /// This returns a **persistent read-write** URI.
259    ///
260    /// The app can read/write it until the app is uninstalled. 
261    /// And it is **not** removed when the app itself is uninstalled.  
262    /// 
263    /// # Note
264    /// ### Android 10 or higher
265    /// Files are automatically registered in the appropriate MediaStore as needed. 
266    /// Scanning is triggered when the file descriptor is closed
267    /// or as part of the [`pending`](PublicStorage::set_pending) lifecycle.
268    /// 
269    /// Diffrences from [`PublicStorage::create_new_file`] are that
270    /// files are marked as pending and will not be visible to other apps until 
271    /// [`PublicStorage::set_pending(..., false)`](PublicStorage::set_pending) is called. 
272    ///
273    /// ### Android 9 or lower
274    /// This behavior is equal to [`PublicStorage::create_new_file`]. 
275    /// So `pending` is ignored.  
276    /// 
277    /// [`WRITE_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE) and [`READ_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE) permissions are required.    
278    /// This needs two steps: 
279    /// 
280    /// 1. Declare :  
281    ///     By enabling the `legacy_storage_permission` feature,  
282    ///     you can declare the permissions only for Android 9 or lower automatically at build time.  
283    ///
284    /// 2. Runtime request :  
285    ///     By calling [`PublicStorage::request_permission`],
286    ///     you can request the permissions from the user at runtime.  
287    ///
288    /// After writing content to the file, call [`PublicStorage::scan`].  
289    /// Until then, the file may not appear in the gallery or other apps.
290    /// 
291    /// # Args
292    /// - ***volume_id*** :  
293    /// The ID of the storage volume, such as internal storage or an SD card.  
294    /// Usually, you don't need to specify this unless there is a special reason.  
295    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.
296    ///
297    /// - ***base_dir*** :  
298    /// The base directory for the file.  
299    /// When using [`PublicImageDir`], only image MIME types should be used for ***mime_type***; using other types may cause errors.  
300    /// Similarly, [`PublicVideoDir`] and [`PublicAudioDir`] should only be used with their respective media types.  
301    /// Only [`PublicGeneralPurposeDir`] supports all MIME types.
302    ///
303    /// - ***relative_path*** :  
304    /// The file path relative to the base directory.  
305    /// To keep files organized, it is recommended to place your app's name directory at the top level.  
306    /// Any missing parent directories will be created automatically.  
307    /// If a file with the same name already exists, a sequential number is appended to ensure uniqueness.  
308    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
309    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
310    /// Note that append-exntesion and sanitize-path operation may vary depending on the device model and Android version.  
311    ///
312    /// - ***mime_type*** :  
313    /// The MIME type of the file to be created.  
314    /// If `None`, the MIME type will be inferred from the extension of ***relative_path***.  
315    /// If that also fails, `application/octet-stream` will be used.
316    /// 
317    /// # Support
318    /// All Android version.
319    ///
320    /// Note :  
321    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
322    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
323    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
324    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
325    /// - Others dirs are available in all Android versions.
326    #[maybe_async]
327    pub fn create_new_file_with_pending(
328        &self,
329        volume_id: Option<&StorageVolumeId>,
330        base_dir: impl Into<PublicDir>,
331        relative_path: impl AsRef<std::path::Path>, 
332        mime_type: Option<&str>
333    ) -> Result<FileUri> {
334
335        #[cfg(not(target_os = "android"))] {
336            Err(Error::NOT_ANDROID)
337        }
338        #[cfg(target_os = "android")] {
339            self.impls().create_new_file_in_public_storage(
340                volume_id, 
341                base_dir, 
342                relative_path, 
343                mime_type, 
344                true
345            ).await
346        }
347    }
348
349    /// Recursively create a directory and all of its parent components if they are missing.  
350    /// If it already exists, do nothing.
351    /// 
352    /// [`PublicStorage::create_new_file`] and [`PublicStorage::create_new_file_with_pending`]
353    /// do this automatically, so there is no need to use it together.
354    /// 
355    /// # Note
356    /// On Android 9 or lower,
357    /// [`WRITE_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE) and [`READ_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE) permissions are required.    
358    /// This needs two steps: 
359    /// 
360    /// 1. Declare :  
361    ///     By enabling the `legacy_storage_permission` feature,  
362    ///     you can declare the permissions only for Android 9 or lower automatically at build time.  
363    ///
364    /// 2. Runtime request :  
365    ///     By calling [`PublicStorage::request_permission`],
366    ///     you can request the permissions from the user at runtime.  
367    ///
368    /// # Args  
369    /// - ***volume_id*** :  
370    /// ID of the storage volume, such as internal storage, SD card, etc.  
371    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
372    /// 
373    /// - ***base_dir*** :  
374    /// The base directory.  
375    ///  
376    /// - ***relative_path*** :  
377    /// The directory path relative to the base directory.    
378    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
379    /// Note that sanitize-path operation may vary depending on the device model and Android version.  
380    ///
381    /// # Support
382    /// All Android Version.
383    ///
384    /// Note :  
385    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
386    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
387    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
388    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
389    /// - Others dirs are available in all Android versions.
390    #[maybe_async]
391    pub fn create_dir_all(
392        &self,
393        volume_id: Option<&StorageVolumeId>,
394        base_dir: impl Into<PublicDir>,
395        relative_path: impl AsRef<std::path::Path>, 
396    ) -> Result<()> {
397
398        #[cfg(not(target_os = "android"))] {
399            Err(Error::NOT_ANDROID)
400        }
401        #[cfg(target_os = "android")] {
402            self.impls().create_dir_all_in_public_storage(volume_id, base_dir, relative_path).await
403        }
404    }
405
406    /// Writes contents to the new file in the specified public directory of the storage volume.  
407    /// This returns a **persistent read-write** URI.
408    ///
409    /// The app can read/write it until the app is uninstalled. 
410    /// And it is **not** removed when the app itself is uninstalled.  
411    /// 
412    /// # Note
413    /// On Android 9 or lower,
414    /// [`WRITE_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE) and [`READ_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE) permissions are required.    
415    /// This needs two steps: 
416    /// 
417    /// 1. Declare :  
418    ///     By enabling the `legacy_storage_permission` feature,  
419    ///     you can declare the permissions only for Android 9 or lower automatically at build time.  
420    ///
421    /// 2. Runtime request :  
422    ///     By calling [`PublicStorage::request_permission`],
423    ///     you can request the permissions from the user at runtime.  
424    ///
425    /// # Args
426    /// - ***volume_id*** :  
427    /// The ID of the storage volume, such as internal storage or an SD card.  
428    /// Usually, you don't need to specify this unless there is a special reason.  
429    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.
430    ///
431    /// - ***base_dir*** :  
432    /// The base directory for the file.  
433    /// When using [`PublicImageDir`], only image MIME types should be used for ***mime_type***; using other types may cause errors.  
434    /// Similarly, [`PublicVideoDir`] and [`PublicAudioDir`] should only be used with their respective media types.  
435    /// Only [`PublicGeneralPurposeDir`] supports all MIME types.
436    ///
437    /// - ***relative_path*** :  
438    /// The file path relative to the base directory.  
439    /// To keep files organized, it is recommended to place your app's name directory at the top level.  
440    /// Any missing parent directories will be created automatically.  
441    /// If a file with the same name already exists, a sequential number is appended to ensure uniqueness.  
442    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
443    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
444    /// Note that append-exntesion and sanitize-path operation may vary depending on the device model and Android version.  
445    ///
446    /// - ***mime_type*** :  
447    /// The MIME type of the file to be created.  
448    /// If `None`, the MIME type will be inferred from the extension of ***relative_path***.  
449    /// If that also fails, `application/octet-stream` will be used.
450    /// 
451    /// - ***contents*** :  
452    /// Contents.
453    /// 
454    /// # Support
455    /// All Android version.
456    ///
457    /// Note :  
458    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
459    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
460    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
461    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
462    /// - Others dirs are available in all Android versions.
463    #[maybe_async]
464    pub fn write_new(
465        &self,
466        volume_id: Option<&StorageVolumeId>,
467        base_dir: impl Into<PublicDir>,
468        relative_path: impl AsRef<std::path::Path>,
469        mime_type: Option<&str>,
470        contents: impl AsRef<[u8]>
471    ) -> Result<FileUri> {
472
473        #[cfg(not(target_os = "android"))] {
474            Err(Error::NOT_ANDROID)
475        }
476        #[cfg(target_os = "android")] {
477            self.impls().write_new_file_in_public_storage(volume_id, base_dir, relative_path, mime_type, contents).await
478        }
479    }
480
481    /// Scans the specified file in MediaStore.   
482    /// By doing this, the file will be visible with corrent metadata in the Gallery and etc.
483    ///
484    /// You don’t need to call this after [`PublicStorage::write_new`].   
485    /// 
486    /// # Version behavior
487    /// ### Android 10 or higher
488    /// This function does nothing, 
489    /// because files are automatically registered in the appropriate MediaStore as needed. 
490    /// Scanning is triggered when the file descriptor is closed
491    /// or as part of the [`pending`](PublicStorage::set_pending) lifecycle.  
492    /// 
493    /// If you really need to perform this operation in this version, 
494    /// please use [`PublicStorage::_scan`].
495    ///
496    /// ### Android 9 or lower
497    /// Requests the specified file to be scanned by MediaStore.  
498    /// This function returns when the scan request has been initiated.   
499    /// 
500    /// # Args
501    /// - ***uri*** :  
502    /// The target file URI.
503    /// This must be a URI obtained from one of the following:  
504    ///     - [`PublicStorage::write_new`]
505    ///     - [`PublicStorage::create_new_file`]
506    ///     - [`PublicStorage::create_new_file_with_pending`]
507    ///     - [`PublicStorage::scan_by_path`]
508    ///
509    /// # Support
510    /// All Android versions.
511    #[maybe_async]
512    pub fn scan(
513        &self, 
514        uri: &FileUri,
515    ) -> Result<()> {
516
517        #[cfg(not(target_os = "android"))] {
518            Err(Error::NOT_ANDROID)
519        }
520        #[cfg(target_os = "android")] {
521            self.impls().scan_file_in_public_storage(uri, false).await
522        }
523    }
524
525    /// Scans the specified file in MediaStore and returns it's URI if success.   
526    /// By doing this, the file will be visible in the Gallery and etc.
527    ///
528    /// # Note
529    /// Unlike [`PublicStorage::scan`], 
530    /// this function waits until the scan is complete and then returns either success or an error.
531    /// 
532    /// # Args
533    /// - ***uri*** :  
534    /// Absolute path of the target file.
535    /// This must be a path obtained from one of the following:  
536    ///     - [`PublicStorage::resolve_path`] and it's descendants path.
537    ///     - [`PublicStorage::get_path`]
538    /// 
539    /// - ***mime_type*** :  
540    /// The MIME type of the file.  
541    /// If `None`, the MIME type will be inferred from the extension of the path.  
542    /// If that also fails, `application/octet-stream` will be used.
543    /// 
544    /// # Support
545    /// All Android version.
546    #[maybe_async]
547    pub fn scan_by_path(
548        &self, 
549        path: impl AsRef<std::path::Path>,
550        mime_type: Option<&str>
551    ) -> Result<FileUri> {
552
553        #[cfg(not(target_os = "android"))] {
554            Err(Error::NOT_ANDROID)
555        }
556        #[cfg(target_os = "android")] {
557            self.impls().scan_file_by_path_in_public_storage(path, mime_type).await
558        }
559    }
560
561    /// Specifies whether the specified file on PublicStorage is marked as pending.   
562    /// When set to `true`, the app has exclusive access to the file, and it becomes invisible to other apps.
563    /// 
564    /// If it remains `true` for more than seven days, 
565    /// the system will automatically delete the file.
566    /// 
567    /// # Note
568    /// This is available for Android 10 or higher.  
569    /// On Android 9 or lower, this does nothing. 
570    /// 
571    /// # Args
572    /// - ***uri*** :  
573    /// Target file URI.
574    /// This must be a URI obtained from one of the following:  
575    ///     - [`PublicStorage::write_new`]
576    ///     - [`PublicStorage::create_new_file`]
577    ///     - [`PublicStorage::create_new_file_with_pending`]
578    ///     - [`PublicStorage::scan_by_path`]
579    /// 
580    /// # Support
581    /// All Android version.
582    /// 
583    /// # References
584    /// - <https://developer.android.com/reference/android/provider/MediaStore.MediaColumns#IS_PENDING>
585    /// - <https://developer.android.com/training/data-storage/shared/media?hl=en#toggle-pending-status>
586    #[maybe_async]
587    pub fn set_pending(&self, uri: &FileUri, is_pending: bool) -> Result<()> {
588        #[cfg(not(target_os = "android"))] {
589            Err(Error::NOT_ANDROID)
590        }
591        #[cfg(target_os = "android")] {
592            self.impls().set_file_pending_in_public_storage(uri, is_pending).await
593        }
594    }
595
596    /// Gets the absolute path of the specified file.
597    /// 
598    /// # Note
599    /// For description and notes on path permissions and handling, 
600    /// see [`PublicStorage::resolve_path`].
601    /// It involves important constraints and required settings. 
602    /// Therefore, **operate files via paths only when it is truly necessary**.
603    /// 
604    /// # Args
605    /// - ***uri*** :   
606    /// Target file URI.
607    /// This must be a URI obtained from one of the following:  
608    ///     - [`PublicStorage::write_new`]
609    ///     - [`PublicStorage::create_new_file`]
610    ///     - [`PublicStorage::create_new_file_with_pending`]
611    ///     - [`PublicStorage::scan_by_path`]
612    /// 
613    /// # Support
614    /// All Android version.
615    #[deprecated = "File operations via paths may result in unstable behaviour and inconsistent outcomes."]
616    #[maybe_async]
617    pub fn get_path(
618        &self,
619        uri: &FileUri,
620    ) -> Result<std::path::PathBuf> {
621
622        #[cfg(not(target_os = "android"))] {
623            Err(Error::NOT_ANDROID)
624        }
625        #[cfg(target_os = "android")] {
626            self.impls().get_file_path_in_public_storage(uri).await
627        }
628    }
629
630    /// Retrieves the absolute path for a specified public directory within the given storage volume.   
631    /// This function does **not** create any directories; it only constructs the path.
632    /// 
633    /// The app is allowed to create files in the directory and read/write the files it creates. 
634    /// Access to files created by other apps is not guaranteed.
635    /// Additionally, after the app is uninstalled and reinstalled, 
636    /// previously created files may become inaccessible.
637    /// 
638    /// The directory is **not** removed when the app itself is uninstalled.  
639    /// 
640    /// It is strongly recommended to call [`PublicStorage::scan_by_path`] 
641    /// after writing to the file to request registration in MediaStore.  
642    /// 
643    /// # Note
644    /// As shown below, this involves important constraints and required settings.
645    /// Therefore, **operate files via paths only when it is truly necessary**.
646    /// 
647    /// Do not use operations such as rename or remove that rely on paths 
648    /// (including URIs obtained via [`FileUri::from_path`] with this paths), 
649    /// as they may break consistency with the MediaStore on old version.
650    /// Instead, use the URI obtained through [`PublicStorage::scan_by_path`] together with methods 
651    /// such as [`AndroidFs::rename`] or [`AndroidFs::remove_file`].
652    /// 
653    /// ### Android 11 or higher
654    /// When using [`PublicImageDir`], use only image type for file name extension, 
655    /// using other type extension or none may cause errors.
656    /// Similarly, use only the corresponding extesions for [`PublicVideoDir`] and [`PublicAudioDir`].
657    /// Only [`PublicGeneralPurposeDir`] supports all extensions and no extension. 
658    /// 
659    /// ### Android 10 or lower
660    /// [`WRITE_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE) and [`READ_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE) permissions are required.    
661    /// This needs two steps: 
662    /// 
663    /// 1. Declare :  
664    ///     By enabling the `legacy_storage_permission_include_android_10` feature,  
665    ///     you can declare the permissions only for Android 10 or lower automatically at build time.  
666    /// 
667    /// 2. Runtime request :  
668    ///     By calling [`PublicStorage::request_permission`],
669    ///     you can request the permissions from the user at runtime.  
670    ///
671    /// ### Android 10
672    /// Files within PublicStorage cannot be accessed via file paths, 
673    /// so it is necessary to declare that the app need access `PublicStorage` using the method of Android 9 or lower.   
674    /// 
675    /// For it, please [set `android:requestLegacyExternalStorage="true"`](https://developer.android.com/training/data-storage/use-cases#opt-out-in-production-app).
676    /// 
677    /// `src-tauri/gen/android/app/src/main/AndroidManifest.xml`
678    /// ```xml
679    /// <manifest ... >
680    ///     <application 
681  	///         android:requestLegacyExternalStorage="true" 
682  	///         ...
683    ///     >
684    ///         ...
685    ///     </application>
686    /// </manifest>
687    /// ```
688    /// And it is not possible to access `PublicStorage`
689	/// on volumes other than the primary storage via paths, just like on Android 9 or lower.   
690	/// But filtering using [`PublicStorage::get_volumes`]
691	/// or [`StorageVolume::is_available_for_public_storage`] may not work correctly, 
692	/// as these are intended for access via URIs.
693    /// 
694    /// # Args
695    /// - ***volume_id*** :  
696    /// ID of the storage volume, such as internal storage, SD card, etc.  
697    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
698    /// 
699    /// - ***base_dir*** :  
700    /// The base directory.  
701    /// One of [`PublicImageDir`], [`PublicVideoDir`], [`PublicAudioDir`], [`PublicGeneralPurposeDir`].  
702    ///  
703    /// # Support
704    /// All Android version.
705    /// 
706    /// Note :  
707    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
708    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
709    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
710    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
711    /// - Others dirs are available in all Android versions.
712    #[deprecated = "File operations via paths may result in unstable behaviour and inconsistent outcomes."]
713    #[maybe_async]
714    pub fn resolve_path(
715        &self,
716        volume_id: Option<&StorageVolumeId>,
717        base_dir: impl Into<PublicDir>,
718    ) -> Result<std::path::PathBuf> {
719
720        #[cfg(not(target_os = "android"))] {
721            Err(Error::NOT_ANDROID)
722        }
723        #[cfg(target_os = "android")] {
724            self.impls().resolve_dir_path_in_public_storage(volume_id, base_dir).await
725        }
726    }
727
728    /// Builds the specified directory URI.  
729    /// 
730    /// This should only be used as `initial_location` in the file picker, such as [`FilePicker::pick_files`]. 
731    /// It must not be used for any other purpose.  
732    /// 
733    /// This is useful when selecting save location, 
734    /// but when selecting existing entries, `initial_location` is often better with None.
735    /// 
736    /// # Args  
737    /// - ***volume_id*** :  
738    /// ID of the storage volume, such as internal storage, SD card, etc.  
739    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
740    /// 
741    /// - ***base_dir*** :  
742    /// The base directory.  
743    ///  
744    /// - ***relative_path*** :  
745    /// The directory path relative to the base directory.  
746    /// 
747    /// - ***create_dir_all*** :  
748    /// Creates directories if missing.  
749    /// See [`PublicStorage::create_dir_all`].
750    /// If error occurs, it will be ignored.
751    ///  
752    /// # Support
753    /// All Android version.
754    ///
755    /// Note :  
756    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
757    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
758    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
759    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
760    /// - Others dirs are available in all Android versions.
761    #[maybe_async]
762    pub fn resolve_initial_location(
763        &self,
764        volume_id: Option<&StorageVolumeId>,
765        base_dir: impl Into<PublicDir>,
766        relative_path: impl AsRef<std::path::Path>,
767        create_dir_all: bool
768    ) -> Result<FileUri> {
769
770        #[cfg(not(target_os = "android"))] {
771            Err(Error::NOT_ANDROID)
772        }
773        #[cfg(target_os = "android")] {
774            self.impls().resolve_initial_location_in_public_storage(volume_id, base_dir, relative_path, create_dir_all).await
775        }
776    }
777
778    /// Verify whether [`PublicAudioDir::Audiobooks`] is available on a given device.   
779    /// 
780    /// If on Android 10 (API level 29) or higher, this returns true.  
781    /// If on Android 9 (API level 28) and lower, this returns false.  
782    /// 
783    /// # Support
784    /// All Android version.
785    #[always_sync]
786    pub fn is_audiobooks_dir_available(&self) -> Result<bool> {
787        #[cfg(not(target_os = "android"))] {
788            Err(Error::NOT_ANDROID)
789        }
790        #[cfg(target_os = "android")] {
791            Ok(self.impls().consts()?.env_dir_audiobooks.is_some())
792        }
793    }
794
795    /// Verify whether [`PublicAudioDir::Recordings`] is available on a given device.   
796    /// 
797    /// If on Android 12 (API level 31) or higher, this returns true.  
798    /// If on Android 11 (API level 30) and lower, this returns false.  
799    /// 
800    /// # Support
801    /// All Android version.
802    #[always_sync]
803    pub fn is_recordings_dir_available(&self) -> Result<bool> {
804        #[cfg(not(target_os = "android"))] {
805            Err(Error::NOT_ANDROID)
806        }
807        #[cfg(target_os = "android")] {
808            Ok(self.impls().consts()?.env_dir_recordings.is_some())
809        }
810    }
811
812    /// For details, see [`PublicStorage::scan`].
813    /// 
814    /// The difference is that this method scans the file even on Android 10 or higher.
815    /// 
816    /// On Android 10 or higher, files are automatically registered in the appropriate MediaStore as needed. 
817    /// Scanning is triggered when the file descriptor is closed
818    /// or as part of the [`pending`](PublicStorage::set_pending) lifecycle.  
819    /// Therefore, please consider carefully whether this is truly necessary. 
820    #[maybe_async]
821    pub fn _scan(
822        &self, 
823        uri: &FileUri,
824    ) -> Result<()> {
825
826        #[cfg(not(target_os = "android"))] {
827            Err(Error::NOT_ANDROID)
828        }
829        #[cfg(target_os = "android")] {
830            self.impls().scan_file_in_public_storage(uri, true).await
831        }
832    }
833
834    /// For details, see [`PublicStorage::_scan`].
835    /// 
836    /// The difference is that this function waits until the scan is complete and then returns either success or an error.
837    #[maybe_async]
838    pub fn _scan_for_result(
839        &self, 
840        uri: &FileUri,
841    ) -> Result<()> {
842
843        #[cfg(not(target_os = "android"))] {
844            Err(Error::NOT_ANDROID)
845        }
846        #[cfg(target_os = "android")] {
847            self.impls().scan_file_in_public_storage_for_result(uri, true).await
848        }
849    }
850}