tauri-plugin-android-fs 28.2.1

Android file system API for Tauri.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
use sync_async::sync_async;
use crate::*;
use super::*;


/// API of file storage that is available to other applications and users.  
/// 
/// # Examples
/// ```no_run
/// fn example(app: &tauri::AppHandle) {
///     use tauri_plugin_android_fs::AndroidFsExt as _;
/// 
///     let api = app.android_fs();
///     let public_storage = api.public_storage();
/// }
/// ```
#[sync_async]
pub struct PublicStorage<'a, R: tauri::Runtime> {
    #[cfg(target_os = "android")]
    pub(crate) handle: &'a tauri::plugin::PluginHandle<R>,

    #[cfg(not(target_os = "android"))]
    #[allow(unused)]
    pub(crate) handle: &'a std::marker::PhantomData<fn() -> R>,
}

#[cfg(target_os = "android")]
#[sync_async(
    use(if_sync) impls::SyncImpls as Impls;
    use(if_async) impls::AsyncImpls as Impls;
)]
impl<'a, R: tauri::Runtime> PublicStorage<'a, R> {
    
    #[always_sync]
    fn impls(&self) -> Impls<'_, R> {
        Impls { handle: &self.handle }
    }
}

#[sync_async(
    use(if_async) api_async::{AndroidFs, FileOpener, FilePicker, AppStorage, PrivateStorage};
    use(if_sync) api_sync::{AndroidFs, FileOpener, FilePicker, AppStorage, PrivateStorage};
)]
impl<'a, R: tauri::Runtime> PublicStorage<'a, R> {

    /// Requests file access permission from the user if needed.
    ///
    /// When this function returns `true`,
    /// the app is allowed to create files in `PublicStorage` and read/write the files it creates. 
    /// Access to files created by other apps is not guaranteed.
    /// Additionally, after the app is uninstalled and reinstalled, 
    /// previously created files may become inaccessible.
    ///
    /// # Version behavior
    /// ### Android 11 or higher
    /// Requests no permission.   
    /// This function always returns `true`.
    /// 
    /// ### Android 10
    /// Selects either the behavior for Android 11 or higher or for Android 9 or lower, as needed.
    ///
    /// ### Android 9 or lower
    /// 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.   
    /// To request the permissions, you must declare it in `AndroidManifest.xml`.
    /// By enabling the `legacy_storage_permission` feature,
    /// the permissions will be declared automatically only for Android 9 or lower.
    ///
    /// # Support
    /// All Android versions
    #[maybe_async]
    pub fn request_permission(&self) -> Result<bool> {
        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().request_storage_permission_for_public_storage().await
        }
    }

    /// Indicates whether the app has file access permission.
    ///
    /// When this function returns `true`,
    /// the app is allowed to create files in `PublicStorage` and read/write the files it creates. 
    /// Access to files created by other apps is not guaranteed.
    /// Additionally, after the app is uninstalled and reinstalled, 
    /// previously created files may become inaccessible.
    ///
    /// # Version behavior
    /// ### Android 11 or higher
    /// Always returns `true`.
    ///
    /// ### Android 10
    /// Selects either the behavior for Android 11 or higher or for Android 9 or lower, as needed.
    ///
    /// ### Android 9 or lower
    /// 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.    
    /// See [`PublicStorage::request_permission`] for requesting the permissions.
    ///
    /// # Support
    /// All Android versions.
    #[maybe_async]
    pub fn check_permission(&self) -> Result<bool> {
        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().check_storage_permission_for_public_storage().await
        }
    }

    /// Gets a list of currently available storage volumes (internal storage, SD card, USB drive, etc.).
    /// Be aware of TOCTOU.
    /// 
    /// Since read-only SD cards and similar cases may be included, 
    /// please use [`StorageVolume { is_readonly, .. }`](StorageVolume) for filtering as needed.
    /// 
    /// This typically includes [`primary storage volume`](PublicStorage::get_primary_volume),
    /// but it may occasionally be absent if the primary volume is inaccessible 
    /// (e.g., mounted on a computer, removed, or another issue).
    ///
    /// Primary storage volume is always listed first, if included. 
    /// But the order of the others is not guaranteed.  
    /// 
    /// # Note
    /// For Android 9 (API level 28) or lower, 
    /// this does not include any storage volumes other than the primary one. 
    /// 
    /// The volume represents the logical view of a storage volume for an individual user:
    /// each user may have a different view for the same physical volume.
    /// In other words, it provides a separate area for each user in a multi-user environment.
    /// 
    /// # Support
    /// All Android versions supported by Tauri.  
    #[maybe_async]
    pub fn get_volumes(&self) -> Result<Vec<StorageVolume>> {
        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().get_available_storage_volumes_for_public_storage().await
        }
    }

    /// Gets a primary storage volume.  
    /// This is the most common and recommended storage volume for placing files that can be accessed by other apps or user.
    /// In many cases, it is device's built-in storage.  
    /// 
    /// A device always has one (and one only) primary storage volume.  
    /// 
    /// Primary volume may not currently be accessible 
    /// if it has been mounted by the user on their computer, 
    /// has been removed from the device, or some other problem has happened. 
    /// If so, this returns `None`.
    /// 
    /// # Note
    /// The volume represents the logical view of a storage volume for an individual user:
    /// each user may have a different view for the same physical volume.
    /// In other words, it provides a separate area for each user in a multi-user environment.
    /// 
    /// # Support
    /// All Android versions supported by Tauri.
    #[maybe_async]
    pub fn get_primary_volume(&self) -> Result<Option<StorageVolume>> {
        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().get_primary_storage_volume_if_available_for_public_storage().await
        }
    }

    /// Creates a new empty file in the specified public directory of the storage volume.  
    /// This returns a **persistent read-write** URI.
    ///
    /// The app can read/write it until the app is uninstalled. 
    /// And it is **not** removed when the app itself is uninstalled.  
    /// 
    /// # Note
    /// ### Android 10 or higher. 
    /// Files are automatically registered in the appropriate MediaStore as needed. 
    /// Scanning is triggered when the file descriptor is closed
    /// or as part of the [`pending`](PublicStorage::set_pending) lifecycle.
    /// 
    /// ### Android 9 or lower
    /// [`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.    
    /// This needs two steps: 
    /// 
    /// 1. Declare :  
    ///     By enabling the `legacy_storage_permission` feature,  
    ///     you can declare the permissions only for Android 9 or lower automatically at build time.  
    ///
    /// 2. Runtime request :  
    ///     By calling [`PublicStorage::request_permission`],
    ///     you can request the permissions from the user at runtime.  
    ///
    /// After writing content to the file, call [`PublicStorage::scan`].  
    /// Until then, the file may not appear in the gallery or other apps.
    /// 
    /// # Args
    /// - ***volume_id*** :  
    /// The ID of the storage volume, such as internal storage or an SD card.  
    /// Usually, you don't need to specify this unless there is a special reason.  
    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.
    ///
    /// - ***base_dir*** :  
    /// The base directory for the file.  
    /// When using [`PublicImageDir`], only image MIME types should be used for ***mime_type***; using other types may cause errors.  
    /// Similarly, [`PublicVideoDir`] and [`PublicAudioDir`] should only be used with their respective media types.  
    /// Only [`PublicGeneralPurposeDir`] supports all MIME types.
    ///
    /// - ***relative_path*** :  
    /// The file path relative to the base directory.  
    /// To keep files organized, it is recommended to place your app's name directory at the top level.  
    /// Any missing parent directories will be created automatically.  
    /// If a file with the same name already exists, a sequential number is appended to ensure uniqueness.  
    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
    /// Note that append-exntesion and sanitize-path operation may vary depending on the device model and Android version.  
    ///
    /// - ***mime_type*** :  
    /// The MIME type of the file to be created.  
    /// If `None`, the MIME type will be inferred from the extension of ***relative_path***.  
    /// If that also fails, `application/octet-stream` will be used.
    /// 
    /// # Support
    /// All Android versions supported by Tauri.
    ///
    /// Note :  
    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
    /// - Others dirs are available in all Android versions.
    #[maybe_async]
    pub fn create_new_file(
        &self,
        volume_id: Option<&StorageVolumeId>,
        base_dir: impl Into<PublicDir>,
        relative_path: impl AsRef<std::path::Path>, 
        mime_type: Option<&str>
    ) -> Result<FileUri> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().create_new_file_in_public_storage(
                volume_id, 
                base_dir, 
                relative_path, 
                mime_type, 
                false
            ).await
        }
    }

    /// Creates a new empty file in the specified public directory of the storage volume.  
    /// This returns a **persistent read-write** URI.
    ///
    /// The app can read/write it until the app is uninstalled. 
    /// And it is **not** removed when the app itself is uninstalled.  
    /// 
    /// # Note
    /// ### Android 10 or higher
    /// Files are automatically registered in the appropriate MediaStore as needed. 
    /// Scanning is triggered when the file descriptor is closed
    /// or as part of the [`pending`](PublicStorage::set_pending) lifecycle.
    /// 
    /// Diffrences from [`PublicStorage::create_new_file`] are that
    /// files are marked as pending and will not be visible to other apps until 
    /// [`PublicStorage::set_pending(..., false)`](PublicStorage::set_pending) is called. 
    ///
    /// ### Android 9 or lower
    /// This behavior is equal to [`PublicStorage::create_new_file`]. 
    /// So `pending` is ignored.  
    /// 
    /// [`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.    
    /// This needs two steps: 
    /// 
    /// 1. Declare :  
    ///     By enabling the `legacy_storage_permission` feature,  
    ///     you can declare the permissions only for Android 9 or lower automatically at build time.  
    ///
    /// 2. Runtime request :  
    ///     By calling [`PublicStorage::request_permission`],
    ///     you can request the permissions from the user at runtime.  
    ///
    /// After writing content to the file, call [`PublicStorage::scan`].  
    /// Until then, the file may not appear in the gallery or other apps.
    /// 
    /// # Args
    /// - ***volume_id*** :  
    /// The ID of the storage volume, such as internal storage or an SD card.  
    /// Usually, you don't need to specify this unless there is a special reason.  
    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.
    ///
    /// - ***base_dir*** :  
    /// The base directory for the file.  
    /// When using [`PublicImageDir`], only image MIME types should be used for ***mime_type***; using other types may cause errors.  
    /// Similarly, [`PublicVideoDir`] and [`PublicAudioDir`] should only be used with their respective media types.  
    /// Only [`PublicGeneralPurposeDir`] supports all MIME types.
    ///
    /// - ***relative_path*** :  
    /// The file path relative to the base directory.  
    /// To keep files organized, it is recommended to place your app's name directory at the top level.  
    /// Any missing parent directories will be created automatically.  
    /// If a file with the same name already exists, a sequential number is appended to ensure uniqueness.  
    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
    /// Note that append-exntesion and sanitize-path operation may vary depending on the device model and Android version.  
    ///
    /// - ***mime_type*** :  
    /// The MIME type of the file to be created.  
    /// If `None`, the MIME type will be inferred from the extension of ***relative_path***.  
    /// If that also fails, `application/octet-stream` will be used.
    /// 
    /// # Support
    /// All Android versions supported by Tauri.
    ///
    /// Note :  
    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
    /// - Others dirs are available in all Android versions.
    #[maybe_async]
    pub fn create_new_file_with_pending(
        &self,
        volume_id: Option<&StorageVolumeId>,
        base_dir: impl Into<PublicDir>,
        relative_path: impl AsRef<std::path::Path>, 
        mime_type: Option<&str>
    ) -> Result<FileUri> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().create_new_file_in_public_storage(
                volume_id, 
                base_dir, 
                relative_path, 
                mime_type, 
                true
            ).await
        }
    }

    /// Recursively create a directory and all of its parent components if they are missing.  
    /// If it already exists, do nothing.
    /// 
    /// [`PublicStorage::create_new_file`] and [`PublicStorage::create_new_file_with_pending`]
    /// do this automatically, so there is no need to use it together.
    /// 
    /// # Note
    /// On Android 9 or lower,
    /// [`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.    
    /// This needs two steps: 
    /// 
    /// 1. Declare :  
    ///     By enabling the `legacy_storage_permission` feature,  
    ///     you can declare the permissions only for Android 9 or lower automatically at build time.  
    ///
    /// 2. Runtime request :  
    ///     By calling [`PublicStorage::request_permission`],
    ///     you can request the permissions from the user at runtime.  
    ///
    /// # Args  
    /// - ***volume_id*** :  
    /// ID of the storage volume, such as internal storage, SD card, etc.  
    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
    /// 
    /// - ***base_dir*** :  
    /// The base directory.  
    ///  
    /// - ***relative_path*** :  
    /// The directory path relative to the base directory.    
    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
    /// Note that sanitize-path operation may vary depending on the device model and Android version.  
    ///
    /// # Support
    /// All Android versions supported by Tauri.
    ///
    /// Note :  
    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
    /// - Others dirs are available in all Android versions.
    #[maybe_async]
    pub fn create_dir_all(
        &self,
        volume_id: Option<&StorageVolumeId>,
        base_dir: impl Into<PublicDir>,
        relative_path: impl AsRef<std::path::Path>, 
    ) -> Result<()> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().create_dir_all_in_public_storage(volume_id, base_dir, relative_path).await
        }
    }

    /// Writes contents to the new file in the specified public directory of the storage volume.  
    /// This returns a **persistent read-write** URI.
    ///
    /// The app can read/write it until the app is uninstalled. 
    /// And it is **not** removed when the app itself is uninstalled.  
    /// 
    /// # Note
    /// On Android 9 or lower,
    /// [`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.    
    /// This needs two steps: 
    /// 
    /// 1. Declare :  
    ///     By enabling the `legacy_storage_permission` feature,  
    ///     you can declare the permissions only for Android 9 or lower automatically at build time.  
    ///
    /// 2. Runtime request :  
    ///     By calling [`PublicStorage::request_permission`],
    ///     you can request the permissions from the user at runtime.  
    ///
    /// # Args
    /// - ***volume_id*** :  
    /// The ID of the storage volume, such as internal storage or an SD card.  
    /// Usually, you don't need to specify this unless there is a special reason.  
    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.
    ///
    /// - ***base_dir*** :  
    /// The base directory for the file.  
    /// When using [`PublicImageDir`], only image MIME types should be used for ***mime_type***; using other types may cause errors.  
    /// Similarly, [`PublicVideoDir`] and [`PublicAudioDir`] should only be used with their respective media types.  
    /// Only [`PublicGeneralPurposeDir`] supports all MIME types.
    ///
    /// - ***relative_path*** :  
    /// The file path relative to the base directory.  
    /// To keep files organized, it is recommended to place your app's name directory at the top level.  
    /// Any missing parent directories will be created automatically.  
    /// If a file with the same name already exists, a sequential number is appended to ensure uniqueness.  
    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
    /// Note that append-exntesion and sanitize-path operation may vary depending on the device model and Android version.  
    ///
    /// - ***mime_type*** :  
    /// The MIME type of the file to be created.  
    /// If `None`, the MIME type will be inferred from the extension of ***relative_path***.  
    /// If that also fails, `application/octet-stream` will be used.
    /// 
    /// - ***contents*** :  
    /// Contents.
    /// 
    /// # Support
    /// All Android versions supported by Tauri.
    ///
    /// Note :  
    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
    /// - Others dirs are available in all Android versions.
    #[maybe_async]
    pub fn write_new(
        &self,
        volume_id: Option<&StorageVolumeId>,
        base_dir: impl Into<PublicDir>,
        relative_path: impl AsRef<std::path::Path>,
        mime_type: Option<&str>,
        contents: impl AsRef<[u8]>
    ) -> Result<FileUri> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().write_new_file_in_public_storage(volume_id, base_dir, relative_path, mime_type, contents).await
        }
    }

    /// Scans the specified file in MediaStore.   
    /// By doing this, the file will be visible with corrent metadata in the Gallery and etc.
    ///
    /// You don’t need to call this after [`PublicStorage::write_new`].   
    /// 
    /// # Version behavior
    /// ### Android 10 or higher
    /// This function does nothing, 
    /// because files are automatically registered in the appropriate MediaStore as needed. 
    /// Scanning is triggered when the file descriptor is closed
    /// or as part of the [`pending`](PublicStorage::set_pending) lifecycle.  
    /// 
    /// If you really need to perform this operation in this version, 
    /// please use [`PublicStorage::_scan`].
    ///
    /// ### Android 9 or lower
    /// Requests the specified file to be scanned by MediaStore.  
    /// This function returns when the scan request has been initiated.   
    /// 
    /// # Args
    /// - ***uri*** :  
    /// The target file URI.
    /// This must be a URI obtained from one of the following:  
    ///     - [`PublicStorage::write_new`]
    ///     - [`PublicStorage::create_new_file`]
    ///     - [`PublicStorage::create_new_file_with_pending`]
    ///     - [`PublicStorage::scan_by_path`]
    ///
    /// # Support
    /// All Android versions.
    #[maybe_async]
    pub fn scan(
        &self, 
        uri: &FileUri,
    ) -> Result<()> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().scan_file_in_public_storage(uri, false).await
        }
    }

    /// Scans the specified file in MediaStore and returns it's URI if success.   
    /// By doing this, the file will be visible in the Gallery and etc.
    ///
    /// # Note
    /// Unlike [`PublicStorage::scan`], 
    /// this function waits until the scan is complete and then returns either success or an error.
    /// 
    /// # Args
    /// - ***uri*** :  
    /// Absolute path of the target file.
    /// This must be a path obtained from one of the following:  
    ///     - [`PublicStorage::resolve_path`] and it's descendants path.
    ///     - [`PublicStorage::get_path`]
    /// 
    /// - ***mime_type*** :  
    /// The MIME type of the file.  
    /// If `None`, the MIME type will be inferred from the extension of the path.  
    /// If that also fails, `application/octet-stream` will be used.
    /// 
    /// # Support
    /// All Android versions supported by Tauri.
    #[maybe_async]
    pub fn scan_by_path(
        &self, 
        path: impl AsRef<std::path::Path>,
        mime_type: Option<&str>
    ) -> Result<FileUri> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().scan_file_by_path_in_public_storage(path, mime_type).await
        }
    }

    /// Specifies whether the specified file on PublicStorage is marked as pending.   
    /// When set to `true`, the app has exclusive access to the file, and it becomes invisible to other apps.
    /// 
    /// If it remains `true` for more than seven days, 
    /// the system will automatically delete the file.
    /// 
    /// # Note
    /// This is available for Android 10 or higher.  
    /// On Android 9 or lower, this does nothing. 
    /// 
    /// # Args
    /// - ***uri*** :  
    /// Target file URI.
    /// This must be a URI obtained from one of the following:  
    ///     - [`PublicStorage::write_new`]
    ///     - [`PublicStorage::create_new_file`]
    ///     - [`PublicStorage::create_new_file_with_pending`]
    ///     - [`PublicStorage::scan_by_path`]
    /// 
    /// # Support
    /// All Android versions supported by Tauri.
    /// 
    /// # References
    /// - <https://developer.android.com/reference/android/provider/MediaStore.MediaColumns#IS_PENDING>
    /// - <https://developer.android.com/training/data-storage/shared/media?hl=en#toggle-pending-status>
    #[maybe_async]
    pub fn set_pending(&self, uri: &FileUri, is_pending: bool) -> Result<()> {
        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().set_file_pending_in_public_storage(uri, is_pending).await
        }
    }

    /// Gets the absolute path of the specified file.
    /// 
    /// # Note
    /// For description and notes on path permissions and handling, 
    /// see [`PublicStorage::resolve_path`].
    /// It involves important constraints and required settings. 
    /// Therefore, **operate files via paths only when it is truly necessary**.
    /// 
    /// # Args
    /// - ***uri*** :   
    /// Target file URI.
    /// This must be a URI obtained from one of the following:  
    ///     - [`PublicStorage::write_new`]
    ///     - [`PublicStorage::create_new_file`]
    ///     - [`PublicStorage::create_new_file_with_pending`]
    ///     - [`PublicStorage::scan_by_path`]
    /// 
    /// # Support
    /// All Android versions supported by Tauri.
    #[deprecated = "File operations via paths may result in unstable behaviour and inconsistent outcomes."]
    #[maybe_async]
    pub fn get_path(
        &self,
        uri: &FileUri,
    ) -> Result<std::path::PathBuf> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().get_file_path_in_public_storage(uri).await
        }
    }

    /// Retrieves the absolute path for a specified public directory within the given storage volume.   
    /// This function does **not** create any directories; it only constructs the path.
    /// 
    /// The app is allowed to create files in the directory and read/write the files it creates. 
    /// Access to files created by other apps is not guaranteed.
    /// Additionally, after the app is uninstalled and reinstalled, 
    /// previously created files may become inaccessible.
    /// 
    /// The directory is **not** removed when the app itself is uninstalled.  
    /// 
    /// It is strongly recommended to call [`PublicStorage::scan_by_path`] 
    /// after writing to the file to request registration in MediaStore.  
    /// 
    /// # Note
    /// As shown below, this involves important constraints and required settings.
    /// Therefore, **operate files via paths only when it is truly necessary**.
    /// 
    /// Do not use operations such as rename or remove that rely on paths 
    /// (including URIs obtained via [`FileUri::from_path`] with this paths), 
    /// as they may break consistency with the MediaStore on old version.
    /// Instead, use the URI obtained through [`PublicStorage::scan_by_path`] together with methods 
    /// such as [`AndroidFs::rename`] or [`AndroidFs::remove_file`].
    /// 
    /// ### Android 11 or higher
    /// When using [`PublicImageDir`], use only image type for file name extension, 
    /// using other type extension or none may cause errors.
    /// Similarly, use only the corresponding extesions for [`PublicVideoDir`] and [`PublicAudioDir`].
    /// Only [`PublicGeneralPurposeDir`] supports all extensions and no extension. 
    /// 
    /// ### Android 10 or lower
    /// [`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.    
    /// This needs two steps: 
    /// 
    /// 1. Declare :  
    ///     By enabling the `legacy_storage_permission_include_android_10` feature,  
    ///     you can declare the permissions only for Android 10 or lower automatically at build time.  
    /// 
    /// 2. Runtime request :  
    ///     By calling [`PublicStorage::request_permission`],
    ///     you can request the permissions from the user at runtime.  
    ///
    /// ### Android 10
    /// Files within PublicStorage cannot be accessed via file paths, 
    /// so it is necessary to declare that the app need access `PublicStorage` using the method of Android 9 or lower.   
    /// 
    /// For it, please [set `android:requestLegacyExternalStorage="true"`](https://developer.android.com/training/data-storage/use-cases#opt-out-in-production-app).
    /// 
    /// `src-tauri/gen/android/app/src/main/AndroidManifest.xml`
    /// ```xml
    /// <manifest ... >
    ///     <application 
  	///         android:requestLegacyExternalStorage="true" 
  	///         ...
    ///     >
    ///         ...
    ///     </application>
    /// </manifest>
    /// ```
    /// And it is not possible to access `PublicStorage`
	/// on volumes other than the primary storage via paths, just like on Android 9 or lower.   
	/// But filtering using [`PublicStorage::get_volumes`]
	/// or [`StorageVolume::is_available_for_public_storage`] may not work correctly, 
	/// as these are intended for access via URIs.
    /// 
    /// # Args
    /// - ***volume_id*** :  
    /// ID of the storage volume, such as internal storage, SD card, etc.  
    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
    /// 
    /// - ***base_dir*** :  
    /// The base directory.  
    /// One of [`PublicImageDir`], [`PublicVideoDir`], [`PublicAudioDir`], [`PublicGeneralPurposeDir`].  
    ///  
    /// # Support
    /// All Android versions supported by Tauri.
    /// 
    /// Note :  
    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
    /// - Others dirs are available in all Android versions.
    #[deprecated = "File operations via paths may result in unstable behaviour and inconsistent outcomes."]
    #[maybe_async]
    pub fn resolve_path(
        &self,
        volume_id: Option<&StorageVolumeId>,
        base_dir: impl Into<PublicDir>,
    ) -> Result<std::path::PathBuf> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().resolve_dir_path_in_public_storage(volume_id, base_dir).await
        }
    }

    /// Builds the specified directory URI.  
    /// 
    /// This should only be used as `initial_location` in the file picker, such as [`FilePicker::pick_files`]. 
    /// It must not be used for any other purpose.  
    /// 
    /// This is useful when selecting save location, 
    /// but when selecting existing entries, `initial_location` is often better with None.
    /// 
    /// # Args  
    /// - ***volume_id*** :  
    /// ID of the storage volume, such as internal storage, SD card, etc.  
    /// If `None` is provided, [`the primary storage volume`](PublicStorage::get_primary_volume) will be used.  
    /// 
    /// - ***base_dir*** :  
    /// The base directory.  
    ///  
    /// - ***relative_path*** :  
    /// The directory path relative to the base directory.  
    /// 
    /// - ***create_dir_all*** :  
    /// Creates directories if missing.  
    /// See [`PublicStorage::create_dir_all`].
    /// If error occurs, it will be ignored.
    ///  
    /// # Support
    /// All Android versions supported by Tauri.
    ///
    /// Note :  
    /// - [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
    /// - [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
    /// - Others dirs are available in all Android versions.
    #[maybe_async]
    pub fn resolve_initial_location(
        &self,
        volume_id: Option<&StorageVolumeId>,
        base_dir: impl Into<PublicDir>,
        relative_path: impl AsRef<std::path::Path>,
        create_dir_all: bool
    ) -> Result<FileUri> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().resolve_initial_location_in_public_storage(volume_id, base_dir, relative_path, create_dir_all).await
        }
    }

    /// Verify whether [`PublicAudioDir::Audiobooks`] is available on a given device.   
    /// 
    /// If on Android 10 (API level 29) or higher, this returns true.  
    /// If on Android 9 (API level 28) and lower, this returns false.  
    /// 
    /// # Support
    /// All Android versions supported by Tauri.
    #[always_sync]
    pub fn is_audiobooks_dir_available(&self) -> Result<bool> {
        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            Ok(self.impls().consts()?.env_dir_audiobooks.is_some())
        }
    }

    /// Verify whether [`PublicAudioDir::Recordings`] is available on a given device.   
    /// 
    /// If on Android 12 (API level 31) or higher, this returns true.  
    /// If on Android 11 (API level 30) and lower, this returns false.  
    /// 
    /// # Support
    /// All Android versions supported by Tauri.
    #[always_sync]
    pub fn is_recordings_dir_available(&self) -> Result<bool> {
        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            Ok(self.impls().consts()?.env_dir_recordings.is_some())
        }
    }

    /// For details, see [`PublicStorage::scan`].
    /// 
    /// The difference is that this method scans the file even on Android 10 or higher.
    /// 
    /// On Android 10 or higher, files are automatically registered in the appropriate MediaStore as needed. 
    /// Scanning is triggered when the file descriptor is closed
    /// or as part of the [`pending`](PublicStorage::set_pending) lifecycle.  
    /// Therefore, please consider carefully whether this is truly necessary. 
    #[maybe_async]
    pub fn _scan(
        &self, 
        uri: &FileUri,
    ) -> Result<()> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().scan_file_in_public_storage(uri, true).await
        }
    }

    /// For details, see [`PublicStorage::_scan`].
    /// 
    /// The difference is that this function waits until the scan is complete and then returns either success or an error.
    #[maybe_async]
    pub fn _scan_for_result(
        &self, 
        uri: &FileUri,
    ) -> Result<()> {

        #[cfg(not(target_os = "android"))] {
            Err(Error::NOT_ANDROID)
        }
        #[cfg(target_os = "android")] {
            self.impls().scan_file_in_public_storage_for_result(uri, true).await
        }
    }
}