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