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_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_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_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.
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}