tauri_plugin_android_fs/api/
android_fs.rs

1use sync_async::sync_async;
2use crate::*;
3use super::*;
4
5
6/// ***Root API***  
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/// }
15/// ```
16
17#[sync_async]
18pub struct AndroidFs<R: tauri::Runtime> {
19    #[cfg(target_os = "android")]
20    pub(crate) handle: tauri::plugin::PluginHandle<R>,
21
22    #[cfg(not(target_os = "android"))]
23    #[allow(unused)]
24    pub(crate) handle: 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<R: tauri::Runtime> AndroidFs<R> {
33    
34    #[always_sync]
35    pub(crate) fn impls(&self) -> Impls<'_, R> {
36        Impls { handle: &self.handle }
37    }
38}
39
40#[sync_async(
41    use(if_async) api_async::{FileOpener, FilePicker, PrivateStorage, PublicStorage, WritableStream};
42    use(if_sync) api_sync::{FileOpener, FilePicker, PrivateStorage, PublicStorage, WritableStream};
43)]
44impl<R: tauri::Runtime> AndroidFs<R> {
45
46    /// API of file storage intended for the app's use only.
47    #[always_sync]
48    pub fn private_storage(&self) -> PrivateStorage<'_, R> {
49        PrivateStorage { handle: &self.handle }
50    }
51
52    /// API of file storage that is available to other applications and users.
53    #[always_sync]
54    pub fn public_storage(&self) -> PublicStorage<'_, R> {
55        PublicStorage { handle: &self.handle }
56    }
57
58    /// API of file/dir picker.
59    #[always_sync]
60    pub fn file_picker(&self) -> FilePicker<'_, R> {
61        FilePicker { handle: &self.handle }
62    }
63
64    /// API of opening file/dir with other apps.
65    #[always_sync]
66    pub fn file_opener(&self) -> FileOpener<'_, R> {
67        FileOpener { handle: &self.handle }
68    }
69
70    /// Get the file or directory name.  
71    /// 
72    /// # Args
73    /// - ***uri*** :  
74    /// Target URI.  
75    /// Must be **readable**.
76    /// 
77    /// # Support
78    /// All Android version.
79    #[maybe_async]
80    pub fn get_name(&self, uri: &FileUri) -> Result<String> {
81        #[cfg(not(target_os = "android"))] {
82            Err(Error::NOT_ANDROID)
83        }
84        #[cfg(target_os = "android")] {
85            self.impls().get_entry_name(uri).await
86        }
87    }
88
89    /// Queries the provider to get the MIME type.
90    ///
91    /// For file URIs via [`FileUri::from_path`], the MIME type is determined from the file extension.  
92    /// In most other cases, it uses the MIME type that was associated with the file when it was created.  
93    /// If the MIME type is unknown or unset, it falls back to `"application/octet-stream"`.  
94    /// 
95    /// If the target is a directory, an error will occur.  
96    /// To check whether the target is a file or a directory, use [`AndroidFs::get_type`].  
97    /// 
98    /// # Args
99    /// - ***uri*** :  
100    /// Target file URI.  
101    /// Must be **readable**.
102    /// 
103    /// # Support
104    /// All Android version.
105    #[maybe_async]
106    pub fn get_mime_type(&self, uri: &FileUri) -> Result<String> {
107        #[cfg(not(target_os = "android"))] {
108            Err(Error::NOT_ANDROID)
109        }
110        #[cfg(target_os = "android")] {
111            self.impls().get_file_mime_type(uri).await
112        }
113    }
114
115    /// Gets the entry type.
116    ///
117    /// If the target is a directory, returns [`EntryType::Dir`].
118    ///
119    /// If the target is a file, returns [`EntryType::File { mime_type }`](EntryType::File).  
120    /// For file URIs via [`FileUri::from_path`], the MIME type is determined from the file extension.  
121    /// In most other cases, it uses the MIME type that was associated with the file when it was created.  
122    /// If the MIME type is unknown or unset, it falls back to `"application/octet-stream"`.  
123    /// 
124    /// # Args
125    /// - ***uri*** :  
126    /// Target URI.  
127    /// Must be **readable**.
128    /// 
129    /// # Support
130    /// All Android version.
131    #[maybe_async]
132    pub fn get_type(&self, uri: &FileUri) -> Result<EntryType> {
133        #[cfg(not(target_os = "android"))] {
134            Err(Error::NOT_ANDROID)
135        }
136        #[cfg(target_os = "android")] {
137            self.impls().get_entry_type(uri).await
138        }
139    }
140
141    /// Queries the file system to get information about a file, directory.
142    /// 
143    /// # Args
144    /// - ***uri*** :  
145    /// Target URI.  
146    /// Must be **readable**.
147    /// 
148    /// # Note
149    /// This uses [`AndroidFs::open_file`] internally.
150    /// 
151    /// # Support
152    /// All Android version.
153    #[maybe_async]
154    pub fn get_metadata(&self, uri: &FileUri) -> Result<std::fs::Metadata> {
155        #[cfg(not(target_os = "android"))] {
156            Err(Error::NOT_ANDROID)
157        }
158        #[cfg(target_os = "android")] {
159            self.impls().get_entry_metadata(uri).await
160        }
161    }
162
163    /// Open the file in **readable** mode. 
164    /// 
165    /// # Note
166    /// If the target is a file on cloud storage or otherwise not physically present on the device,
167    /// the file provider may downloads the entire contents, and then opens it. 
168    /// As a result, this processing may take longer than with regular local files.
169    /// And files might be a pair of pipe or socket for streaming data.
170    /// 
171    /// # Args
172    /// - ***uri*** :  
173    /// Target file URI.  
174    /// This need to be **readable**.
175    /// 
176    /// # Support
177    /// All Android version.
178    #[maybe_async]
179    pub fn open_file_readable(&self, uri: &FileUri) -> Result<std::fs::File> {
180        #[cfg(not(target_os = "android"))] {
181            Err(Error::NOT_ANDROID)
182        }
183        #[cfg(target_os = "android")] {
184            self.impls().open_file_readable(uri).await
185        }
186    }
187
188    /// Open the file in **writable** mode.  
189    /// This truncates the existing contents.  
190    /// 
191    /// # Note
192    /// For file provider of some cloud storage, 
193    /// writing by file descriptor like std::fs may not correctoly notify and reflect changes. 
194    /// If you need to write to such files, use [`AndroidFs::open_writable_stream`].
195    /// It will fall back to Kotlin API as needed.
196    /// And you can check by [`AndroidFs::need_write_via_kotlin`].
197    /// 
198    /// # Args
199    /// - ***uri*** :  
200    /// Target file URI.  
201    /// This need to be **writable**.
202    /// 
203    /// # Support
204    /// All Android version.
205    #[maybe_async]
206    pub fn open_file_writable(
207        &self, 
208        uri: &FileUri, 
209    ) -> Result<std::fs::File> {
210
211        #[cfg(not(target_os = "android"))] {
212            Err(Error::NOT_ANDROID)
213        }
214        #[cfg(target_os = "android")] {
215            self.impls().open_file_writable(uri).await
216        }
217    }
218
219    /// Open the file in the specified mode.  
220    /// 
221    /// # Note
222    /// If the target is a file on cloud storage or otherwise not physically present on the device,
223    /// the file provider may downloads the entire contents, and then opens it. 
224    /// As a result, this processing may take longer than with regular local files.
225    /// And files might be a pair of pipe or socket for streaming data.
226    /// 
227    /// When writing to a file with this function,
228    /// pay attention to the following points:
229    /// 
230    /// 1. **File reflection**:  
231    /// For file provider of some cloud storage, 
232    /// writing by file descriptor like std::fs may not correctoly notify and reflect changes. 
233    /// If you need to write to such files, use [`AndroidFs::open_writable_stream`].
234    /// It will fall back to Kotlin API as needed.
235    /// And you can check by [`AndroidFs::need_write_via_kotlin`].
236    /// 
237    /// 2. **File mode restrictions**:  
238    /// Files provided by third-party apps may not support writable modes other than
239    /// [`FileAccessMode::Write`]. However, [`FileAccessMode::Write`] does not guarantee
240    /// that existing contents will always be truncated.  
241    /// As a result, if the new contents are shorter than the original, the file may
242    /// become corrupted. To avoid this, consider using
243    /// [`AndroidFs::open_file_writable`] or [`AndroidFs::open_writable_stream`], which
244    /// ensure that existing contents are truncated and also automatically apply the
245    /// maximum possible fallbacks.  
246    /// <https://issuetracker.google.com/issues/180526528>
247    /// 
248    /// # Args
249    /// - ***uri*** :  
250    /// Target file URI.  
251    /// This must have corresponding permissions (read, write, or both) for the specified ***mode***.
252    /// 
253    /// - ***mode*** :  
254    /// Indicates how the file is opened and the permissions granted. 
255    /// The only ones that can be expected to work in all cases are [`FileAccessMode::Write`] and [`FileAccessMode::Read`].
256    /// Because files hosted by third-party apps may not support others.
257    /// 
258    /// # Support
259    /// All Android version.
260    #[maybe_async]
261    pub fn open_file(&self, uri: &FileUri, mode: FileAccessMode) -> Result<std::fs::File> {
262        #[cfg(not(target_os = "android"))] {
263            Err(Error::NOT_ANDROID)
264        }
265        #[cfg(target_os = "android")] {
266            self.impls().open_file(uri, mode).await
267        }
268    }
269 
270    /// For detailed documentation and notes, see [`AndroidFs::open_file`].  
271    ///
272    /// The modes specified in ***candidate_modes*** are tried in order.  
273    /// If the file can be opened, this returns the file along with the mode used.  
274    /// If all attempts fail, an error is returned.  
275    #[maybe_async]
276    pub fn open_file_with_fallback(
277        &self, 
278        uri: &FileUri, 
279        candidate_modes: impl IntoIterator<Item = FileAccessMode>
280    ) -> Result<(std::fs::File, FileAccessMode)> {
281
282        #[cfg(not(target_os = "android"))] {
283            Err(Error::NOT_ANDROID)
284        }
285        #[cfg(target_os = "android")] {
286            self.impls().open_file_with_fallback(uri, candidate_modes).await
287        }
288    }
289
290    /// Opens a stream for writing to the specified file.  
291    /// This truncates the existing contents.  
292    /// 
293    /// # Usage
294    /// [`WritableStream`] implements [`std::io::Write`], so it can be used for writing.  
295    /// As with [`std::fs::File`], wrap it with [`std::io::BufWriter`] if buffering is needed.  
296    ///
297    /// After writing, call [`WritableStream::reflect`].  
298    /// 
299    /// # Note
300    /// The behavior depends on [`AndroidFs::need_write_via_kotlin`].  
301    /// If it is `false`, this behaves like [`AndroidFs::open_file_writable`].  
302    /// If it is `true`, this behaves like [`AndroidFs::open_writable_stream_via_kotlin`].  
303    /// 
304    /// # Args
305    /// - ***uri*** :  
306    /// Target file URI.  
307    /// This need to be **writable**.
308    /// 
309    /// # Support
310    /// All Android version.
311    #[maybe_async]
312    pub fn open_writable_stream(
313        &self,
314        uri: &FileUri
315    ) -> Result<WritableStream<R>> {
316
317        #[cfg(not(target_os = "android"))] {
318            Err(Error::NOT_ANDROID)
319        }
320        #[cfg(target_os = "android")] {
321            let impls = self.impls().create_writable_stream_auto(uri).await?;
322            Ok(WritableStream { impls })
323        }
324    }
325
326    /// Opens a writable stream to the specified file.  
327    /// This truncates the existing contents.  
328    /// 
329    /// This function always writes content via the Kotlin API.
330    /// But this takes several times longer compared.  
331    /// [`AndroidFs::open_writable_stream`] automatically falls back to this function depending on [`AndroidFs::need_write_via_kotlin`].  
332    /// 
333    /// # Usage
334    /// [`WritableStream`] implements [`std::io::Write`], so it can be used for writing.  
335    /// As with [`std::fs::File`], wrap it with [`std::io::BufWriter`] if buffering is needed.  
336    ///
337    /// After writing, call [`WritableStream::reflect`].
338    /// 
339    /// # Args
340    /// - ***uri*** :  
341    /// Target file URI.  
342    /// This need to be **writable**.
343    /// 
344    /// # Support
345    /// All Android version.
346    #[maybe_async]
347    pub fn open_writable_stream_via_kotlin(
348        &self,
349        uri: &FileUri
350    ) -> Result<WritableStream<R>> {
351
352        #[cfg(not(target_os = "android"))] {
353            Err(Error::NOT_ANDROID)
354        }
355        #[cfg(target_os = "android")] {
356            let impls = self.impls().create_writable_stream_via_kotlin(uri).await?;
357            Ok(WritableStream { impls })
358        }
359    }
360
361    /// Reads the entire contents of a file into a bytes vector.  
362    /// 
363    /// # Args
364    /// - ***uri*** :  
365    /// Target file URI.    
366    /// Must be **readable**.
367    /// 
368    /// # Support
369    /// All Android version.
370    #[maybe_async]
371    pub fn read(&self, uri: &FileUri) -> Result<Vec<u8>> {
372        #[cfg(not(target_os = "android"))] {
373            Err(Error::NOT_ANDROID)
374        }
375        #[cfg(target_os = "android")] {
376            self.impls().read_file(uri).await
377        }
378    }
379
380    /// Reads the entire contents of a file into a string.  
381    /// 
382    /// # Args
383    /// - ***uri*** :  
384    /// Target file URI.  
385    /// Must be **readable**.
386    /// 
387    /// # Support
388    /// All Android version.
389    #[maybe_async]
390    pub fn read_to_string(&self, uri: &FileUri) -> Result<String> {
391        #[cfg(not(target_os = "android"))] {
392            Err(Error::NOT_ANDROID)
393        }
394        #[cfg(target_os = "android")] {
395            self.impls().read_file_to_string(uri).await
396        }
397    }
398
399    /// Writes a slice as the entire contents of a file.  
400    /// This function will entirely replace its contents if it does exist.    
401    /// 
402    /// # Note
403    /// The behavior depends on [`AndroidFs::need_write_via_kotlin`].  
404    /// If it is `false`, this uses [`std::fs::File`].  
405    /// If it is `true`, this uses [`AndroidFs::write_via_kotlin`].  
406    /// 
407    /// # Args
408    /// - ***uri*** :  
409    /// Target file URI.  
410    /// Must be **writable**.
411    /// 
412    /// # Support
413    /// All Android version.
414    #[maybe_async]
415    pub fn write(&self, uri: &FileUri, contents: impl AsRef<[u8]>) -> Result<()> {
416        #[cfg(not(target_os = "android"))] {
417            Err(Error::NOT_ANDROID)
418        }
419        #[cfg(target_os = "android")] {
420            self.impls().write_file_auto(uri, contents).await
421        }
422    }
423
424    /// Writes a slice as the entire contents of a file.  
425    /// This function will entirely replace its contents if it does exist.    
426    /// 
427    /// This function always writes content via the Kotlin API.
428    /// But this takes several times longer compared.   
429    /// [`AndroidFs::write`] automatically falls back to this function depending on [`AndroidFs::need_write_via_kotlin`].  
430    /// 
431    /// # Support
432    /// All Android version.
433    #[maybe_async]
434    pub fn write_via_kotlin(
435        &self, 
436        uri: &FileUri,
437        contents: impl AsRef<[u8]>
438    ) -> Result<()> {
439
440        #[cfg(not(target_os = "android"))] {
441            Err(Error::NOT_ANDROID)
442        }
443        #[cfg(target_os = "android")] {
444            self.impls().write_file_via_kotlin(uri, contents).await
445        }
446    }
447
448    /// Copies the contents of the source file to the destination.  
449    /// If the destination already has contents, they are truncated before writing the source contents.  
450    /// 
451    /// # Note
452    /// The behavior depends on [`AndroidFs::need_write_via_kotlin`].  
453    /// If it is `false`, this uses [`std::io::copy`] with [`std::fs::File`].  
454    /// If it is `true`, this uses [`AndroidFs::copy_via_kotlin`].  
455    /// 
456    /// # Args
457    /// - ***src*** :  
458    /// The URI of source file.   
459    /// Must be **readable**.
460    /// 
461    /// - ***dest*** :  
462    /// The URI of destination file.  
463    /// Must be **writable**.
464    /// 
465    /// # Support
466    /// All Android version.
467    #[maybe_async]
468    pub fn copy(&self, src: &FileUri, dest: &FileUri) -> Result<()> {
469        #[cfg(not(target_os = "android"))] {
470            Err(Error::NOT_ANDROID)
471        }
472        #[cfg(target_os = "android")] {
473            self.impls().copy_file(src, dest).await
474        }
475    }
476
477    /// Copies the contents of src file to dest.  
478    /// If dest already has contents, it is truncated before write src contents.  
479    /// 
480    /// This function always writes content via the Kotlin API.  
481    /// [`AndroidFs::copy`] automatically falls back to this function depending on [`AndroidFs::need_write_via_kotlin`].   
482    /// 
483    /// # Args
484    /// - ***src*** :  
485    /// The URI of source file.   
486    /// Must be **readable**.
487    /// 
488    /// - ***dest*** :  
489    /// The URI of destination file.  
490    /// Must be **writable**.
491    /// 
492    /// - ***buffer_size***:  
493    /// The size of the buffer, in bytes, to use during the copy process on Kotlin.  
494    /// If `None`, [`DEFAULT_BUFFER_SIZE`](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/-d-e-f-a-u-l-t_-b-u-f-f-e-r_-s-i-z-e.html) is used. 
495    /// At least, when I checked, it was 8 KB.  
496    /// If zero, this causes error.
497    /// 
498    /// # Support
499    /// All Android version.
500    #[maybe_async]
501    pub fn copy_via_kotlin(
502        &self, 
503        src: &FileUri, 
504        dest: &FileUri,
505        buffer_size: Option<u32>,
506    ) -> Result<()> {
507
508        #[cfg(not(target_os = "android"))] {
509            Err(Error::NOT_ANDROID)
510        }
511        #[cfg(target_os = "android")] {
512            self.impls().copy_file_via_kotlin(src, dest, buffer_size).await
513        }
514    }
515
516    /// Determines whether the file must be written via the Kotlin API rather than through a file descriptor.
517    /// 
518    /// In the case of a file that physically exists on the device, this will always return false.
519    /// This is intended for special cases, such as some cloud storage.
520    /// 
521    /// # Support
522    /// All Android version.
523    #[maybe_async]
524    pub fn need_write_via_kotlin(&self, uri: &FileUri) -> Result<bool> {
525        #[cfg(not(target_os = "android"))] {
526            Err(Error::NOT_ANDROID)
527        }
528        #[cfg(target_os = "android")] {
529            self.impls().need_write_file_via_kotlin(uri).await
530        }
531    }
532
533    /// Renames a file or directory to a new name, and return new URI.  
534    /// Even if the names conflict, the existing file will not be overwritten.  
535    /// 
536    /// Note that when files or folders (and their descendants) are renamed, their URIs will change, and any previously granted permissions will be lost.
537    /// In other words, this function returns a new URI without any permissions.
538    /// However, for files created in PublicStorage, the URI remains unchanged even after such operations, and all permissions are retained.
539    /// In this, this function returns the same URI as original URI.
540    ///
541    /// # Args
542    /// - ***uri*** :  
543    /// URI of target entry.  
544    /// 
545    /// - ***new_name*** :  
546    /// New name of target entry. 
547    /// This include extension if use.  
548    /// The behaviour in the same name already exists depends on the file provider.  
549    /// In the case of e.g. [`PublicStorage`], the suffix (e.g. `(1)`) is added to this name.  
550    /// In the case of files hosted by other applications, errors may occur.  
551    /// But at least, the existing file will not be overwritten.  
552    /// The system may sanitize these strings as needed, so those strings may not be used as it is.
553    /// 
554    /// # Support
555    /// All Android version.
556    #[maybe_async]
557    pub fn rename(&self, uri: &FileUri, new_name: impl AsRef<str>) -> Result<FileUri> {
558        #[cfg(not(target_os = "android"))] {
559            Err(Error::NOT_ANDROID)
560        }
561        #[cfg(target_os = "android")] {
562            self.impls().rename_entry(uri, new_name).await
563        }
564    }
565
566    /// Remove the file.
567    /// 
568    /// # Args
569    /// - ***uri*** :  
570    /// Target file URI.  
571    /// Must be **read-writable**.   
572    /// If not file, an error will occur.
573    /// 
574    /// # Support
575    /// All Android version.
576    #[maybe_async]
577    pub fn remove_file(&self, uri: &FileUri) -> Result<()> {
578        #[cfg(not(target_os = "android"))] {
579            Err(Error::NOT_ANDROID)
580        }
581        #[cfg(target_os = "android")] {
582            self.impls().remove_file(uri).await
583        }
584    }
585
586    /// Remove the **empty** directory.
587    /// 
588    /// # Args
589    /// - ***uri*** :  
590    /// Target directory URI.  
591    /// Must be **read-writable**.  
592    /// If not empty directory, an error will occur.
593    /// 
594    /// # Support
595    /// All Android version.
596    #[maybe_async]
597    pub fn remove_dir(&self, uri: &FileUri) -> Result<()> {
598        #[cfg(not(target_os = "android"))] {
599            Err(Error::NOT_ANDROID)
600        }
601        #[cfg(target_os = "android")] {
602            self.impls().remove_dir_if_empty(uri).await
603        }
604    }
605
606    /// Removes a directory and all its contents. Use carefully!
607    /// 
608    /// # Args
609    /// - ***uri*** :  
610    /// Target directory URI.  
611    /// Must be **read-writable**.  
612    /// If not directory, an error will occur.
613    /// 
614    /// # Support
615    /// All Android version.
616    #[maybe_async]
617    pub fn remove_dir_all(&self, uri: &FileUri) -> Result<()> {
618        #[cfg(not(target_os = "android"))] {
619            Err(Error::NOT_ANDROID)
620        }
621        #[cfg(target_os = "android")] {
622            self.impls().remove_dir_all(uri).await
623        }
624    }
625
626    /// Build a URI of an **existing** file located at the relative path from the specified directory.   
627    /// Error occurs, if the file does not exist.  
628    /// 
629    /// The permissions and validity period of the returned URI depend on the origin directory 
630    /// (e.g., the top directory selected by [`FilePicker::pick_dir`]) 
631    /// 
632    /// # Note
633    /// For [`AndroidFs::create_new_file`] and etc, the system may sanitize path strings as needed, so those strings may not be used as it is.
634    /// However, this function does not perform any sanitization, so the same ***relative_path*** may still fail.  
635    /// So consider using [`AndroidFs::create_new_file_and_return_relative_path`].
636    /// 
637    /// # Args
638    /// - ***uri*** :  
639    /// Base directory URI.  
640    /// Must be **readable**.  
641    /// 
642    /// - ***relative_path*** :
643    /// Relative path from base directory.
644    /// 
645    /// # Support
646    /// All Android version.
647    #[maybe_async]
648    pub fn resolve_file_uri(
649        &self, 
650        dir: &FileUri, 
651        relative_path: impl AsRef<std::path::Path>
652    ) -> Result<FileUri> {
653
654        #[cfg(not(target_os = "android"))] {
655            Err(Error::NOT_ANDROID)
656        }
657        #[cfg(target_os = "android")] {
658            self.impls().resolve_file_uri(dir, relative_path).await
659        }
660    }
661
662    /// Build a URI of an **existing** directory located at the relative path from the specified directory.   
663    /// Error occurs, if the directory does not exist.  
664    /// 
665    /// The permissions and validity period of the returned URI depend on the origin directory 
666    /// (e.g., the top directory selected by [`FilePicker::pick_dir`]) 
667    /// 
668    /// # Note
669    /// For [`AndroidFs::create_dir_all`] and etc, the system may sanitize path strings as needed, so those strings may not be used as it is.
670    /// However, this function does not perform any sanitization, so the same ***relative_path*** may still fail.  
671    /// So consider using [`AndroidFs::create_dir_all_and_return_relative_path`].
672    /// 
673    /// # Args
674    /// - ***uri*** :  
675    /// Base directory URI.  
676    /// Must be **readable**.  
677    /// 
678    /// - ***relative_path*** :
679    /// Relative path from base directory.
680    /// 
681    /// # Support
682    /// All Android version.
683    #[maybe_async]
684    pub fn resolve_dir_uri(
685        &self,
686        dir: &FileUri, 
687        relative_path: impl AsRef<std::path::Path>
688    ) -> Result<FileUri> {
689
690        #[cfg(not(target_os = "android"))] {
691            Err(Error::NOT_ANDROID)
692        }
693        #[cfg(target_os = "android")] {
694            self.impls().resolve_dir_uri(dir, relative_path).await
695        }
696    }
697
698    /// See [`AndroidFs::get_thumbnail_to`] for descriptions.  
699    /// 
700    /// If thumbnail does not wrote to dest, return false.
701    #[maybe_async]
702    pub fn get_thumbnail_to(
703        &self, 
704        src: &FileUri,
705        dest: &FileUri,
706        preferred_size: Size,
707        format: ImageFormat,
708    ) -> Result<bool> {
709
710        #[cfg(not(target_os = "android"))] {
711            Err(Error::NOT_ANDROID)
712        }
713        #[cfg(target_os = "android")] {
714            self.impls().get_file_thumbnail_to_file(src, dest, preferred_size, format).await
715        }
716    }
717
718    /// Get a file thumbnail.  
719    /// If thumbnail does not exist it, return None.
720    /// 
721    /// Note this does not cache. Please do it in your part if need.  
722    /// 
723    /// # Args
724    /// - ***uri*** :  
725    /// Targe file uri.  
726    /// Thumbnail availablty depends on the file provider.  
727    /// In general, images and videos are available.  
728    /// For file URIs via [`FileUri::from_path`], 
729    /// the file type must match the filename extension. 
730    /// In this case, the type is determined by the extension and generate thumbnails.  
731    /// Otherwise, thumbnails are provided through MediaStore, file provider, and etc.
732    /// 
733    /// - ***preferred_size*** :  
734    /// Optimal thumbnail size desired.  
735    /// This may return a thumbnail of a different size, 
736    /// but never more than double the requested size. 
737    /// In any case, the aspect ratio is maintained.
738    /// 
739    /// - ***format*** :  
740    /// Thumbnail image format.  
741    /// [`ImageFormat::Jpeg`] is recommended. 
742    /// If you need transparency, use others.
743    /// 
744    /// # Support
745    /// All Android version.
746    #[maybe_async]
747    pub fn get_thumbnail(
748        &self,
749        uri: &FileUri,
750        preferred_size: Size,
751        format: ImageFormat,
752    ) -> Result<Option<Vec<u8>>> {
753
754        #[cfg(not(target_os = "android"))] {
755            Err(Error::NOT_ANDROID)
756        }
757        #[cfg(target_os = "android")] {
758            self.impls().get_file_thumbnail_in_memory(uri, preferred_size, format).await
759        }
760    }
761
762    /// Creates a new empty file in the specified location and returns a URI.   
763    /// 
764    /// The permissions and validity period of the returned URIs depend on the origin directory 
765    /// (e.g., the top directory selected by [`FilePicker::pick_dir`]) 
766    /// 
767    /// # Args  
768    /// - ***dir*** :  
769    /// The URI of the base directory.  
770    /// Must be **read-write**.
771    ///  
772    /// - ***relative_path*** :  
773    /// The file path relative to the base directory.  
774    /// Any missing parent directories will be created automatically.  
775    /// If a file with the same name already exists, a sequential number may be appended to ensure uniqueness.  
776    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
777    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
778    /// Note those operation may vary depending on the file provider.  
779    /// 
780    /// - ***mime_type*** :  
781    /// The MIME type of the file to be created.  
782    /// If this is None, MIME type is inferred from the extension of ***relative_path***
783    /// and if that fails, `application/octet-stream` is used.  
784    ///  
785    /// # Support
786    /// All Android version.
787    #[maybe_async]
788    pub fn create_new_file(
789        &self,
790        dir: &FileUri, 
791        relative_path: impl AsRef<std::path::Path>, 
792        mime_type: Option<&str>
793    ) -> Result<FileUri> {
794
795        #[cfg(not(target_os = "android"))] {
796            Err(Error::NOT_ANDROID)
797        }
798        #[cfg(target_os = "android")] {
799            self.impls().create_new_file(dir, relative_path, mime_type).await
800        }
801    }
802
803    /// Creates a new empty file in the specified location and returns a URI and relative path.   
804    /// 
805    /// The returned relative path may be sanitized and have a suffix appended to the file name, 
806    /// so it may differ from the input relative path.
807    /// And it is a logical path within the file provider and 
808    /// available for [`AndroidFs::resolve_file_uri`].
809    /// 
810    /// The permissions and validity period of the returned URIs depend on the origin directory 
811    /// (e.g., the top directory selected by [`FilePicker::pick_dir`]) 
812    /// 
813    /// # Args  
814    /// - ***dir*** :  
815    /// The URI of the base directory.  
816    /// Must be **read-write**.
817    ///  
818    /// - ***relative_path*** :  
819    /// The file path relative to the base directory.  
820    /// Any missing parent directories will be created automatically.  
821    /// If a file with the same name already exists, a sequential number may be appended to ensure uniqueness.  
822    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
823    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
824    /// Note those operation may vary depending on the file provider.  
825    ///  
826    /// - ***mime_type*** :  
827    /// The MIME type of the file to be created.  
828    /// If this is None, MIME type is inferred from the extension of ***relative_path***
829    /// and if that fails, `application/octet-stream` is used.  
830    ///  
831    /// # Support
832    /// All Android version.
833    #[maybe_async]
834    pub fn create_new_file_and_return_relative_path(
835        &self,
836        dir: &FileUri, 
837        relative_path: impl AsRef<std::path::Path>, 
838        mime_type: Option<&str>
839    ) -> Result<(FileUri, std::path::PathBuf)> {
840
841        #[cfg(not(target_os = "android"))] {
842            Err(Error::NOT_ANDROID)
843        }
844        #[cfg(target_os = "android")] {
845            self.impls().create_new_file_and_retrun_relative_path(dir, relative_path, mime_type).await
846        }
847    }
848
849    /// Recursively create a directory and all of its parent components if they are missing,
850    /// then return the URI.  
851    /// If it already exists, do nothing and just return the direcotry uri.
852    /// 
853    /// [`AndroidFs::create_new_file`] does this automatically, so there is no need to use it together.
854    /// 
855    /// # Args  
856    /// - ***dir*** :  
857    /// The URI of the base directory.  
858    /// Must be **read-write**.
859    ///  
860    /// - ***relative_path*** :  
861    /// The directory path relative to the base directory.    
862    /// Any missing parent directories will be created automatically.  
863    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
864    /// Note this sanitization may vary depending on the file provider.  
865    ///  
866    /// # Support
867    /// All Android version.
868    #[maybe_async]
869    pub fn create_dir_all(
870        &self,
871        dir: &FileUri, 
872        relative_path: impl AsRef<std::path::Path>, 
873    ) -> Result<FileUri> {
874
875        #[cfg(not(target_os = "android"))] {
876            Err(Error::NOT_ANDROID)
877        }
878        #[cfg(target_os = "android")] {
879            self.impls().create_dir_all(dir, relative_path).await
880        }
881    }
882
883    /// Recursively create a directory and all of its parent components if they are missing,
884    /// then return the URI and relative path.  
885    /// 
886    /// The returned relative path may be sanitized, 
887    /// so it may differ from the input relative path.
888    /// And it is a logical path within the file provider and 
889    /// available for [`AndroidFs::resolve_dir_uri`].
890    /// 
891    /// [`AndroidFs::create_new_file`] does this automatically, so there is no need to use it together.
892    /// 
893    /// # Args  
894    /// - ***dir*** :  
895    /// The URI of the base directory.  
896    /// Must be **read-write**.
897    ///  
898    /// - ***relative_path*** :  
899    /// The directory path relative to the base directory.    
900    /// Any missing parent directories will be created automatically.  
901    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
902    /// Note this sanitization may vary depending on the file provider.  
903    ///  
904    /// # Support
905    /// All Android version.
906    #[maybe_async]
907    pub fn create_dir_all_and_return_relative_path(
908        &self,
909        dir: &FileUri, 
910        relative_path: impl AsRef<std::path::Path>, 
911    ) -> Result<(FileUri, std::path::PathBuf)> {
912
913        #[cfg(not(target_os = "android"))] {
914            Err(Error::NOT_ANDROID)
915        }
916        #[cfg(target_os = "android")] {
917            self.impls().create_dir_all_and_return_relative_path(dir, relative_path).await
918        }
919    }
920
921    /// Returns the child files and directories of the specified directory.  
922    /// The order of the entries is not guaranteed.  
923    /// 
924    /// The permissions and validity period of the returned URIs depend on the origin directory 
925    /// (e.g., the top directory selected by [`FilePicker::pick_dir`])  
926    /// 
927    /// This retrieves all metadata including `uri`, `name`, `last_modified`, `len`, and `mime_type`. 
928    /// If only specific information is needed, 
929    /// using [`AndroidFs::read_dir_with_options`] will improve performance.
930    /// 
931    /// # Note
932    /// The returned type is an iterator, but the file system call is not executed lazily.  
933    /// Instead, all data is retrieved at once.  
934    /// For directories containing thousands or even tens of thousands of entries,  
935    /// this function may take several seconds to complete.  
936    /// The returned iterator itself is low-cost, as it only performs lightweight data formatting.
937    /// 
938    /// # Args
939    /// - ***uri*** :  
940    /// Target directory URI.  
941    /// Must be **readable**.
942    /// 
943    /// # Support
944    /// All Android version.
945    #[maybe_async]
946    pub fn read_dir(&self, uri: &FileUri) -> Result<impl Iterator<Item = Entry>> {
947        let entries = self.read_dir_with_options(uri, EntryOptions::ALL).await?
948            .map(Entry::try_from)
949            .filter_map(Result::ok);
950        
951        Ok(entries)
952    }
953
954    /// Returns the child files and directories of the specified directory.  
955    /// The order of the entries is not guaranteed.  
956    /// 
957    /// The permissions and validity period of the returned URIs depend on the origin directory 
958    /// (e.g., the top directory selected by [`FilePicker::pick_dir`])  
959    /// 
960    /// # Note
961    /// The returned type is an iterator, but the file system call is not executed lazily.  
962    /// Instead, all data is retrieved at once.  
963    /// For directories containing thousands or even tens of thousands of entries,  
964    /// this function may take several seconds to complete.  
965    /// The returned iterator itself is low-cost, as it only performs lightweight data formatting.
966    /// 
967    /// # Args
968    /// - ***uri*** :  
969    /// Target directory URI.  
970    /// Must be **readable**.
971    /// 
972    /// # Support
973    /// All Android version.
974    #[maybe_async]
975    pub fn read_dir_with_options(
976        &self, 
977        uri: &FileUri, 
978        options: EntryOptions
979    ) -> Result<impl Iterator<Item = OptionalEntry>> {
980        
981        #[cfg(not(target_os = "android"))] {
982            Err::<std::iter::Empty<_>, _>(Error::NOT_ANDROID)
983        }
984        #[cfg(target_os = "android")] {
985            self.impls().read_dir_with_options(uri, options).await
986        }
987    }
988
989    /// Take persistent permission to access the file, directory and its descendants.  
990    /// This is a prolongation of an already acquired permission, not the acquisition of a new one.  
991    /// 
992    /// This works by just calling, without displaying any confirmation to the user.
993    /// 
994    /// Note that [there is a limit to the total number of URI that can be made persistent by this function.](https://stackoverflow.com/questions/71099575/should-i-release-persistableuripermission-when-a-new-storage-location-is-chosen/71100621#71100621)  
995    /// Therefore, it is recommended to relinquish the unnecessary persisted URI by [`AndroidFs::release_persisted_uri_permission`] or [`AndroidFs::release_all_persisted_uri_permissions`].  
996    /// Persisted permissions may be relinquished by other apps, user, or by moving/removing entries.
997    /// So check by [`AndroidFs::check_persisted_uri_permission`].  
998    /// And you can retrieve the list of persisted uris using [`AndroidFs::get_all_persisted_uri_permissions`].
999    /// 
1000    /// # Args
1001    /// - **uri** :  
1002    /// URI of the target file or directory.   
1003    /// This must be a URI taken from following :  
1004    ///     - [`FilePicker::pick_files`]  
1005    ///     - [`FilePicker::pick_file`]  
1006    ///     - [`FilePicker::pick_visual_medias`]  
1007    ///     - [`FilePicker::pick_visual_media`]  
1008    ///     - [`FilePicker::pick_dir`]  
1009    ///     - [`FilePicker::save_file`]  
1010    ///     - [`AndroidFs::resolve_file_uri`], [`AndroidFs::resolve_dir_uri`], [`AndroidFs::read_dir`], [`AndroidFs::create_new_file`], [`AndroidFs::create_dir_all`] :  
1011    ///     If use URI from thoese fucntions, the permissions of the origin directory URI is persisted, not a entry iteself by this function. 
1012    ///     Because the permissions and validity period of the descendant entry URIs depend on the origin directory.   
1013    /// 
1014    /// # Support
1015    /// All Android version. 
1016    #[maybe_async]
1017    pub fn take_persistable_uri_permission(&self, uri: &FileUri) -> Result<()> {
1018        #[cfg(not(target_os = "android"))] {
1019            Err(Error::NOT_ANDROID)
1020        }
1021        #[cfg(target_os = "android")] {
1022            self.impls().take_persistable_uri_permission(uri).await
1023        }
1024    }
1025
1026    /// Check a persisted URI permission grant by [`AndroidFs::take_persistable_uri_permission`].  
1027    /// Returns false if there are only non-persistent permissions or no permissions.
1028    /// 
1029    /// # Args
1030    /// - **uri** :  
1031    /// URI of the target file or directory.  
1032    /// This must be a URI taken from following :  
1033    ///     - [`FilePicker::pick_files`]  
1034    ///     - [`FilePicker::pick_file`]  
1035    ///     - [`FilePicker::pick_visual_medias`]  
1036    ///     - [`FilePicker::pick_visual_media`]  
1037    ///     - [`FilePicker::pick_dir`]  
1038    ///     - [`FilePicker::save_file`]  
1039    ///     - [`AndroidFs::resolve_file_uri`], [`AndroidFs::resolve_dir_uri`], [`AndroidFs::read_dir`], [`AndroidFs::create_new_file`], [`AndroidFs::create_dir_all`] :  
1040    ///     If use URI from thoese fucntions, the permissions of the origin directory URI is checked, not a entry iteself by this function. 
1041    ///     Because the permissions and validity period of the descendant entry URIs depend on the origin directory.   
1042    /// 
1043    /// - **mode** :  
1044    /// The mode of permission you want to check.  
1045    /// 
1046    /// # Support
1047    /// All Android version.
1048    #[maybe_async]
1049    pub fn check_persisted_uri_permission(
1050        &self, 
1051        uri: &FileUri, 
1052        mode: PersistableAccessMode
1053    ) -> Result<bool> {
1054
1055        #[cfg(not(target_os = "android"))] {
1056            Err(Error::NOT_ANDROID)
1057        }
1058        #[cfg(target_os = "android")] {
1059            self.impls().check_persisted_uri_permission(uri, mode).await
1060        }
1061    }
1062
1063    /// Return list of all persisted URIs that have been persisted by [`AndroidFs::take_persistable_uri_permission`] and currently valid.   
1064    /// 
1065    /// # Support
1066    /// All Android version.
1067    #[maybe_async]
1068    pub fn get_all_persisted_uri_permissions(&self) -> Result<impl Iterator<Item = PersistedUriPermission>> {
1069        #[cfg(not(target_os = "android"))] {
1070            Err::<std::iter::Empty<_>, _>(Error::NOT_ANDROID)
1071        }
1072        #[cfg(target_os = "android")] {
1073            self.impls().get_all_persisted_uri_permissions().await
1074        }
1075    }
1076
1077    /// Relinquish a persisted URI permission grant by [`AndroidFs::take_persistable_uri_permission`].   
1078    /// 
1079    /// # Args
1080    /// - ***uri*** :  
1081    /// URI of the target file or directory.  
1082    ///
1083    /// # Support
1084    /// All Android version.
1085    #[maybe_async]
1086    pub fn release_persisted_uri_permission(&self, uri: &FileUri) -> Result<()> {
1087        #[cfg(not(target_os = "android"))] {
1088            Err(Error::NOT_ANDROID)
1089        }
1090        #[cfg(target_os = "android")] {
1091            self.impls().release_persisted_uri_permission(uri).await
1092        }
1093    }
1094
1095    /// Relinquish a all persisted uri permission grants by [`AndroidFs::take_persistable_uri_permission`].  
1096    /// 
1097    /// # Support
1098    /// All Android version.
1099    #[maybe_async]
1100    pub fn release_all_persisted_uri_permissions(&self) -> Result<()> {
1101        #[cfg(not(target_os = "android"))] {
1102            Err(Error::NOT_ANDROID)
1103        }
1104        #[cfg(target_os = "android")] {
1105            self.impls().release_all_persisted_uri_permissions().await
1106        }
1107    }
1108
1109    /// See [`PublicStorage::get_volumes`] or [`PrivateStorage::get_volumes`] for details.
1110    /// 
1111    /// The difference is that this does not perform any filtering.
1112    /// You can it by [`StorageVolume { is_available_for_public_storage, is_available_for_private_storage, .. } `](StorageVolume).
1113    #[maybe_async]
1114    pub fn get_volumes(&self) -> Result<Vec<StorageVolume>> {
1115        #[cfg(not(target_os = "android"))] {
1116            Err(Error::NOT_ANDROID)
1117        }
1118        #[cfg(target_os = "android")] {
1119            self.impls().get_available_storage_volumes().await
1120        }
1121    }
1122
1123    /// See [`PublicStorage::get_primary_volume`] or [`PrivateStorage::get_primary_volume`] for details.
1124    /// 
1125    /// The difference is that this does not perform any filtering.
1126    /// You can it by [`StorageVolume { is_available_for_public_storage, is_available_for_private_storage, .. } `](StorageVolume).
1127    #[maybe_async]
1128    pub fn get_primary_volume(&self) -> Result<Option<StorageVolume>> {
1129        #[cfg(not(target_os = "android"))] {
1130            Err(Error::NOT_ANDROID)
1131        }
1132        #[cfg(target_os = "android")] {
1133            self.impls().get_primary_storage_volume_if_available().await
1134        }
1135    }
1136
1137    /// Verify whether this plugin is available.  
1138    /// 
1139    /// On Android, this returns true.  
1140    /// On other platforms, this returns false.  
1141    #[always_sync]
1142    pub fn is_available(&self) -> bool {
1143        cfg!(target_os = "android")
1144    }
1145
1146    /// Get the api level of this Android device.
1147    /// 
1148    /// The correspondence table between API levels and Android versions can be found following.  
1149    /// <https://developer.android.com/guide/topics/manifest/uses-sdk-element#api-level-table>
1150    /// 
1151    /// If you want the constant value of the API level from an Android version, there is the [`api_level`] module.
1152    /// 
1153    /// # Table
1154    /// | Android version  | API Level |
1155    /// |------------------|-----------|
1156    /// | 16.0             | 36        |
1157    /// | 15.0             | 35        |
1158    /// | 14.0             | 34        |
1159    /// | 13.0             | 33        |
1160    /// | 12L              | 32        |
1161    /// | 12.0             | 31        |
1162    /// | 11.0             | 30        |
1163    /// | 10.0             | 29        |
1164    /// | 9.0              | 28        |
1165    /// | 8.1              | 27        |
1166    /// | 8.0              | 26        |
1167    /// | 7.1 - 7.1.2      | 25        |
1168    /// | 7.0              | 24        |
1169    /// 
1170    /// Tauri does not support Android versions below 7.
1171    #[always_sync]
1172    pub fn api_level(&self) -> Result<i32> {
1173        #[cfg(not(target_os = "android"))] {
1174            Err(Error::NOT_ANDROID)
1175        }
1176        #[cfg(target_os = "android")] {
1177            self.impls().api_level()
1178        }
1179    }
1180
1181
1182    #[deprecated = "Use resolve_file_uri instead"]
1183    #[maybe_async]
1184    pub fn try_resolve_file_uri(
1185        &self,
1186        dir: &FileUri, 
1187        relative_path: impl AsRef<std::path::Path>
1188    ) -> Result<FileUri> {
1189
1190        #[cfg(not(target_os = "android"))] {
1191            Err(Error::NOT_ANDROID)
1192        }
1193        #[cfg(target_os = "android")] {
1194            self.impls().resolve_file_uri(dir, relative_path).await
1195        }
1196    }
1197
1198    #[deprecated = "Use resolve_dir_uri instead"]
1199    #[maybe_async]
1200    pub fn try_resolve_dir_uri(
1201        &self,
1202        dir: &FileUri, 
1203        relative_path: impl AsRef<std::path::Path>
1204    ) -> Result<FileUri> {
1205
1206        #[cfg(not(target_os = "android"))] {
1207            Err(Error::NOT_ANDROID)
1208        }
1209        #[cfg(target_os = "android")] {
1210            self.impls().resolve_dir_uri(dir, relative_path).await
1211        }
1212    }
1213
1214    #[deprecated = "This may not return the correct uri. Use resolve_file_uri or resolve_dir_uri instead"]
1215    #[maybe_async]
1216    pub fn resolve_uri_unvalidated(
1217        &self, 
1218        dir: &FileUri, 
1219        relative_path: impl AsRef<std::path::Path>
1220    ) -> Result<FileUri> {
1221
1222        #[cfg(not(target_os = "android"))] {
1223            Err(Error::NOT_ANDROID)
1224        }
1225        #[cfg(target_os = "android")] {
1226            #[allow(deprecated)]
1227            self.impls()._resolve_uri_legacy(dir, relative_path).await
1228        }
1229    }
1230
1231    #[deprecated = "This may not return the correct uri. Use resolve_file_uri or resolve_dir_uri instead"]
1232    #[maybe_async]
1233    pub fn resolve_uri(
1234        &self, 
1235        dir: &FileUri, 
1236        relative_path: impl AsRef<std::path::Path>
1237    ) -> Result<FileUri> {
1238
1239        #[cfg(not(target_os = "android"))] {
1240            Err(Error::NOT_ANDROID)
1241        }
1242        #[cfg(target_os = "android")] {
1243            #[allow(deprecated)]
1244            self.impls()._resolve_uri_legacy(dir, relative_path).await
1245        }
1246    }
1247}