Utility methods useful for working with files.

Part of getting DocumentsUI ready for building against public API.

Test: builds
Bug: 110959821
Change-Id: I7cc0acd5ac3bcc89790cb49f34291ae523e44019
This commit is contained in:
Jeff Sharkey
2018-07-09 16:38:20 -06:00
parent 0b5f738f4c
commit 5aae0c9df7
10 changed files with 244 additions and 93 deletions

View File

@@ -9137,6 +9137,7 @@ package android.content {
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
method public void close();
method public static void closeQuietly(android.content.ContentProviderClient);
method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
method public android.content.ContentProvider getLocalContentProvider();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -32547,6 +32548,21 @@ package android.os {
ctor public FileUriExposedException(java.lang.String);
}
public class FileUtils {
method public static void closeQuietly(java.lang.AutoCloseable);
method public static void closeQuietly(java.io.FileDescriptor);
method public static long copy(java.io.File, java.io.File) throws java.io.IOException;
method public static long copy(java.io.File, java.io.File, android.os.CancellationSignal, java.util.concurrent.Executor, android.os.FileUtils.ProgressListener) throws java.io.IOException;
method public static long copy(java.io.InputStream, java.io.OutputStream) throws java.io.IOException;
method public static long copy(java.io.InputStream, java.io.OutputStream, android.os.CancellationSignal, java.util.concurrent.Executor, android.os.FileUtils.ProgressListener) throws java.io.IOException;
method public static long copy(java.io.FileDescriptor, java.io.FileDescriptor) throws java.io.IOException;
method public static long copy(java.io.FileDescriptor, java.io.FileDescriptor, android.os.CancellationSignal, java.util.concurrent.Executor, android.os.FileUtils.ProgressListener) throws java.io.IOException;
}
public static abstract interface FileUtils.ProgressListener {
method public abstract void onProgress(long);
}
public class Handler {
ctor public Handler();
ctor public Handler(android.os.Handler.Callback);
@@ -42510,13 +42526,11 @@ package android.telephony {
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
method public java.lang.String getImei();
method public java.lang.String getImei(int);
method public java.lang.String getTypeAllocationCode();
method public java.lang.String getTypeAllocationCode(int);
method public java.lang.String getLine1Number();
method public java.lang.String getMeid();
method public java.lang.String getMeid(int);
method public java.lang.String getManufacturerCode();
method public java.lang.String getManufacturerCode(int);
method public java.lang.String getMeid();
method public java.lang.String getMeid(int);
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public java.lang.String getNai();
@@ -42539,6 +42553,8 @@ package android.telephony {
method public int getSimState();
method public int getSimState(int);
method public java.lang.String getSubscriberId();
method public java.lang.String getTypeAllocationCode();
method public java.lang.String getTypeAllocationCode(int);
method public java.lang.String getVisualVoicemailPackageName();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();

View File

@@ -39,6 +39,8 @@ import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -560,14 +562,17 @@ public class ContentProviderClient implements AutoCloseable {
return ContentProvider.coerceToLocalContentProvider(mContentProvider);
}
/**
* Closes the given object quietly, ignoring any checked exceptions. Does
* nothing if the given object is {@code null}.
*/
public static void closeQuietly(ContentProviderClient client) {
IoUtils.closeQuietly(client);
}
/** {@hide} */
public static void releaseQuietly(ContentProviderClient client) {
if (client != null) {
try {
client.release();
} catch (Exception ignored) {
}
}
IoUtils.closeQuietly(client);
}
private class NotRespondingRunnable implements Runnable {

View File

@@ -53,32 +53,35 @@ import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;
/**
* Tools for managing files. Not for public consumption.
* @hide
* Utility methods useful for working with files.
*/
public class FileUtils {
private static final String TAG = "FileUtils";
public static final int S_IRWXU = 00700;
public static final int S_IRUSR = 00400;
public static final int S_IWUSR = 00200;
public static final int S_IXUSR = 00100;
/** {@hide} */ public static final int S_IRWXU = 00700;
/** {@hide} */ public static final int S_IRUSR = 00400;
/** {@hide} */ public static final int S_IWUSR = 00200;
/** {@hide} */ public static final int S_IXUSR = 00100;
public static final int S_IRWXG = 00070;
public static final int S_IRGRP = 00040;
public static final int S_IWGRP = 00020;
public static final int S_IXGRP = 00010;
/** {@hide} */ public static final int S_IRWXG = 00070;
/** {@hide} */ public static final int S_IRGRP = 00040;
/** {@hide} */ public static final int S_IWGRP = 00020;
/** {@hide} */ public static final int S_IXGRP = 00010;
public static final int S_IRWXO = 00007;
public static final int S_IROTH = 00004;
public static final int S_IWOTH = 00002;
public static final int S_IXOTH = 00001;
/** {@hide} */ public static final int S_IRWXO = 00007;
/** {@hide} */ public static final int S_IROTH = 00004;
/** {@hide} */ public static final int S_IWOTH = 00002;
/** {@hide} */ public static final int S_IXOTH = 00001;
private FileUtils() {
}
/** Regular expression for safe filenames: no spaces or metacharacters.
*
@@ -94,6 +97,9 @@ public class FileUtils {
private static final long COPY_CHECKPOINT_BYTES = 524288;
/**
* Listener that is called periodically as progress is made.
*/
public interface ProgressListener {
public void onProgress(long progress);
}
@@ -105,6 +111,7 @@ public class FileUtils {
* @param uid to apply through {@code chown}, or -1 to leave unchanged
* @param gid to apply through {@code chown}, or -1 to leave unchanged
* @return 0 on success, otherwise errno.
* @hide
*/
public static int setPermissions(File path, int mode, int uid, int gid) {
return setPermissions(path.getAbsolutePath(), mode, uid, gid);
@@ -117,6 +124,7 @@ public class FileUtils {
* @param uid to apply through {@code chown}, or -1 to leave unchanged
* @param gid to apply through {@code chown}, or -1 to leave unchanged
* @return 0 on success, otherwise errno.
* @hide
*/
public static int setPermissions(String path, int mode, int uid, int gid) {
try {
@@ -145,6 +153,7 @@ public class FileUtils {
* @param uid to apply through {@code chown}, or -1 to leave unchanged
* @param gid to apply through {@code chown}, or -1 to leave unchanged
* @return 0 on success, otherwise errno.
* @hide
*/
public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) {
try {
@@ -166,7 +175,14 @@ public class FileUtils {
return 0;
}
public static void copyPermissions(File from, File to) throws IOException {
/**
* Copy the owner UID, owner GID, and mode bits from one file to another.
*
* @param from File where attributes should be copied from.
* @param to File where attributes should be copied to.
* @hide
*/
public static void copyPermissions(@NonNull File from, @NonNull File to) throws IOException {
try {
final StructStat stat = Os.stat(from.getAbsolutePath());
Os.chmod(to.getAbsolutePath(), stat.st_mode);
@@ -177,8 +193,10 @@ public class FileUtils {
}
/**
* Return owning UID of given path, otherwise -1.
* @deprecated use {@link Os#stat(String)} instead.
* @hide
*/
@Deprecated
public static int getUid(String path) {
try {
return Os.stat(path).st_uid;
@@ -190,6 +208,8 @@ public class FileUtils {
/**
* Perform an fsync on the given FileOutputStream. The stream at this
* point must be flushed but not yet closed.
*
* @hide
*/
public static boolean sync(FileOutputStream stream) {
try {
@@ -204,6 +224,7 @@ public class FileUtils {
/**
* @deprecated use {@link #copy(File, File)} instead.
* @hide
*/
@Deprecated
public static boolean copyFile(File srcFile, File destFile) {
@@ -217,6 +238,7 @@ public class FileUtils {
/**
* @deprecated use {@link #copy(File, File)} instead.
* @hide
*/
@Deprecated
public static void copyFileOrThrow(File srcFile, File destFile) throws IOException {
@@ -227,6 +249,7 @@ public class FileUtils {
/**
* @deprecated use {@link #copy(InputStream, OutputStream)} instead.
* @hide
*/
@Deprecated
public static boolean copyToFile(InputStream inputStream, File destFile) {
@@ -240,6 +263,7 @@ public class FileUtils {
/**
* @deprecated use {@link #copy(InputStream, OutputStream)} instead.
* @hide
*/
@Deprecated
public static void copyToFileOrThrow(InputStream in, File destFile) throws IOException {
@@ -265,7 +289,7 @@ public class FileUtils {
* @return number of bytes copied.
*/
public static long copy(@NonNull File from, @NonNull File to) throws IOException {
return copy(from, to, null, null);
return copy(from, to, null, null, null);
}
/**
@@ -274,16 +298,17 @@ public class FileUtils {
* Attempts to use several optimization strategies to copy the data in the
* kernel before falling back to a userspace copy as a last resort.
*
* @param listener to be periodically notified as the copy progresses.
* @param signal to signal if the copy should be cancelled early.
* @param executor that listener events should be delivered via.
* @param listener to be periodically notified as the copy progresses.
* @return number of bytes copied.
*/
public static long copy(@NonNull File from, @NonNull File to,
@Nullable ProgressListener listener, @Nullable CancellationSignal signal)
throws IOException {
@Nullable CancellationSignal signal, @Nullable Executor executor,
@Nullable ProgressListener listener) throws IOException {
try (FileInputStream in = new FileInputStream(from);
FileOutputStream out = new FileOutputStream(to)) {
return copy(in, out, listener, signal);
return copy(in, out, signal, executor, listener);
}
}
@@ -296,7 +321,7 @@ public class FileUtils {
* @return number of bytes copied.
*/
public static long copy(@NonNull InputStream in, @NonNull OutputStream out) throws IOException {
return copy(in, out, null, null);
return copy(in, out, null, null, null);
}
/**
@@ -305,22 +330,23 @@ public class FileUtils {
* Attempts to use several optimization strategies to copy the data in the
* kernel before falling back to a userspace copy as a last resort.
*
* @param listener to be periodically notified as the copy progresses.
* @param signal to signal if the copy should be cancelled early.
* @param executor that listener events should be delivered via.
* @param listener to be periodically notified as the copy progresses.
* @return number of bytes copied.
*/
public static long copy(@NonNull InputStream in, @NonNull OutputStream out,
@Nullable ProgressListener listener, @Nullable CancellationSignal signal)
throws IOException {
@Nullable CancellationSignal signal, @Nullable Executor executor,
@Nullable ProgressListener listener) throws IOException {
if (ENABLE_COPY_OPTIMIZATIONS) {
if (in instanceof FileInputStream && out instanceof FileOutputStream) {
return copy(((FileInputStream) in).getFD(), ((FileOutputStream) out).getFD(),
listener, signal);
signal, executor, listener);
}
}
// Worse case fallback to userspace
return copyInternalUserspace(in, out, listener, signal);
return copyInternalUserspace(in, out, signal, executor, listener);
}
/**
@@ -333,7 +359,7 @@ public class FileUtils {
*/
public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out)
throws IOException {
return copy(in, out, null, null);
return copy(in, out, null, null, null);
}
/**
@@ -342,14 +368,15 @@ public class FileUtils {
* Attempts to use several optimization strategies to copy the data in the
* kernel before falling back to a userspace copy as a last resort.
*
* @param listener to be periodically notified as the copy progresses.
* @param signal to signal if the copy should be cancelled early.
* @param executor that listener events should be delivered via.
* @param listener to be periodically notified as the copy progresses.
* @return number of bytes copied.
*/
public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
@Nullable ProgressListener listener, @Nullable CancellationSignal signal)
throws IOException {
return copy(in, out, listener, signal, Long.MAX_VALUE);
@Nullable CancellationSignal signal, @Nullable Executor executor,
@Nullable ProgressListener listener) throws IOException {
return copy(in, out, Long.MAX_VALUE, signal, executor, listener);
}
/**
@@ -358,22 +385,24 @@ public class FileUtils {
* Attempts to use several optimization strategies to copy the data in the
* kernel before falling back to a userspace copy as a last resort.
*
* @param listener to be periodically notified as the copy progresses.
* @param signal to signal if the copy should be cancelled early.
* @param count the number of bytes to copy.
* @param signal to signal if the copy should be cancelled early.
* @param executor that listener events should be delivered via.
* @param listener to be periodically notified as the copy progresses.
* @return number of bytes copied.
* @hide
*/
public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
@Nullable ProgressListener listener, @Nullable CancellationSignal signal, long count)
throws IOException {
public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out, long count,
@Nullable CancellationSignal signal, @Nullable Executor executor,
@Nullable ProgressListener listener) throws IOException {
if (ENABLE_COPY_OPTIMIZATIONS) {
try {
final StructStat st_in = Os.fstat(in);
final StructStat st_out = Os.fstat(out);
if (S_ISREG(st_in.st_mode) && S_ISREG(st_out.st_mode)) {
return copyInternalSendfile(in, out, listener, signal, count);
return copyInternalSendfile(in, out, count, signal, executor, listener);
} else if (S_ISFIFO(st_in.st_mode) || S_ISFIFO(st_out.st_mode)) {
return copyInternalSplice(in, out, listener, signal, count);
return copyInternalSplice(in, out, count, signal, executor, listener);
}
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
@@ -381,15 +410,17 @@ public class FileUtils {
}
// Worse case fallback to userspace
return copyInternalUserspace(in, out, listener, signal, count);
return copyInternalUserspace(in, out, count, signal, executor, listener);
}
/**
* Requires one of input or output to be a pipe.
*
* @hide
*/
@VisibleForTesting
public static long copyInternalSplice(FileDescriptor in, FileDescriptor out,
ProgressListener listener, CancellationSignal signal, long count)
public static long copyInternalSplice(FileDescriptor in, FileDescriptor out, long count,
CancellationSignal signal, Executor executor, ProgressListener listener)
throws ErrnoException {
long progress = 0;
long checkpoint = 0;
@@ -405,24 +436,32 @@ public class FileUtils {
if (signal != null) {
signal.throwIfCanceled();
}
if (listener != null) {
listener.onProgress(progress);
if (executor != null && listener != null) {
final long progressSnapshot = progress;
executor.execute(() -> {
listener.onProgress(progressSnapshot);
});
}
checkpoint = 0;
}
}
if (listener != null) {
listener.onProgress(progress);
if (executor != null && listener != null) {
final long progressSnapshot = progress;
executor.execute(() -> {
listener.onProgress(progressSnapshot);
});
}
return progress;
}
/**
* Requires both input and output to be a regular file.
*
* @hide
*/
@VisibleForTesting
public static long copyInternalSendfile(FileDescriptor in, FileDescriptor out,
ProgressListener listener, CancellationSignal signal, long count)
public static long copyInternalSendfile(FileDescriptor in, FileDescriptor out, long count,
CancellationSignal signal, Executor executor, ProgressListener listener)
throws ErrnoException {
long progress = 0;
long checkpoint = 0;
@@ -437,33 +476,52 @@ public class FileUtils {
if (signal != null) {
signal.throwIfCanceled();
}
if (listener != null) {
listener.onProgress(progress);
if (executor != null && listener != null) {
final long progressSnapshot = progress;
executor.execute(() -> {
listener.onProgress(progressSnapshot);
});
}
checkpoint = 0;
}
}
if (listener != null) {
listener.onProgress(progress);
if (executor != null && listener != null) {
final long progressSnapshot = progress;
executor.execute(() -> {
listener.onProgress(progressSnapshot);
});
}
return progress;
}
/** {@hide} */
@Deprecated
@VisibleForTesting
public static long copyInternalUserspace(FileDescriptor in, FileDescriptor out,
ProgressListener listener, CancellationSignal signal, long count) throws IOException {
ProgressListener listener, CancellationSignal signal, long count)
throws IOException {
return copyInternalUserspace(in, out, count, signal, Runnable::run, listener);
}
/** {@hide} */
@VisibleForTesting
public static long copyInternalUserspace(FileDescriptor in, FileDescriptor out, long count,
CancellationSignal signal, Executor executor, ProgressListener listener)
throws IOException {
if (count != Long.MAX_VALUE) {
return copyInternalUserspace(new SizedInputStream(new FileInputStream(in), count),
new FileOutputStream(out), listener, signal);
new FileOutputStream(out), signal, executor, listener);
} else {
return copyInternalUserspace(new FileInputStream(in),
new FileOutputStream(out), listener, signal);
new FileOutputStream(out), signal, executor, listener);
}
}
/** {@hide} */
@VisibleForTesting
public static long copyInternalUserspace(InputStream in, OutputStream out,
ProgressListener listener, CancellationSignal signal) throws IOException {
CancellationSignal signal, Executor executor, ProgressListener listener)
throws IOException {
long progress = 0;
long checkpoint = 0;
byte[] buffer = new byte[8192];
@@ -479,14 +537,20 @@ public class FileUtils {
if (signal != null) {
signal.throwIfCanceled();
}
if (listener != null) {
listener.onProgress(progress);
if (executor != null && listener != null) {
final long progressSnapshot = progress;
executor.execute(() -> {
listener.onProgress(progressSnapshot);
});
}
checkpoint = 0;
}
}
if (listener != null) {
listener.onProgress(progress);
if (executor != null && listener != null) {
final long progressSnapshot = progress;
executor.execute(() -> {
listener.onProgress(progressSnapshot);
});
}
return progress;
}
@@ -494,6 +558,7 @@ public class FileUtils {
/**
* Check if a filename is "safe" (no metacharacters or spaces).
* @param file The file to check
* @hide
*/
public static boolean isFilenameSafe(File file) {
// Note, we check whether it matches what's known to be safe,
@@ -509,6 +574,7 @@ public class FileUtils {
* @param ellipsis to add of the file was truncated (can be null)
* @return the contents of the file, possibly truncated
* @throws IOException if something goes wrong reading the file
* @hide
*/
public static String readTextFile(File file, int max, String ellipsis) throws IOException {
InputStream input = new FileInputStream(file);
@@ -563,13 +629,16 @@ public class FileUtils {
}
}
/** {@hide} */
public static void stringToFile(File file, String string) throws IOException {
stringToFile(file.getAbsolutePath(), string);
}
/*
/**
* Writes the bytes given in {@code content} to the file whose absolute path
* is {@code filename}.
*
* @hide
*/
public static void bytesToFile(String filename, byte[] content) throws IOException {
if (filename.startsWith("/proc/")) {
@@ -592,18 +661,23 @@ public class FileUtils {
* @param filename
* @param string
* @throws IOException
* @hide
*/
public static void stringToFile(String filename, String string) throws IOException {
bytesToFile(filename, string.getBytes(StandardCharsets.UTF_8));
}
/**
* Computes the checksum of a file using the CRC32 checksum routine.
* The value of the checksum is returned.
* Computes the checksum of a file using the CRC32 checksum routine. The
* value of the checksum is returned.
*
* @param file the file to checksum, must not be null
* @param file the file to checksum, must not be null
* @return the checksum value or an exception is thrown.
* @deprecated this is a weak hashing algorithm, and should not be used due
* to its potential for collision.
* @hide
*/
@Deprecated
public static long checksumCrc32(File file) throws FileNotFoundException, IOException {
CRC32 checkSummer = new CRC32();
CheckedInputStream cis = null;
@@ -632,6 +706,7 @@ public class FileUtils {
* @param minCount Always keep at least this many files.
* @param minAgeMs Always keep files younger than this age, in milliseconds.
* @return if any files were deleted.
* @hide
*/
public static boolean deleteOlderFiles(File dir, int minCount, long minAgeMs) {
if (minCount < 0 || minAgeMs < 0) {
@@ -673,6 +748,8 @@ public class FileUtils {
* Both files <em>must</em> have been resolved using
* {@link File#getCanonicalFile()} to avoid symlink or path traversal
* attacks.
*
* @hide
*/
public static boolean contains(File[] dirs, File file) {
for (File dir : dirs) {
@@ -690,12 +767,15 @@ public class FileUtils {
* Both files <em>must</em> have been resolved using
* {@link File#getCanonicalFile()} to avoid symlink or path traversal
* attacks.
*
* @hide
*/
public static boolean contains(File dir, File file) {
if (dir == null || file == null) return false;
return contains(dir.getAbsolutePath(), file.getAbsolutePath());
}
/** {@hide} */
public static boolean contains(String dirPath, String filePath) {
if (dirPath.equals(filePath)) {
return true;
@@ -706,6 +786,7 @@ public class FileUtils {
return filePath.startsWith(dirPath);
}
/** {@hide} */
public static boolean deleteContentsAndDir(File dir) {
if (deleteContents(dir)) {
return dir.delete();
@@ -714,6 +795,7 @@ public class FileUtils {
}
}
/** {@hide} */
public static boolean deleteContents(File dir) {
File[] files = dir.listFiles();
boolean success = true;
@@ -743,6 +825,8 @@ public class FileUtils {
/**
* Check if given filename is valid for an ext4 filesystem.
*
* @hide
*/
public static boolean isValidExtFilename(String name) {
return (name != null) && name.equals(buildValidExtFilename(name));
@@ -751,6 +835,8 @@ public class FileUtils {
/**
* Mutate the given filename to make it valid for an ext4 filesystem,
* replacing any invalid characters with "_".
*
* @hide
*/
public static String buildValidExtFilename(String name) {
if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) {
@@ -792,6 +878,8 @@ public class FileUtils {
/**
* Check if given filename is valid for a FAT filesystem.
*
* @hide
*/
public static boolean isValidFatFilename(String name) {
return (name != null) && name.equals(buildValidFatFilename(name));
@@ -800,6 +888,8 @@ public class FileUtils {
/**
* Mutate the given filename to make it valid for a FAT filesystem,
* replacing any invalid characters with "_".
*
* @hide
*/
public static String buildValidFatFilename(String name) {
if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) {
@@ -820,6 +910,7 @@ public class FileUtils {
return res.toString();
}
/** {@hide} */
@VisibleForTesting
public static String trimFilename(String str, int maxBytes) {
final StringBuilder res = new StringBuilder(str);
@@ -827,6 +918,7 @@ public class FileUtils {
return res.toString();
}
/** {@hide} */
private static void trimFilename(StringBuilder res, int maxBytes) {
byte[] raw = res.toString().getBytes(StandardCharsets.UTF_8);
if (raw.length > maxBytes) {
@@ -839,12 +931,14 @@ public class FileUtils {
}
}
/** {@hide} */
public static String rewriteAfterRename(File beforeDir, File afterDir, String path) {
if (path == null) return null;
final File result = rewriteAfterRename(beforeDir, afterDir, new File(path));
return (result != null) ? result.getAbsolutePath() : null;
}
/** {@hide} */
public static String[] rewriteAfterRename(File beforeDir, File afterDir, String[] paths) {
if (paths == null) return null;
final String[] result = new String[paths.length];
@@ -858,6 +952,8 @@ public class FileUtils {
* Given a path under the "before" directory, rewrite it to live under the
* "after" directory. For example, {@code /before/foo/bar.txt} would become
* {@code /after/foo/bar.txt}.
*
* @hide
*/
public static File rewriteAfterRename(File beforeDir, File afterDir, File file) {
if (file == null || beforeDir == null || afterDir == null) return null;
@@ -869,6 +965,7 @@ public class FileUtils {
return null;
}
/** {@hide} */
private static File buildUniqueFileWithExtension(File parent, String name, String ext)
throws FileNotFoundException {
File file = buildFile(parent, name, ext);
@@ -895,6 +992,7 @@ public class FileUtils {
* 'example.txt' or 'example (1).txt', etc.
*
* @throws FileNotFoundException
* @hide
*/
public static File buildUniqueFile(File parent, String mimeType, String displayName)
throws FileNotFoundException {
@@ -905,6 +1003,8 @@ public class FileUtils {
/**
* Generates a unique file name under the given parent directory, keeping
* any extension intact.
*
* @hide
*/
public static File buildUniqueFile(File parent, String displayName)
throws FileNotFoundException {
@@ -929,6 +1029,8 @@ public class FileUtils {
* If the display name doesn't have an extension that matches the requested MIME type, the
* extension is regarded as a part of filename and default extension for that MIME type is
* appended.
*
* @hide
*/
public static String[] splitFileName(String mimeType, String displayName) {
String name;
@@ -975,6 +1077,7 @@ public class FileUtils {
return new String[] { name, ext };
}
/** {@hide} */
private static File buildFile(File parent, String name, String ext) {
if (TextUtils.isEmpty(ext)) {
return new File(parent, name);
@@ -983,6 +1086,7 @@ public class FileUtils {
}
}
/** {@hide} */
public static @NonNull String[] listOrEmpty(@Nullable File dir) {
if (dir == null) return EmptyArray.STRING;
final String[] res = dir.list();
@@ -993,6 +1097,7 @@ public class FileUtils {
}
}
/** {@hide} */
public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) {
if (dir == null) return EMPTY;
final File[] res = dir.listFiles();
@@ -1003,6 +1108,7 @@ public class FileUtils {
}
}
/** {@hide} */
public static @NonNull File[] listFilesOrEmpty(@Nullable File dir, FilenameFilter filter) {
if (dir == null) return EMPTY;
final File[] res = dir.listFiles(filter);
@@ -1013,6 +1119,7 @@ public class FileUtils {
}
}
/** {@hide} */
public static @Nullable File newFileOrNull(@Nullable String path) {
return (path != null) ? new File(path) : null;
}
@@ -1021,6 +1128,8 @@ public class FileUtils {
* Creates a directory with name {@code name} under an existing directory {@code baseDir}.
* Returns a {@code File} object representing the directory on success, {@code null} on
* failure.
*
* @hide
*/
public static @Nullable File createDir(File baseDir, String name) {
final File dir = new File(baseDir, name);
@@ -1036,6 +1145,8 @@ public class FileUtils {
* Round the given size of a storage device to a nice round power-of-two
* value, such as 256MB or 32GB. This avoids showing weird values like
* "29.5GB" in UI.
*
* @hide
*/
public static long roundStorageSize(long size) {
long val = 1;
@@ -1050,6 +1161,23 @@ public class FileUtils {
return val * pow;
}
/**
* Closes the given object quietly, ignoring any checked exceptions. Does
* nothing if the given object is {@code null}.
*/
public static void closeQuietly(@Nullable AutoCloseable closeable) {
IoUtils.closeQuietly(closeable);
}
/**
* Closes the given object quietly, ignoring any checked exceptions. Does
* nothing if the given object is {@code null}.
*/
public static void closeQuietly(@Nullable FileDescriptor fd) {
IoUtils.closeQuietly(fd);
}
/** {@hide} */
@VisibleForTesting
public static class MemoryPipe extends Thread implements AutoCloseable {
private final FileDescriptor[] pipe;

View File

@@ -118,7 +118,7 @@ public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
protected Void doInBackground(Void... params) {
try (InputStream in = new FileInputStream(mFile);
OutputStream out = new FileOutputStream(mDestination.getFileDescriptor())) {
FileUtils.copy(in, out, null, mCancellationSignal);
FileUtils.copy(in, out, mCancellationSignal, null, null);
} catch (OperationCanceledException e) {
// Ignored; already handled below
} catch (IOException e) {

View File

@@ -100,7 +100,8 @@ public final class DocumentsContract {
public static final String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
/** {@hide} */
public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
@Deprecated
public static final String EXTRA_PACKAGE_NAME = Intent.EXTRA_PACKAGE_NAME;
/** {@hide} */
public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";

View File

@@ -54,7 +54,7 @@ public class FileUtilsBenchmark {
for (int i = 0; i < reps; i++) {
try (FileInputStream in = new FileInputStream(mSrc);
FileOutputStream out = new FileOutputStream(mDest)) {
copyInternalUserspace(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
copyInternalUserspace(in.getFD(), out.getFD(), Long.MAX_VALUE, null, null, null);
}
}
}
@@ -63,7 +63,7 @@ public class FileUtilsBenchmark {
for (int i = 0; i < reps; i++) {
try (FileInputStream in = new FileInputStream(mSrc);
FileOutputStream out = new FileOutputStream(mDest)) {
copyInternalSendfile(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
copyInternalSendfile(in.getFD(), out.getFD(), Long.MAX_VALUE, null, null, null);
}
}
}
@@ -72,7 +72,7 @@ public class FileUtilsBenchmark {
for (int i = 0; i < reps; i++) {
try (MemoryPipe in = MemoryPipe.createSource(mData);
FileOutputStream out = new FileOutputStream(mDest)) {
copyInternalUserspace(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
copyInternalUserspace(in.getFD(), out.getFD(), Long.MAX_VALUE, null, null, null);
}
}
}
@@ -81,7 +81,7 @@ public class FileUtilsBenchmark {
for (int i = 0; i < reps; i++) {
try (MemoryPipe in = MemoryPipe.createSource(mData);
FileOutputStream out = new FileOutputStream(mDest)) {
copyInternalSplice(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
copyInternalSplice(in.getFD(), out.getFD(), Long.MAX_VALUE, null, null, null);
}
}
}
@@ -90,7 +90,7 @@ public class FileUtilsBenchmark {
for (int i = 0; i < reps; i++) {
try (FileInputStream in = new FileInputStream(mSrc);
MemoryPipe out = MemoryPipe.createSink(mData)) {
copyInternalUserspace(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
copyInternalUserspace(in.getFD(), out.getFD(), Long.MAX_VALUE, null, null, null);
}
}
}
@@ -99,7 +99,7 @@ public class FileUtilsBenchmark {
for (int i = 0; i < reps; i++) {
try (FileInputStream in = new FileInputStream(mSrc);
MemoryPipe out = MemoryPipe.createSink(mData)) {
copyInternalSplice(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
copyInternalSplice(in.getFD(), out.getFD(), Long.MAX_VALUE, null, null, null);
}
}
}

View File

@@ -193,7 +193,7 @@ public class FileUtilsTest {
try (MemoryPipe in = MemoryPipe.createSource(source);
FileOutputStream out = new FileOutputStream(dest)) {
FileUtils.copy(in.getFD(), out.getFD(), null, null, size);
FileUtils.copy(in.getFD(), out.getFD(), size, null, null, null);
}
actual = readFile(dest);

View File

@@ -297,7 +297,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
+ " cannot be null");
}
mCallingPackageName = extras.getString(DocumentsContract.EXTRA_PACKAGE_NAME);
mCallingPackageName = extras.getString(Intent.EXTRA_PACKAGE_NAME);
if (savedInstanceState == null) {
MetricsLogger.action(this, MetricsEvent.PRINT_PREVIEW, mCallingPackageName);
@@ -715,7 +715,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.setType("application/pdf");
intent.putExtra(Intent.EXTRA_TITLE, info.getName());
intent.putExtra(DocumentsContract.EXTRA_PACKAGE_NAME, mCallingPackageName);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mCallingPackageName);
try {
startActivityForResult(intent, ACTIVITY_REQUEST_CREATE_FILE);

View File

@@ -685,13 +685,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// inserted above to hold the session active.
try {
final Int64Ref last = new Int64Ref(0);
FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, (long progress) -> {
if (params.sizeBytes > 0) {
final long delta = progress - last.value;
last.value = progress;
addClientProgress((float) delta / (float) params.sizeBytes);
}
}, null, lengthBytes);
FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null,
Runnable::run, (long progress) -> {
if (params.sizeBytes > 0) {
final long delta = progress - last.value;
last.value = progress;
addClientProgress((float) delta / (float) params.sizeBytes);
}
});
} finally {
IoUtils.closeQuietly(targetFd);
IoUtils.closeQuietly(incomingFd);

View File

@@ -243,7 +243,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
intent.setData(Uri.fromParts("printjob", printJob.getId().flattenToString(), null));
intent.putExtra(PrintManager.EXTRA_PRINT_DOCUMENT_ADAPTER, adapter.asBinder());
intent.putExtra(PrintManager.EXTRA_PRINT_JOB, printJob);
intent.putExtra(DocumentsContract.EXTRA_PACKAGE_NAME, packageName);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
IntentSender intentSender = PendingIntent.getActivityAsUser(
mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT