diff options
| author | Po Lu | 2023-07-28 12:21:47 +0800 |
|---|---|---|
| committer | Po Lu | 2023-07-28 12:21:47 +0800 |
| commit | 03cf3bbb5c38aa55abd6f7d4860025f7482fcfc3 (patch) | |
| tree | a8d55088a6efed2cbe4b0bfad1c1bde61579b54e /java | |
| parent | 7c0899586471d3649dfb468d2b8f7d6d9685fea1 (diff) | |
| download | emacs-03cf3bbb5c38aa55abd6f7d4860025f7482fcfc3.tar.gz emacs-03cf3bbb5c38aa55abd6f7d4860025f7482fcfc3.zip | |
Update Android port
* java/org/gnu/emacs/EmacsDirectoryEntry.java
(EmacsDirectoryEntry): Make class final.
* java/org/gnu/emacs/EmacsService.java (accessDocument)
(openDocumentDirectory, openDocument, createDocument): Throw
access and IO error exceptions instead of catching them.
(createDirectory, deleteDocument): New functions.
* src/android.c (android_init_emacs_service): Add new functions.
* src/android.h (struct android_emacs_service): Likewise.
* src/androidvfs.c (android_saf_exception_check): New function.
Translate between Java exceptions and errno values.
(android_saf_stat, android_saf_access, android_saf_delete_document)
(struct android_saf_tree_vnode, android_document_id_from_name)
(android_saf_tree_name, android_saf_tree_rmdir)
(android_saf_tree_opendir_1, android_saf_tree_opendir)
(android_saf_file_open, android_saf_file_unlink)
(android_saf_new_open, android_saf_new_mkdir): Implement missing
VFS operations and derive errno values from the type of any
exceptions thrown.
(android_vfs_init): Initialize exception classes.
(android_mkdir, android_fstat): Remove trailing whitespace.
Diffstat (limited to 'java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsDirectoryEntry.java | 2 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsService.java | 210 |
2 files changed, 119 insertions, 93 deletions
diff --git a/java/org/gnu/emacs/EmacsDirectoryEntry.java b/java/org/gnu/emacs/EmacsDirectoryEntry.java index 9c10f2e8771..75c52e48002 100644 --- a/java/org/gnu/emacs/EmacsDirectoryEntry.java +++ b/java/org/gnu/emacs/EmacsDirectoryEntry.java | |||
| @@ -22,7 +22,7 @@ package org.gnu.emacs; | |||
| 22 | /* Structure holding a single ``directory entry'' from a document | 22 | /* Structure holding a single ``directory entry'' from a document |
| 23 | provider. */ | 23 | provider. */ |
| 24 | 24 | ||
| 25 | public class EmacsDirectoryEntry | 25 | public final class EmacsDirectoryEntry |
| 26 | { | 26 | { |
| 27 | /* The type of this directory entry. 0 means a regular file and 1 | 27 | /* The type of this directory entry. 0 means a regular file and 1 |
| 28 | means a directory. */ | 28 | means a directory. */ |
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index bc62e050345..aa672994f12 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java | |||
| @@ -1723,9 +1723,12 @@ public final class EmacsService extends Service | |||
| 1723 | not: | 1723 | not: |
| 1724 | 1724 | ||
| 1725 | -1, if the file does not exist. | 1725 | -1, if the file does not exist. |
| 1726 | -2, upon a security exception or if WRITABLE the file | 1726 | -2, if WRITABLE and the file is not writable. |
| 1727 | is not writable. | 1727 | -3, upon any other error. |
| 1728 | -3, upon any other error. */ | 1728 | |
| 1729 | In addition, arbitrary runtime exceptions (such as | ||
| 1730 | SecurityException or UnsupportedOperationException) may be | ||
| 1731 | thrown. */ | ||
| 1729 | 1732 | ||
| 1730 | public int | 1733 | public int |
| 1731 | accessDocument (String uri, String documentId, boolean writable) | 1734 | accessDocument (String uri, String documentId, boolean writable) |
| @@ -1754,24 +1757,8 @@ public final class EmacsService extends Service | |||
| 1754 | Document.COLUMN_MIME_TYPE, | 1757 | Document.COLUMN_MIME_TYPE, |
| 1755 | }; | 1758 | }; |
| 1756 | 1759 | ||
| 1757 | try | 1760 | cursor = resolver.query (uriObject, projection, null, |
| 1758 | { | 1761 | null, null); |
| 1759 | cursor = resolver.query (uriObject, projection, null, | ||
| 1760 | null, null); | ||
| 1761 | } | ||
| 1762 | catch (SecurityException exception) | ||
| 1763 | { | ||
| 1764 | /* A SecurityException can be thrown if Emacs doesn't have | ||
| 1765 | access to uriObject. */ | ||
| 1766 | return -2; | ||
| 1767 | } | ||
| 1768 | catch (UnsupportedOperationException exception) | ||
| 1769 | { | ||
| 1770 | exception.printStackTrace (); | ||
| 1771 | |||
| 1772 | /* Why is this? */ | ||
| 1773 | return -3; | ||
| 1774 | } | ||
| 1775 | 1762 | ||
| 1776 | if (cursor == null || !cursor.moveToFirst ()) | 1763 | if (cursor == null || !cursor.moveToFirst ()) |
| 1777 | return -1; | 1764 | return -1; |
| @@ -1816,13 +1803,10 @@ public final class EmacsService extends Service | |||
| 1816 | if (writable && (tem & Document.FLAG_SUPPORTS_WRITE) == 0) | 1803 | if (writable && (tem & Document.FLAG_SUPPORTS_WRITE) == 0) |
| 1817 | return -3; | 1804 | return -3; |
| 1818 | } | 1805 | } |
| 1819 | catch (Exception exception) | 1806 | finally |
| 1820 | { | 1807 | { |
| 1821 | /* Whether or not type errors cause exceptions to be signaled | 1808 | /* Close the cursor if an exception occurs. */ |
| 1822 | is defined ``by the implementation of Cursor'', whatever | 1809 | cursor.close (); |
| 1823 | that means. */ | ||
| 1824 | exception.printStackTrace (); | ||
| 1825 | return -3; | ||
| 1826 | } | 1810 | } |
| 1827 | 1811 | ||
| 1828 | return 0; | 1812 | return 0; |
| @@ -1832,7 +1816,11 @@ public final class EmacsService extends Service | |||
| 1832 | designated by the specified DOCUMENTID within the tree URI. | 1816 | designated by the specified DOCUMENTID within the tree URI. |
| 1833 | 1817 | ||
| 1834 | If DOCUMENTID is NULL, use the document ID within URI itself. | 1818 | If DOCUMENTID is NULL, use the document ID within URI itself. |
| 1835 | Value is NULL upon failure. */ | 1819 | Value is NULL upon failure. |
| 1820 | |||
| 1821 | In addition, arbitrary runtime exceptions (such as | ||
| 1822 | SecurityException or UnsupportedOperationException) may be | ||
| 1823 | thrown. */ | ||
| 1836 | 1824 | ||
| 1837 | public Cursor | 1825 | public Cursor |
| 1838 | openDocumentDirectory (String uri, String documentId) | 1826 | openDocumentDirectory (String uri, String documentId) |
| @@ -1861,25 +1849,8 @@ public final class EmacsService extends Service | |||
| 1861 | Document.COLUMN_MIME_TYPE, | 1849 | Document.COLUMN_MIME_TYPE, |
| 1862 | }; | 1850 | }; |
| 1863 | 1851 | ||
| 1864 | try | 1852 | cursor = resolver.query (uriObject, projection, null, null, |
| 1865 | { | 1853 | null); |
| 1866 | cursor = resolver.query (uriObject, projection, null, null, | ||
| 1867 | null); | ||
| 1868 | } | ||
| 1869 | catch (SecurityException exception) | ||
| 1870 | { | ||
| 1871 | /* A SecurityException can be thrown if Emacs doesn't have | ||
| 1872 | access to uriObject. */ | ||
| 1873 | return null; | ||
| 1874 | } | ||
| 1875 | catch (UnsupportedOperationException exception) | ||
| 1876 | { | ||
| 1877 | exception.printStackTrace (); | ||
| 1878 | |||
| 1879 | /* Why is this? */ | ||
| 1880 | return null; | ||
| 1881 | } | ||
| 1882 | |||
| 1883 | /* Return the cursor. */ | 1854 | /* Return the cursor. */ |
| 1884 | return cursor; | 1855 | return cursor; |
| 1885 | } | 1856 | } |
| @@ -1966,11 +1937,15 @@ public final class EmacsService extends Service | |||
| 1966 | 1937 | ||
| 1967 | Value is NULL upon failure or a parcel file descriptor upon | 1938 | Value is NULL upon failure or a parcel file descriptor upon |
| 1968 | success. Call `ParcelFileDescriptor.close' on this file | 1939 | success. Call `ParcelFileDescriptor.close' on this file |
| 1969 | descriptor instead of using the `close' system call. */ | 1940 | descriptor instead of using the `close' system call. |
| 1941 | |||
| 1942 | FileNotFoundException and/or SecurityException and | ||
| 1943 | UnsupportedOperationException may be thrown upon failure. */ | ||
| 1970 | 1944 | ||
| 1971 | public ParcelFileDescriptor | 1945 | public ParcelFileDescriptor |
| 1972 | openDocument (String uri, String documentId, boolean write, | 1946 | openDocument (String uri, String documentId, boolean write, |
| 1973 | boolean truncate) | 1947 | boolean truncate) |
| 1948 | throws FileNotFoundException | ||
| 1974 | { | 1949 | { |
| 1975 | Uri treeUri, documentUri; | 1950 | Uri treeUri, documentUri; |
| 1976 | String mode; | 1951 | String mode; |
| @@ -1984,40 +1959,33 @@ public final class EmacsService extends Service | |||
| 1984 | documentUri | 1959 | documentUri |
| 1985 | = DocumentsContract.buildDocumentUriUsingTree (treeUri, documentId); | 1960 | = DocumentsContract.buildDocumentUriUsingTree (treeUri, documentId); |
| 1986 | 1961 | ||
| 1987 | try | 1962 | if (write || Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) |
| 1988 | { | 1963 | { |
| 1989 | if (write || Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) | 1964 | /* Select the mode used to open the file. `rw' means open |
| 1990 | { | 1965 | a stat-able file, while `rwt' means that and to |
| 1991 | /* Select the mode used to open the file. `rw' means open | 1966 | truncate the file as well. */ |
| 1992 | a stat-able file, while `rwt' means that and to | ||
| 1993 | truncate the file as well. */ | ||
| 1994 | |||
| 1995 | if (truncate) | ||
| 1996 | mode = "rwt"; | ||
| 1997 | else | ||
| 1998 | mode = "rw"; | ||
| 1999 | |||
| 2000 | fileDescriptor | ||
| 2001 | = resolver.openFileDescriptor (documentUri, mode, | ||
| 2002 | null); | ||
| 2003 | } | ||
| 2004 | else | ||
| 2005 | { | ||
| 2006 | /* Select the mode used to open the file. `openFile' | ||
| 2007 | below means always open a stat-able file. */ | ||
| 2008 | 1967 | ||
| 2009 | if (truncate) | 1968 | if (truncate) |
| 2010 | /* Invalid mode! */ | 1969 | mode = "rwt"; |
| 2011 | return null; | 1970 | else |
| 2012 | else | 1971 | mode = "rw"; |
| 2013 | mode = "r"; | ||
| 2014 | 1972 | ||
| 2015 | fileDescriptor = resolver.openFile (documentUri, mode, null); | 1973 | fileDescriptor |
| 2016 | } | 1974 | = resolver.openFileDescriptor (documentUri, mode, |
| 1975 | null); | ||
| 2017 | } | 1976 | } |
| 2018 | catch (Exception exception) | 1977 | else |
| 2019 | { | 1978 | { |
| 2020 | return null; | 1979 | /* Select the mode used to open the file. `openFile' |
| 1980 | below means always open a stat-able file. */ | ||
| 1981 | |||
| 1982 | if (truncate) | ||
| 1983 | /* Invalid mode! */ | ||
| 1984 | return null; | ||
| 1985 | else | ||
| 1986 | mode = "r"; | ||
| 1987 | |||
| 1988 | fileDescriptor = resolver.openFile (documentUri, mode, null); | ||
| 2021 | } | 1989 | } |
| 2022 | 1990 | ||
| 2023 | return fileDescriptor; | 1991 | return fileDescriptor; |
| @@ -2030,11 +1998,15 @@ public final class EmacsService extends Service | |||
| 2030 | If DOCUMENTID is NULL, create the document inside the root of | 1998 | If DOCUMENTID is NULL, create the document inside the root of |
| 2031 | that tree. | 1999 | that tree. |
| 2032 | 2000 | ||
| 2001 | Either FileNotFoundException, SecurityException or | ||
| 2002 | UnsupportedOperationException may be thrown upon failure. | ||
| 2003 | |||
| 2033 | Return the document ID of the new file upon success, NULL | 2004 | Return the document ID of the new file upon success, NULL |
| 2034 | otherwise. */ | 2005 | otherwise. */ |
| 2035 | 2006 | ||
| 2036 | public String | 2007 | public String |
| 2037 | createDocument (String uri, String documentId, String name) | 2008 | createDocument (String uri, String documentId, String name) |
| 2009 | throws FileNotFoundException | ||
| 2038 | { | 2010 | { |
| 2039 | String mimeType, separator, mime, extension; | 2011 | String mimeType, separator, mime, extension; |
| 2040 | int index; | 2012 | int index; |
| @@ -2072,23 +2044,77 @@ public final class EmacsService extends Service | |||
| 2072 | = DocumentsContract.buildChildDocumentsUriUsingTree (directoryUri, | 2044 | = DocumentsContract.buildChildDocumentsUriUsingTree (directoryUri, |
| 2073 | documentId); | 2045 | documentId); |
| 2074 | 2046 | ||
| 2075 | try | 2047 | docUri = DocumentsContract.createDocument (resolver, |
| 2076 | { | 2048 | directoryUri, |
| 2077 | docUri = DocumentsContract.createDocument (resolver, | 2049 | mimeType, name); |
| 2078 | directoryUri, | ||
| 2079 | mimeType, name); | ||
| 2080 | 2050 | ||
| 2081 | if (docUri == null) | 2051 | if (docUri == null) |
| 2082 | return null; | 2052 | return null; |
| 2083 | 2053 | ||
| 2084 | /* Return the ID of the new document. */ | 2054 | /* Return the ID of the new document. */ |
| 2085 | return DocumentsContract.getDocumentId (docUri); | 2055 | return DocumentsContract.getDocumentId (docUri); |
| 2086 | } | 2056 | } |
| 2087 | catch (Exception exception) | ||
| 2088 | { | ||
| 2089 | exception.printStackTrace (); | ||
| 2090 | } | ||
| 2091 | 2057 | ||
| 2092 | return null; | 2058 | /* Like `createDocument', but create a directory instead of an |
| 2059 | ordinary document. */ | ||
| 2060 | |||
| 2061 | public String | ||
| 2062 | createDirectory (String uri, String documentId, String name) | ||
| 2063 | throws FileNotFoundException | ||
| 2064 | { | ||
| 2065 | int index; | ||
| 2066 | Uri directoryUri, docUri; | ||
| 2067 | |||
| 2068 | /* Now parse URI. */ | ||
| 2069 | directoryUri = Uri.parse (uri); | ||
| 2070 | |||
| 2071 | if (documentId == null) | ||
| 2072 | documentId = DocumentsContract.getTreeDocumentId (directoryUri); | ||
| 2073 | |||
| 2074 | /* And build a file URI referring to the directory. */ | ||
| 2075 | |||
| 2076 | directoryUri | ||
| 2077 | = DocumentsContract.buildChildDocumentsUriUsingTree (directoryUri, | ||
| 2078 | documentId); | ||
| 2079 | |||
| 2080 | /* If name ends with a directory separator character, delete | ||
| 2081 | it. */ | ||
| 2082 | |||
| 2083 | if (name.endsWith ("/")) | ||
| 2084 | name = name.substring (0, name.length () - 1); | ||
| 2085 | |||
| 2086 | /* From Android's perspective, directories are just ordinary | ||
| 2087 | documents with the `MIME_TYPE_DIR' type. */ | ||
| 2088 | |||
| 2089 | docUri = DocumentsContract.createDocument (resolver, | ||
| 2090 | directoryUri, | ||
| 2091 | Document.MIME_TYPE_DIR, | ||
| 2092 | name); | ||
| 2093 | |||
| 2094 | if (docUri == null) | ||
| 2095 | return null; | ||
| 2096 | |||
| 2097 | /* Return the ID of the new document. */ | ||
| 2098 | return DocumentsContract.getDocumentId (docUri); | ||
| 2099 | } | ||
| 2100 | |||
| 2101 | /* Delete the document identified by ID from the document tree | ||
| 2102 | identified by URI. Return 0 upon success and -1 upon | ||
| 2103 | failure. */ | ||
| 2104 | |||
| 2105 | public int | ||
| 2106 | deleteDocument (String uri, String id) | ||
| 2107 | throws FileNotFoundException | ||
| 2108 | { | ||
| 2109 | Uri uriObject; | ||
| 2110 | |||
| 2111 | uriObject = Uri.parse (uri); | ||
| 2112 | uriObject = DocumentsContract.buildDocumentUriUsingTree (uriObject, | ||
| 2113 | id); | ||
| 2114 | |||
| 2115 | if (DocumentsContract.deleteDocument (resolver, uriObject)) | ||
| 2116 | return 0; | ||
| 2117 | |||
| 2118 | return -1; | ||
| 2093 | } | 2119 | } |
| 2094 | }; | 2120 | }; |