Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 63280e06 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Utilities for content:// Uris and file modes.

Bug: 111268862, 111960973
Test: atest cts/tests/tests/content/src/android/content/cts/ContentUrisTest.java
Test: atest frameworks/base/core/tests/coretests/src/android/os/FileUtilsTest.java
Change-Id: I94373055468d279e6553d4a038267732b9b53745
parent 7bd671e1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9332,6 +9332,7 @@ package android.content {
    ctor public ContentUris();
    method public static android.net.Uri.Builder appendId(android.net.Uri.Builder, long);
    method public static long parseId(android.net.Uri);
    method public static android.net.Uri removeId(android.net.Uri);
    method public static android.net.Uri withAppendedId(android.net.Uri, long);
  }
+28 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package android.content;

import android.net.Uri;

import java.util.List;

/**
* Utility methods useful for working with {@link android.net.Uri} objects
* that use the "content" (content://) scheme.
@@ -109,4 +111,30 @@ public class ContentUris {
    public static Uri withAppendedId(Uri contentUri, long id) {
        return appendId(contentUri.buildUpon(), id).build();
    }

    /**
     * Removes any ID from the end of the path.
     *
     * @param contentUri that ends with an ID
     * @return a new URI with the ID removed from the end of the path
     * @throws IllegalArgumentException when the given URI has no ID to remove
     *             from the end of the path
     */
    public static Uri removeId(Uri contentUri) {
        // Verify that we have a valid ID to actually remove
        final String last = contentUri.getLastPathSegment();
        if (last == null) {
            throw new IllegalArgumentException("No path segments to remove");
        } else {
            Long.parseLong(last);
        }

        final List<String> segments = contentUri.getPathSegments();
        final Uri.Builder builder = contentUri.buildUpon();
        builder.path(null);
        for (int i = 0; i < segments.size() - 1; i++) {
            builder.appendPath(segments.get(i));
        }
        return builder.build();
    }
}
+109 −2
Original line number Diff line number Diff line
@@ -16,6 +16,18 @@

package android.os;

import static android.os.ParcelFileDescriptor.MODE_APPEND;
import static android.os.ParcelFileDescriptor.MODE_CREATE;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
import static android.system.OsConstants.O_APPEND;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_RDWR;
import static android.system.OsConstants.O_TRUNC;
import static android.system.OsConstants.O_WRONLY;
import static android.system.OsConstants.SPLICE_F_MORE;
import static android.system.OsConstants.SPLICE_F_MOVE;
import static android.system.OsConstants.S_ISFIFO;
@@ -1061,8 +1073,13 @@ public class FileUtils {
                mimeTypeFromExt = ContentResolver.MIME_TYPE_DEFAULT;
            }

            final String extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType(
                    mimeType);
            final String extFromMimeType;
            if (ContentResolver.MIME_TYPE_DEFAULT.equals(mimeType)) {
                extFromMimeType = null;
            } else {
                extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
            }

            if (Objects.equals(mimeType, mimeTypeFromExt) || Objects.equals(ext, extFromMimeType)) {
                // Extension maps back to requested MIME type; allow it
            } else {
@@ -1179,6 +1196,96 @@ public class FileUtils {
        IoUtils.closeQuietly(fd);
    }

    /** {@hide} */
    public static int translateModeStringToPosix(String mode) {
        int res = 0;
        if (mode.startsWith("rw")) {
            res |= O_RDWR | O_CREAT;
        } else if (mode.startsWith("w")) {
            res |= O_WRONLY | O_CREAT;
        } else if (mode.startsWith("r")) {
            res |= O_RDONLY;
        } else {
            throw new IllegalArgumentException("Bad mode: " + mode);
        }
        if (mode.indexOf('t') != -1) {
            res |= O_TRUNC;
        }
        if (mode.indexOf('a') != -1) {
            res |= O_APPEND;
        }
        return res;
    }

    /** {@hide} */
    public static String translateModePosixToString(int mode) {
        String res = "";
        if ((mode & O_RDWR) == O_RDWR) {
            res += "rw";
        } else if ((mode & O_WRONLY) == O_WRONLY) {
            res += "w";
        } else if ((mode & O_RDONLY) == O_RDONLY) {
            res += "r";
        } else {
            throw new IllegalArgumentException("Bad mode: " + mode);
        }
        if ((mode & O_TRUNC) == O_TRUNC) {
            res += "t";
        }
        if ((mode & O_APPEND) == O_APPEND) {
            res += "a";
        }
        return res;
    }

    /** {@hide} */
    public static int translateModePosixToPfd(int mode) {
        int res = 0;
        if ((mode & O_RDWR) == O_RDWR) {
            res |= MODE_READ_WRITE;
        } else if ((mode & O_WRONLY) == O_WRONLY) {
            res |= MODE_WRITE_ONLY;
        } else if ((mode & O_RDONLY) == O_RDONLY) {
            res |= MODE_READ_ONLY;
        } else {
            throw new IllegalArgumentException("Bad mode: " + mode);
        }
        if ((mode & O_CREAT) == O_CREAT) {
            res |= MODE_CREATE;
        }
        if ((mode & O_TRUNC) == O_TRUNC) {
            res |= MODE_TRUNCATE;
        }
        if ((mode & O_APPEND) == O_APPEND) {
            res |= MODE_APPEND;
        }
        return res;
    }

    /** {@hide} */
    public static int translateModePfdToPosix(int mode) {
        int res = 0;
        if ((mode & MODE_READ_WRITE) == MODE_READ_WRITE) {
            res |= O_RDWR;
        } else if ((mode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) {
            res |= O_WRONLY;
        } else if ((mode & MODE_READ_ONLY) == MODE_READ_ONLY) {
            res |= O_RDONLY;
        } else {
            throw new IllegalArgumentException("Bad mode: " + mode);
        }
        if ((mode & MODE_CREATE) == MODE_CREATE) {
            res |= O_CREAT;
        }
        if ((mode & MODE_TRUNCATE) == MODE_TRUNCATE) {
            res |= O_TRUNC;
        }
        if ((mode & MODE_APPEND) == MODE_APPEND) {
            res |= O_APPEND;
        }
        return res;
    }

    /** {@hide} */
    @VisibleForTesting
    public static class MemoryPipe extends Thread implements AutoCloseable {
+1 −22
Original line number Diff line number Diff line
@@ -559,28 +559,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
     * @throws IllegalArgumentException if the given string does not match a known file mode.
     */
    public static int parseMode(String mode) {
        final int modeBits;
        if ("r".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
        } else if ("w".equals(mode) || "wt".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
                    | ParcelFileDescriptor.MODE_CREATE
                    | ParcelFileDescriptor.MODE_TRUNCATE;
        } else if ("wa".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
                    | ParcelFileDescriptor.MODE_CREATE
                    | ParcelFileDescriptor.MODE_APPEND;
        } else if ("rw".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
                    | ParcelFileDescriptor.MODE_CREATE;
        } else if ("rwt".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
                    | ParcelFileDescriptor.MODE_CREATE
                    | ParcelFileDescriptor.MODE_TRUNCATE;
        } else {
            throw new IllegalArgumentException("Bad mode '" + mode + "'");
        }
        return modeBits;
        return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode));
    }

    /**
+42 −0
Original line number Diff line number Diff line
@@ -17,6 +17,22 @@
package android.os;

import static android.os.FileUtils.roundStorageSize;
import static android.os.FileUtils.translateModePfdToPosix;
import static android.os.FileUtils.translateModePosixToPfd;
import static android.os.FileUtils.translateModePosixToString;
import static android.os.FileUtils.translateModeStringToPosix;
import static android.os.ParcelFileDescriptor.MODE_APPEND;
import static android.os.ParcelFileDescriptor.MODE_CREATE;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
import static android.system.OsConstants.O_APPEND;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_RDWR;
import static android.system.OsConstants.O_TRUNC;
import static android.system.OsConstants.O_WRONLY;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
@@ -476,6 +492,32 @@ public class FileUtilsTest {
        assertEquals(G64, roundStorageSize(G32 + 1));
    }

    @Test
    public void testTranslateMode() throws Exception {
        assertTranslate("r", O_RDONLY, MODE_READ_ONLY);

        assertTranslate("rw", O_RDWR | O_CREAT,
                MODE_READ_WRITE | MODE_CREATE);
        assertTranslate("rwt", O_RDWR | O_CREAT | O_TRUNC,
                MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
        assertTranslate("rwa", O_RDWR | O_CREAT | O_APPEND,
                MODE_READ_WRITE | MODE_CREATE | MODE_APPEND);

        assertTranslate("w", O_WRONLY | O_CREAT,
                MODE_WRITE_ONLY | MODE_CREATE | MODE_CREATE);
        assertTranslate("wt", O_WRONLY | O_CREAT | O_TRUNC,
                MODE_WRITE_ONLY | MODE_CREATE | MODE_TRUNCATE);
        assertTranslate("wa", O_WRONLY | O_CREAT | O_APPEND,
                MODE_WRITE_ONLY | MODE_CREATE | MODE_APPEND);
    }

    private static void assertTranslate(String string, int posix, int pfd) {
        assertEquals(posix, translateModeStringToPosix(string));
        assertEquals(string, translateModePosixToString(posix));
        assertEquals(pfd, translateModePosixToPfd(posix));
        assertEquals(posix, translateModePfdToPosix(pfd));
    }

    private static void assertNameEquals(String expected, File actual) {
        assertEquals(expected, actual.getName());
    }