Use UnFile submodule

This commit is contained in:
seven332 committed 2015-06-08 17:03:44 +08:00
1 parent f6a63dd8df
commit 1899571aef
15 files changed
+15 -1153

No files matched your search

@@ -1,166 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.unifile;
import android.content.Context;
import android.net.Uri;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
class DocumentFile extends UniFile {
private Context mContext;
private Uri mUri;
DocumentFile(UniFile parent, Context context, Uri uri) {
super(parent);
mContext = context;
mUri = uri;
}
@Override
public UniFile createFile(String displayName) {
UniFile child = contains(displayName);
if (child != null) {
if (child.isFile()) {
return child;
} else {
return null;
}
} else {
final Uri result = DocumentsContractApi21.createFile(mContext, mUri, "application/octet-stream", displayName);
return (result != null) ? new DocumentFile(this, mContext, result) : null;
}
}
@Override
public UniFile createDirectory(String displayName) {
UniFile child = contains(displayName);
if (child != null) {
if (child.isDirectory()) {
return child;
} else {
return null;
}
} else {
final Uri result = DocumentsContractApi21.createDirectory(mContext, mUri, displayName);
return (result != null) ? new DocumentFile(this, mContext, result) : null;
}
}
@Override
public Uri getUri() {
return mUri;
}
@Override
public String getName() {
return DocumentsContractApi19.getName(mContext, mUri);
}
@Override
public String getType() {
return DocumentsContractApi19.getType(mContext, mUri);
}
@Override
public boolean isDirectory() {
return DocumentsContractApi19.isDirectory(mContext, mUri);
}
@Override
public boolean isFile() {
return DocumentsContractApi19.isFile(mContext, mUri);
}
@Override
public long lastModified() {
return DocumentsContractApi19.lastModified(mContext, mUri);
}
@Override
public long length() {
return DocumentsContractApi19.length(mContext, mUri);
}
@Override
public boolean canRead() {
return DocumentsContractApi19.canRead(mContext, mUri);
}
@Override
public boolean canWrite() {
return DocumentsContractApi19.canWrite(mContext, mUri);
}
@Override
public boolean delete() {
return DocumentsContractApi19.delete(mContext, mUri);
}
@Override
public boolean exists() {
return DocumentsContractApi19.exists(mContext, mUri);
}
@Override
public UniFile contains(String displayName) {
Uri childUri = DocumentsContractApi21.buildChildUri(mUri, displayName);
return DocumentsContractApi19.exists(mContext, childUri) ?
new DocumentFile(this, mContext, childUri) : null;
}
@Override
public UniFile[] listFiles() {
final Uri[] result = DocumentsContractApi21.listFiles(mContext, mUri);
final UniFile[] resultFiles = new UniFile[result.length];
for (int i = 0; i < result.length; i++) {
resultFiles[i] = new DocumentFile(this, mContext, result[i]);
}
return resultFiles;
}
@Override
public boolean renameTo(String displayName) {
final Uri result = DocumentsContractApi21.renameTo(mContext, mUri, displayName);
if (result != null) {
mUri = result;
return true;
} else {
return false;
}
}
@Override
public OutputStream openOutputStream() throws IOException {
return mContext.getContentResolver().openOutputStream(mUri);
}
@Override
public OutputStream openOutputStream(boolean append) throws IOException {
return mContext.getContentResolver().openOutputStream(mUri, append ? "wa" : "w");
}
@Override
public InputStream openInputStream() throws IOException {
return mContext.getContentResolver().openInputStream(mUri);
}
}
@@ -1,200 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.unifile;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.text.TextUtils;
import android.util.Log;
@TargetApi(Build.VERSION_CODES.KITKAT)
class DocumentsContractApi19 {
private static final String TAG = "UniFile";
public static boolean isDocumentUri(Context context, Uri self) {
return DocumentsContract.isDocumentUri(context, self);
}
public static String getName(Context context, Uri self) {
return queryForString(context, self, DocumentsContract.Document.COLUMN_DISPLAY_NAME, null);
}
private static String getRawType(Context context, Uri self) {
return queryForString(context, self, DocumentsContract.Document.COLUMN_MIME_TYPE, null);
}
public static String getType(Context context, Uri self) {
final String rawType = getRawType(context, self);
if (DocumentsContract.Document.MIME_TYPE_DIR.equals(rawType)) {
return null;
} else {
return rawType;
}
}
public static boolean isDirectory(Context context, Uri self) {
return DocumentsContract.Document.MIME_TYPE_DIR.equals(getRawType(context, self));
}
public static boolean isFile(Context context, Uri self) {
final String type = getRawType(context, self);
if (DocumentsContract.Document.MIME_TYPE_DIR.equals(type) || TextUtils.isEmpty(type)) {
return false;
} else {
return true;
}
}
public static long lastModified(Context context, Uri self) {
return queryForLong(context, self, DocumentsContract.Document.COLUMN_LAST_MODIFIED, 0);
}
public static long length(Context context, Uri self) {
return queryForLong(context, self, DocumentsContract.Document.COLUMN_SIZE, 0);
}
public static boolean canRead(Context context, Uri self) {
// Ignore if grant doesn't allow read
if (context.checkCallingOrSelfUriPermission(self, Intent.FLAG_GRANT_READ_URI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
// Ignore documents without MIME
if (TextUtils.isEmpty(getRawType(context, self))) {
return false;
}
return true;
}
public static boolean canWrite(Context context, Uri self) {
// Ignore if grant doesn't allow write
if (context.checkCallingOrSelfUriPermission(self, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
final String type = getRawType(context, self);
final int flags = queryForInt(context, self, DocumentsContract.Document.COLUMN_FLAGS, 0);
// Ignore documents without MIME
if (TextUtils.isEmpty(type)) {
return false;
}
// Deletable documents considered writable
if ((flags & DocumentsContract.Document.FLAG_SUPPORTS_DELETE) != 0) {
return true;
}
if (DocumentsContract.Document.MIME_TYPE_DIR.equals(type)
&& (flags & DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE) != 0) {
// Directories that allow create considered writable
return true;
} else if (!TextUtils.isEmpty(type)
&& (flags & DocumentsContract.Document.FLAG_SUPPORTS_WRITE) != 0) {
// Writable normal files considered writable
return true;
}
return false;
}
public static boolean delete(Context context, Uri self) {
return DocumentsContract.deleteDocument(context.getContentResolver(), self);
}
public static boolean exists(Context context, Uri self) {
final ContentResolver resolver = context.getContentResolver();
Cursor c = null;
try {
c = resolver.query(self, new String[] {
DocumentsContract.Document.COLUMN_DOCUMENT_ID }, null, null, null);
return c.getCount() > 0;
} catch (Exception e) {
Log.w(TAG, "Failed query: " + e);
return false;
} finally {
closeQuietly(c);
}
}
private static String queryForString(Context context, Uri self, String column,
String defaultValue) {
final ContentResolver resolver = context.getContentResolver();
Cursor c = null;
try {
c = resolver.query(self, new String[] { column }, null, null, null);
if (c.moveToFirst() && !c.isNull(0)) {
return c.getString(0);
} else {
return defaultValue;
}
} catch (Exception e) {
Log.w(TAG, "Failed query: " + e);
return defaultValue;
} finally {
closeQuietly(c);
}
}
private static int queryForInt(Context context, Uri self, String column,
int defaultValue) {
return (int) queryForLong(context, self, column, defaultValue);
}
private static long queryForLong(Context context, Uri self, String column,
long defaultValue) {
final ContentResolver resolver = context.getContentResolver();
Cursor c = null;
try {
c = resolver.query(self, new String[] { column }, null, null, null);
if (c.moveToFirst() && !c.isNull(0)) {
return c.getLong(0);
} else {
return defaultValue;
}
} catch (Exception e) {
Log.w(TAG, "Failed query: " + e);
return defaultValue;
} finally {
closeQuietly(c);
}
}
private static void closeQuietly(AutoCloseable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (RuntimeException rethrown) {
throw rethrown;
} catch (Exception ignored) {
}
}
}
}
@@ -1,105 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.unifile;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class DocumentsContractApi21 {
private static final String TAG = "UniFile";
private static final String PATH_DOCUMENT = "document";
private static final String PATH_TREE = "tree";
public static Uri createFile(Context context, Uri self, String mimeType,
String displayName) {
return DocumentsContract.createDocument(context.getContentResolver(), self, mimeType,
displayName);
}
public static Uri createDirectory(Context context, Uri self, String displayName) {
return createFile(context, self, DocumentsContract.Document.MIME_TYPE_DIR, displayName);
}
public static Uri prepareTreeUri(Uri treeUri) {
return DocumentsContract.buildDocumentUriUsingTree(treeUri,
DocumentsContract.getTreeDocumentId(treeUri));
}
public static String getTreeDocumentPath(Uri documentUri) {
final List<String> paths = documentUri.getPathSegments();
if (paths.size() >= 4 && PATH_TREE.equals(paths.get(0)) && PATH_DOCUMENT.equals(paths.get(2))) {
return paths.get(3);
}
throw new IllegalArgumentException("Invalid URI: " + documentUri);
}
public static Uri buildChildUri(Uri uri, String displayName) {
return DocumentsContract.buildDocumentUriUsingTree(uri,
getTreeDocumentPath(uri) + "/" + displayName);
}
public static Uri[] listFiles(Context context, Uri self) {
final ContentResolver resolver = context.getContentResolver();
final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(self,
DocumentsContract.getDocumentId(self));
final ArrayList<Uri> results = new ArrayList<Uri>();
Cursor c = null;
try {
c = resolver.query(childrenUri, new String[] {
DocumentsContract.Document.COLUMN_DOCUMENT_ID }, null, null, null);
while (c.moveToNext()) {
final String documentId = c.getString(0);
final Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(self,
documentId);
results.add(documentUri);
}
} catch (Exception e) {
Log.w(TAG, "Failed query: " + e);
} finally {
closeQuietly(c);
}
return results.toArray(new Uri[results.size()]);
}
public static Uri renameTo(Context context, Uri self, String displayName) {
return DocumentsContract.renameDocument(context.getContentResolver(), self, displayName);
}
private static void closeQuietly(AutoCloseable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (RuntimeException rethrown) {
throw rethrown;
} catch (Exception ignored) {
}
}
}
}
@@ -1,194 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.unifile;
import android.net.Uri;
import android.util.Log;
import android.webkit.MimeTypeMap;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
class RawFile extends UniFile {
private File mFile;
RawFile(UniFile parent, File file) {
super(parent);
mFile = file;
}
@Override
public UniFile createFile(String displayName) {
final File target = new File(mFile, displayName);
try {
target.createNewFile();
return new RawFile(this, target);
} catch (IOException e) {
Log.w(TAG, "Failed to createFile: " + e);
return null;
}
}
@Override
public UniFile createDirectory(String displayName) {
final File target = new File(mFile, displayName);
if (target.isDirectory() || target.mkdir()) {
return new RawFile(this, target);
} else {
return null;
}
}
@Override
public Uri getUri() {
return Uri.fromFile(mFile);
}
@Override
public String getName() {
return mFile.getName();
}
@Override
public String getType() {
if (mFile.isDirectory()) {
return null;
} else {
return getTypeForName(mFile.getName());
}
}
@Override
public boolean isDirectory() {
return mFile.isDirectory();
}
@Override
public boolean isFile() {
return mFile.isFile();
}
@Override
public long lastModified() {
return mFile.lastModified();
}
@Override
public long length() {
return mFile.length();
}
@Override
public boolean canRead() {
return mFile.canRead();
}
@Override
public boolean canWrite() {
return mFile.canWrite();
}
@Override
public boolean delete() {
deleteContents(mFile);
return mFile.delete();
}
@Override
public boolean exists() {
return mFile.exists();
}
@Override
public UniFile contains(String displayName) {
final File child = new File(mFile, displayName);
return child.exists() ? new RawFile(this, child) : null;
}
@Override
public UniFile[] listFiles() {
final ArrayList<UniFile> results = new ArrayList<UniFile>();
final File[] files = mFile.listFiles();
if (files != null) {
for (File file : files) {
results.add(new RawFile(this, file));
}
}
return results.toArray(new UniFile[results.size()]);
}
@Override
public boolean renameTo(String displayName) {
final File target = new File(mFile.getParentFile(), displayName);
if (mFile.renameTo(target)) {
mFile = target;
return true;
} else {
return false;
}
}
@Override
public OutputStream openOutputStream() throws IOException {
return new FileOutputStream(mFile);
}
@Override
public OutputStream openOutputStream(boolean append) throws IOException {
return new FileOutputStream(mFile, append);
}
@Override
public InputStream openInputStream() throws IOException {
return new FileInputStream(mFile);
}
private static String getTypeForName(String name) {
final int lastDot = name.lastIndexOf('.');
if (lastDot >= 0) {
final String extension = name.substring(lastDot + 1).toLowerCase();
final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (mime != null) {
return mime;
}
}
return "application/octet-stream";
}
private static boolean deleteContents(File dir) {
File[] files = dir.listFiles();
boolean success = true;
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
success &= deleteContents(file);
}
if (!file.delete()) {
Log.w(TAG, "Failed to delete " + file);
success = false;
}
}
}
return success;
}
}
@@ -1,347 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.unifile;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Representation of a document backed by either a
* {@link android.provider.DocumentsProvider} or a raw file on disk. This is a
* utility class designed to emulate the traditional {@link File} interface. It
* offers a simplified view of a tree of documents, but it has substantial
* overhead. For optimal performance and a richer feature set, use the
* {@link android.provider.DocumentsContract} methods and constants directly.
* <p>
* There are several differences between documents and traditional files:
* <ul>
* <li>Documents express their display name and MIME type as separate fields,
* instead of relying on file extensions. Some documents providers may still
* choose to append extensions to their display names, but that's an
* implementation detail.
* <li>A single document may appear as the child of multiple directories, so it
* doesn't inherently know who its parent is. That is, documents don't have a
* strong notion of path. You can easily traverse a tree of documents from
* parent to child, but not from child to parent.
* <li>Each document has a unique identifier within that provider. This
* identifier is an <em>opaque</em> implementation detail of the provider, and
* as such it must not be parsed.
* </ul>
* <p>
* Before using this class, first consider if you really need access to an
* entire subtree of documents. The principle of least privilege dictates that
* you should only ask for access to documents you really need. If you only need
* the user to pick a single file, use {@link Intent#ACTION_OPEN_DOCUMENT} or
* {@link Intent#ACTION_GET_CONTENT}. If you want to let the user pick multiple
* files, add {@link Intent#EXTRA_ALLOW_MULTIPLE}. If you only need the user to
* save a single file, use {@link Intent#ACTION_CREATE_DOCUMENT}.
* <p>
* If you really do need full access to an entire subtree of documents, start by
* launching {@link Intent#ACTION_OPEN_DOCUMENT_TREE} to let the user pick a
* directory. Then pass the resulting {@link Intent#getData()} into
* {@link #fromTreeUri(Context, Uri)} to start working with the user selected
* tree.
* <p>
* As you navigate the tree of UniFile instances, you can always use
* {@link #getUri()} to obtain the Uri representing the underlying document for
* that object, for use with {@link ContentResolver#openInputStream(Uri)}, etc.
* <p>
* To simplify your code on devices running
* {@link Build.VERSION_CODES#KITKAT} or earlier, you can use
* {@link #fromFile(File)} which emulates the behavior of a
* {@link android.provider.DocumentsProvider}.
*
* @see android.provider.DocumentsProvider
* @see android.provider.DocumentsContract
*/
public abstract class UniFile {
static final String TAG = "UniFile";
private final UniFile mParent;
UniFile(UniFile parent) {
mParent = parent;
}
/**
* Create a {@link UniFile} representing the filesystem tree rooted at
* the given {@link Uri}. This doesn't give you any additional access to the
* underlying files beyond what your app already has.
* <p>
* {@link #getUri()} will return {@code file://} Uris for files explored
* through this tree.
*/
public static UniFile fromFile(File file) {
return new RawFile(null, file);
}
/**
* Create a {@link UniFile} representing the document tree rooted at
* the given {@link Uri}. This is only useful on devices running
* {@link Build.VERSION_CODES#LOLLIPOP} or later, and will return
* {@code null} when called on earlier platform versions.
*
* @param treeUri the {@link Intent#getData()} from a successful
* {@link Intent#ACTION_OPEN_DOCUMENT_TREE} request.
*/
public static UniFile fromTreeUri(Context context, Uri treeUri) {
final int version = Build.VERSION.SDK_INT;
if (version >= 21) {
return new DocumentFile(null, context,
DocumentsContractApi21.prepareTreeUri(treeUri));
} else {
return null;
}
}
/**
* Test if given Uri is backed by a
* {@link android.provider.DocumentsProvider}.
*/
public static boolean isDocumentUri(Context context, Uri uri) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
return DocumentsContractApi19.isDocumentUri(context, uri);
} else {
return false;
}
}
/**
* Create a new document as a direct child of this directory.
*
* @param displayName name of new document, without any file extension
* appended; the underlying provider may choose to append the
* extension
* @return file representing newly created document, or null if failed
* @see android.provider.DocumentsContract#createDocument(ContentResolver,
* Uri, String, String)
*/
public abstract UniFile createFile(String displayName);
/**
* Create a new directory as a direct child of this directory.
*
* @param displayName name of new directory
* @return file representing newly created directory, or null if failed
* @see android.provider.DocumentsContract#createDocument(ContentResolver,
* Uri, String, String)
*/
public abstract UniFile createDirectory(String displayName);
/**
* Return a Uri for the underlying document represented by this file. This
* can be used with other platform APIs to manipulate or share the
* underlying content. You can use {@link #isDocumentUri(Context, Uri)} to
* test if the returned Uri is backed by a
* {@link android.provider.DocumentsProvider}.
*
* @see Intent#setData(Uri)
* @see Intent#setClipData(android.content.ClipData)
* @see ContentResolver#openInputStream(Uri)
* @see ContentResolver#openOutputStream(Uri)
* @see ContentResolver#openFileDescriptor(Uri, String)
*/
public abstract Uri getUri();
/**
* Return the display name of this document.
*
* @see android.provider.DocumentsContract.Document#COLUMN_DISPLAY_NAME
*/
public abstract String getName();
/**
* Return the MIME type of this document.
*
* @see android.provider.DocumentsContract.Document#COLUMN_MIME_TYPE
*/
public abstract String getType();
/**
* Return the parent file of this document. Only defined inside of the
* user-selected tree; you can never escape above the top of the tree.
* <p>
* The underlying {@link android.provider.DocumentsProvider} only defines a
* forward mapping from parent to child, so the reverse mapping of child to
* parent offered here is purely a convenience method, and it may be
* incorrect if the underlying tree structure changes.
*/
public UniFile getParentFile() {
return mParent;
}
/**
* Indicates if this file represents a <em>directory</em>.
*
* @return {@code true} if this file is a directory, {@code false}
* otherwise.
* @see android.provider.DocumentsContract.Document#MIME_TYPE_DIR
*/
public abstract boolean isDirectory();
/**
* Indicates if this file represents a <em>file</em>.
*
* @return {@code true} if this file is a file, {@code false} otherwise.
* @see android.provider.DocumentsContract.Document#COLUMN_MIME_TYPE
*/
public abstract boolean isFile();
/**
* Returns the time when this file was last modified, measured in
* milliseconds since January 1st, 1970, midnight. Returns 0 if the file
* does not exist, or if the modified time is unknown.
*
* @return the time when this file was last modified.
* @see android.provider.DocumentsContract.Document#COLUMN_LAST_MODIFIED
*/
public abstract long lastModified();
/**
* Returns the length of this file in bytes. Returns 0 if the file does not
* exist, or if the length is unknown. The result for a directory is not
* defined.
*
* @return the number of bytes in this file.
* @see android.provider.DocumentsContract.Document#COLUMN_SIZE
*/
public abstract long length();
/**
* Indicates whether the current context is allowed to read from this file.
*
* @return {@code true} if this file can be read, {@code false} otherwise.
*/
public abstract boolean canRead();
/**
* Indicates whether the current context is allowed to write to this file.
*
* @return {@code true} if this file can be written, {@code false}
* otherwise.
* @see android.provider.DocumentsContract.Document#COLUMN_FLAGS
* @see android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE
* @see android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE
* @see android.provider.DocumentsContract.Document#FLAG_DIR_SUPPORTS_CREATE
*/
public abstract boolean canWrite();
/**
* Deletes this file.
* <p>
* Note that this method does <i>not</i> throw {@code IOException} on
* failure. Callers must check the return value.
*
* @return {@code true} if this file was deleted, {@code false} otherwise.
* @see android.provider.DocumentsContract#deleteDocument(ContentResolver,
* Uri)
*/
public abstract boolean delete();
/**
* Returns a boolean indicating whether this file can be found.
*
* @return {@code true} if this file exists, {@code false} otherwise.
*/
public abstract boolean exists();
/**
* Returns the file contained in the directory represented by this
* file.
*
* @return the file, or null if it does not exist.
*/
public abstract UniFile contains(String displayName);
/**
* Returns an array of files contained in the directory represented by this
* file.
*
* @return an array of files or {@code null}.
* @see android.provider.DocumentsContract#buildChildDocumentsUriUsingTree(Uri,
* String)
*/
public abstract UniFile[] listFiles();
/**
* Search through {@link #listFiles()} for the first document matching the
* given display name. Returns {@code null} when no matching document is
* found.
*/
public UniFile findFile(String displayName) {
for (UniFile doc : listFiles()) {
if (displayName.equals(doc.getName())) {
return doc;
}
}
return null;
}
/**
* Renames this file to {@code displayName}.
* <p>
* Note that this method does <i>not</i> throw {@code IOException} on
* failure. Callers must check the return value.
* <p>
* Some providers may need to create a new document to reflect the rename,
* potentially with a different MIME type, so {@link #getUri()} and
* {@link #getType()} may change to reflect the rename.
* <p>
* When renaming a directory, children previously enumerated through
* {@link #listFiles()} may no longer be valid.
*
* @param displayName the new display name.
* @return true on success.
* @see android.provider.DocumentsContract#renameDocument(ContentResolver,
* Uri, String)
*/
public abstract boolean renameTo(String displayName);
/**
* Open a stream on to the content associated with the file, clean it if it exists
*
* @return the {@link OutputStream}
* @throws IOException
*/
public abstract OutputStream openOutputStream() throws IOException;
/**
* Open a stream on to the content associated with the file
*
* @param append {@code true} for do not clean it if it exists
* @return the {@link OutputStream}
* @throws IOException
*/
public abstract OutputStream openOutputStream(boolean append) throws IOException;
/**
* Open a stream on to the content associated with the file
*
* @return the {@link InputStream}
* @throws IOException
*/
public abstract InputStream openInputStream() throws IOException;
}