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, PrivateStorage, WritableStream};
42    use(if_sync) api_sync::{AndroidFs, FileOpener, FilePicker, 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_file`].  
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_store(
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_file`].  
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_store(
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_store(volume_id, base_dir, relative_path, mime_type, contents).await
481        }
482    }
483
484    /// Scans the specified file.   
485    /// This ensures that the file will be visible 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    /// ### 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    ///
508    /// # Support
509    /// All Android versions.
510    #[maybe_async]
511    pub fn scan_file(
512        &self, 
513        uri: &FileUri,
514    ) -> Result<()> {
515
516        #[cfg(not(target_os = "android"))] {
517            Err(Error::NOT_ANDROID)
518        }
519        #[cfg(target_os = "android")] {
520            self.impls().scan_file_in_public_storage(uri).await
521        }
522    }
523
524    /// Specifies whether the specified file on PublicStorage is marked as pending.   
525    /// When set to `true`, the app has exclusive access to the file, and it becomes invisible to other apps.
526    /// 
527    /// If it remains `true` for more than seven days, 
528    /// the system will automatically delete the file.
529    /// 
530    /// # Version behavior
531    /// This is available for Android 10 or higher.  
532    /// On Android 9 or lower, this does nothing. 
533    /// 
534    /// # Args
535    /// - ***uri*** :  
536    /// Target file URI on PublicStorage.
537    /// This must be **read-writable**.
538    /// 
539    /// # Support
540    /// All Android version.
541    /// 
542    /// # References
543    /// - <https://developer.android.com/reference/android/provider/MediaStore.MediaColumns#IS_PENDING>
544    /// - <https://developer.android.com/training/data-storage/shared/media?hl=en#toggle-pending-status>
545    #[maybe_async]
546    pub fn set_pending(&self, uri: &FileUri, is_pending: bool) -> Result<()> {
547        #[cfg(not(target_os = "android"))] {
548            Err(Error::NOT_ANDROID)
549        }
550        #[cfg(target_os = "android")] {
551            self.impls().set_file_pending_in_public_storage(uri, is_pending).await
552        }
553    }
554
555    /// Retrieves the absolute path for a specified public directory within the given storage volume.   
556    /// This function does **not** create any directories; it only constructs the path.
557    /// 
558    /// Please **avoid using this whenever possible.**  
559    /// Use it only in cases that cannot be handled by [`PublicStorage::create_new_file`] or [`PrivateStorage::resolve_path`],  
560    /// such as when you need to pass the absolute path of a user-accessible file as an argument to debug logger, and etc.
561    /// This should not be used in production.
562    /// 
563    /// # Version behavior
564    /// ### Android 11 or higher
565    /// You can create files and folders under this directory and read/write the files it creates.  
566    /// You cannot access files created by other apps. 
567    /// Additionally, if the app is uninstalled, 
568    /// you will no longer be able to access the files you created, 
569    /// even if the app is reinstalled.  
570    /// 
571    /// When using [`PublicImageDir`], use only image type for file name extension, 
572    /// using other type extension or none may cause errors.
573    /// Similarly, use only the corresponding extesions for [`PublicVideoDir`] and [`PublicAudioDir`].
574    /// Only [`PublicGeneralPurposeDir`] supports all extensions and no extension. 
575    /// 
576    /// ### Android 10
577    /// You can do nothing with this path.
578    /// 
579    /// ### Android 9 or lower
580    /// You can create/read/write files and folders under this directory.  
581    /// 
582    /// [`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.    
583    /// This needs two steps: 
584    /// 
585    /// 1. Declare :  
586    ///     By enabling the `legacy_storage_permission` feature,  
587    ///     you can declare the permissions only for Android 9 or lower automatically at build time.  
588    ///
589    /// 2. Runtime request :  
590    ///     By calling [`PublicStorage::request_permission`],
591    ///     you can request the permissions from the user at runtime.  
592    ///
593    /// # Note
594    /// Filesystem access via this path may be heavily impacted by emulation overhead.
595    /// And those files will not be registered in MediaStore. 
596    /// It might eventually be registered over time, but this should not be expected.
597    /// As a result, it may not appear in gallery apps or photo picker tools.
598    /// 
599    /// # Args
600    /// - ***volume_id*** :  
601    /// ID of the storage volume, such as internal storage, SD card, etc.  
602    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
603    /// 
604    /// - ***base_dir*** :  
605    /// The base directory.  
606    ///  
607    /// # Support
608    /// All Android version.
609    /// 
610    /// Note :  
611    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
612    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
613    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
614    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
615    /// - Others dirs are available in all Android versions.
616    #[maybe_async]
617    #[deprecated]
618    pub fn resolve_path(
619        &self,
620        volume_id: Option<&StorageVolumeId>,
621        base_dir: impl Into<PublicDir>,
622    ) -> Result<std::path::PathBuf> {
623
624        #[cfg(not(target_os = "android"))] {
625            Err(Error::NOT_ANDROID)
626        }
627        #[cfg(target_os = "android")] {
628            self.impls().resolve_path_in_public_storage(volume_id, base_dir).await
629        }
630    }
631
632    /// Create the specified directory URI that has **no permissions**.  
633    /// 
634    /// This should only be used as `initial_location` in the file picker. 
635    /// It must not be used for any other purpose.  
636    /// 
637    /// This is useful when selecting save location, 
638    /// but when selecting existing entries, `initial_location` is often better with None.
639    /// 
640    /// # Args  
641    /// - ***volume_id*** :  
642    /// ID of the storage volume, such as internal storage, SD card, etc.  
643    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
644    /// 
645    /// - ***base_dir*** :  
646    /// The base directory.  
647    ///  
648    /// - ***relative_path*** :  
649    /// The directory path relative to the base directory.    
650    ///  
651    /// # Support
652    /// All Android version.
653    ///
654    /// Note :  
655    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
656    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
657    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
658    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
659    /// - Others dirs are available in all Android versions.
660    #[maybe_async]
661    pub fn resolve_initial_location(
662        &self,
663        volume_id: Option<&StorageVolumeId>,
664        base_dir: impl Into<PublicDir>,
665        relative_path: impl AsRef<std::path::Path>,
666        create_dir_all: bool
667    ) -> Result<FileUri> {
668
669        #[cfg(not(target_os = "android"))] {
670            Err(Error::NOT_ANDROID)
671        }
672        #[cfg(target_os = "android")] {
673            self.impls().resolve_initial_location_in_public_storage(volume_id, base_dir, relative_path, create_dir_all).await
674        }
675    }
676
677    /// Create the specified directory URI that has **no permissions**.  
678    /// 
679    /// This should only be used as `initial_location` in the file picker. 
680    /// It must not be used for any other purpose.  
681    /// 
682    /// This is useful when selecting save location, 
683    /// but when selecting existing entries, `initial_location` is often better with None.
684    /// 
685    /// # Args  
686    /// - ***volume_id*** :  
687    /// ID of the storage volume, such as internal storage, SD card, etc.  
688    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
689    /// 
690    /// # Support
691    /// All Android version.
692    ///
693    /// Note :  
694    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
695    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
696    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
697    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
698    /// - Others dirs are available in all Android versions.
699    #[maybe_async]
700    pub fn resolve_initial_location_top(
701        &self,
702        volume_id: Option<&StorageVolumeId>
703    ) -> Result<FileUri> {
704
705        #[cfg(not(target_os = "android"))] {
706            Err(Error::NOT_ANDROID)
707        }
708        #[cfg(target_os = "android")] {
709            self.impls().resolve_initial_location_top_in_public_storage(volume_id).await
710        }
711    }
712
713    /// Verify whether [`PublicAudioDir::Audiobooks`] is available on a given device.   
714    /// 
715    /// If on Android 10 (API level 29) or higher, this returns true.  
716    /// If on Android 9 (API level 28) and lower, this returns false.  
717    /// 
718    /// # Support
719    /// All Android version.
720    #[always_sync]
721    pub fn is_audiobooks_dir_available(&self) -> Result<bool> {
722        #[cfg(not(target_os = "android"))] {
723            Err(Error::NOT_ANDROID)
724        }
725        #[cfg(target_os = "android")] {
726            Ok(self.impls().consts()?.env_dir_audiobooks.is_some())
727        }
728    }
729
730    /// Verify whether [`PublicAudioDir::Recordings`] is available on a given device.   
731    /// 
732    /// If on Android 12 (API level 31) or higher, this returns true.  
733    /// If on Android 11 (API level 30) and lower, this returns false.  
734    /// 
735    /// # Support
736    /// All Android version.
737    #[always_sync]
738    pub fn is_recordings_dir_available(&self) -> Result<bool> {
739        #[cfg(not(target_os = "android"))] {
740            Err(Error::NOT_ANDROID)
741        }
742        #[cfg(target_os = "android")] {
743            Ok(self.impls().consts()?.env_dir_recordings.is_some())
744        }
745    }
746
747
748
749    /// ~~Verify whether the basic functions of PublicStorage (such as [`PublicStorage::create_new_file`]) can be performed.~~
750    /// 
751    /// If on Android 9 (API level 28) and lower, this returns false.  
752    /// If on Android 10 (API level 29) or higher, this returns true.  
753    /// 
754    /// # Support
755    /// All Android version.
756    #[deprecated]
757    #[always_sync]
758    pub fn is_available(&self) -> Result<bool> {
759        #[cfg(not(target_os = "android"))] {
760            Err(Error::NOT_ANDROID)
761        }
762        #[cfg(target_os = "android")] {
763            Ok(api_level::ANDROID_10 <= self.impls().api_level()?)
764        }
765    }
766}