15fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey/*
25fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * Copyright (C) 2014 The Android Open Source Project
35fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey *
45fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
55fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * you may not use this file except in compliance with the License.
65fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * You may obtain a copy of the License at
75fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey *
85fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
95fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey *
105fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
115fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
125fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * See the License for the specific language governing permissions and
145fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * limitations under the License.
155fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey */
165fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
175fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeypackage android.support.v4.provider;
185fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
195fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.content.ContentResolver;
205fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.content.Context;
215fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.content.Intent;
225fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.net.Uri;
235fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.os.Build;
24e688455e4ae168245a812dff792bad2fbe16f120Aurimas Liutikasimport android.provider.DocumentsContract;
255fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
265fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport java.io.File;
275fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
285fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey/**
295fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * Representation of a document backed by either a
305fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * {@link android.provider.DocumentsProvider} or a raw file on disk. This is a
315fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * utility class designed to emulate the traditional {@link File} interface. It
325fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * offers a simplified view of a tree of documents, but it has substantial
335fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * overhead. For optimal performance and a richer feature set, use the
345fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * {@link android.provider.DocumentsContract} methods and constants directly.
355fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * <p>
365fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * There are several differences between documents and traditional files:
375fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * <ul>
385fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * <li>Documents express their display name and MIME type as separate fields,
395fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * instead of relying on file extensions. Some documents providers may still
405fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * choose to append extensions to their display names, but that's an
415fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * implementation detail.
425fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * <li>A single document may appear as the child of multiple directories, so it
435fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * doesn't inherently know who its parent is. That is, documents don't have a
445fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * strong notion of path. You can easily traverse a tree of documents from
455fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * parent to child, but not from child to parent.
465fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * <li>Each document has a unique identifier within that provider. This
475fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * identifier is an <em>opaque</em> implementation detail of the provider, and
485fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * as such it must not be parsed.
495fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * </ul>
505fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * <p>
515fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * Before using this class, first consider if you really need access to an
525fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * entire subtree of documents. The principle of least privilege dictates that
535fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * you should only ask for access to documents you really need. If you only need
545fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * the user to pick a single file, use {@link Intent#ACTION_OPEN_DOCUMENT} or
555fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * {@link Intent#ACTION_GET_CONTENT}. If you want to let the user pick multiple
565fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * files, add {@link Intent#EXTRA_ALLOW_MULTIPLE}. If you only need the user to
575fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * save a single file, use {@link Intent#ACTION_CREATE_DOCUMENT}. If you use
585fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * these APIs, you can pass the resulting {@link Intent#getData()} into
595fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * {@link #fromSingleUri(Context, Uri)} to work with that document.
605fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * <p>
615fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * If you really do need full access to an entire subtree of documents, start by
625fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * launching {@link Intent#ACTION_OPEN_DOCUMENT_TREE} to let the user pick a
635fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * directory. Then pass the resulting {@link Intent#getData()} into
645fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * {@link #fromTreeUri(Context, Uri)} to start working with the user selected
655fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * tree.
665fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * <p>
675fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * As you navigate the tree of DocumentFile instances, you can always use
685fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * {@link #getUri()} to obtain the Uri representing the underlying document for
695fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * that object, for use with {@link ContentResolver#openInputStream(Uri)}, etc.
705fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * <p>
715fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * To simplify your code on devices running
725fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * {@link android.os.Build.VERSION_CODES#KITKAT} or earlier, you can use
735fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * {@link #fromFile(File)} which emulates the behavior of a
745fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * {@link android.provider.DocumentsProvider}.
755fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey *
765fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * @see android.provider.DocumentsProvider
775fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * @see android.provider.DocumentsContract
785fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey */
795fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeypublic abstract class DocumentFile {
805fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    static final String TAG = "DocumentFile";
815fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
825fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private final DocumentFile mParent;
835fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
845fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    DocumentFile(DocumentFile parent) {
855fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        mParent = parent;
865fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
875fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
885fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
895fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Create a {@link DocumentFile} representing the filesystem tree rooted at
908b977168147ee1135c39de1ac3c1b45aa83376c8Jeff Sharkey     * the given {@link File}. This doesn't give you any additional access to the
915fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * underlying files beyond what your app already has.
925fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * <p>
935fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * {@link #getUri()} will return {@code file://} Uris for files explored
945fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * through this tree.
955fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
965fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public static DocumentFile fromFile(File file) {
975fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        return new RawDocumentFile(null, file);
985fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
995fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1005fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
1015fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Create a {@link DocumentFile} representing the single document at the
1025fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * given {@link Uri}. This is only useful on devices running
1035fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * {@link android.os.Build.VERSION_CODES#KITKAT} or later, and will return
1045fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * {@code null} when called on earlier platform versions.
1055fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
1065fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @param singleUri the {@link Intent#getData()} from a successful
1075fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *            {@link Intent#ACTION_OPEN_DOCUMENT} or
1085fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *            {@link Intent#ACTION_CREATE_DOCUMENT} request.
1095fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
1105fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public static DocumentFile fromSingleUri(Context context, Uri singleUri) {
111c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette        if (Build.VERSION.SDK_INT >= 19) {
1125fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            return new SingleDocumentFile(null, context, singleUri);
1135fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        } else {
1145fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            return null;
1155fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        }
1165fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
1175fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1185fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
1195fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Create a {@link DocumentFile} representing the document tree rooted at
1205fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * the given {@link Uri}. This is only useful on devices running
12195a62c18174e92eb2bf90b808cef5fd6f36ad944Dianne Hackborn     * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or later, and will return
1225fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * {@code null} when called on earlier platform versions.
1235fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
1245fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @param treeUri the {@link Intent#getData()} from a successful
1255fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *            {@link Intent#ACTION_OPEN_DOCUMENT_TREE} request.
1265fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
1275fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public static DocumentFile fromTreeUri(Context context, Uri treeUri) {
128c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette        if (Build.VERSION.SDK_INT >= 21) {
1295fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            return new TreeDocumentFile(null, context,
130e688455e4ae168245a812dff792bad2fbe16f120Aurimas Liutikas                    DocumentsContract.buildDocumentUriUsingTree(treeUri,
131e688455e4ae168245a812dff792bad2fbe16f120Aurimas Liutikas                            DocumentsContract.getTreeDocumentId(treeUri)));
1325fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        } else {
1335fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            return null;
1345fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        }
1355fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
1365fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1375fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
1385fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Test if given Uri is backed by a
1395fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * {@link android.provider.DocumentsProvider}.
1405fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
1415fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public static boolean isDocumentUri(Context context, Uri uri) {
142c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette        if (Build.VERSION.SDK_INT >= 19) {
1435fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            return DocumentsContractApi19.isDocumentUri(context, uri);
1445fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        } else {
1455fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            return false;
1465fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        }
1475fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
1485fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1495fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
1505fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Create a new document as a direct child of this directory.
1515fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
1525fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @param mimeType MIME type of new document, such as {@code image/png} or
1535fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *            {@code audio/flac}
1545fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @param displayName name of new document, without any file extension
1555fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *            appended; the underlying provider may choose to append the
1565fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *            extension
1575fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return file representing newly created document, or null if failed
1585fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @throws UnsupportedOperationException when working with a single document
1595fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *             created from {@link #fromSingleUri(Context, Uri)}.
1605fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract#createDocument(ContentResolver,
1615fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *      Uri, String, String)
1625fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
1635fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract DocumentFile createFile(String mimeType, String displayName);
1645fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1655fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
1665fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Create a new directory as a direct child of this directory.
1675fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
1685fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @param displayName name of new directory
1695fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return file representing newly created directory, or null if failed
1705fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @throws UnsupportedOperationException when working with a single document
1715fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *             created from {@link #fromSingleUri(Context, Uri)}.
1725fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract#createDocument(ContentResolver,
1735fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *      Uri, String, String)
1745fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
1755fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract DocumentFile createDirectory(String displayName);
1765fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1775fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
1785fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Return a Uri for the underlying document represented by this file. This
1795fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * can be used with other platform APIs to manipulate or share the
1805fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * underlying content. You can use {@link #isDocumentUri(Context, Uri)} to
1815fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * test if the returned Uri is backed by a
1825fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * {@link android.provider.DocumentsProvider}.
1835fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
1845fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see Intent#setData(Uri)
1855fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see Intent#setClipData(android.content.ClipData)
1865fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see ContentResolver#openInputStream(Uri)
1875fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see ContentResolver#openOutputStream(Uri)
1885fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see ContentResolver#openFileDescriptor(Uri, String)
1895fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
1905fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract Uri getUri();
1915fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1925fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
1935fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Return the display name of this document.
1945fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
1955fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#COLUMN_DISPLAY_NAME
1965fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
1975fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract String getName();
1985fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1995fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
2005fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Return the MIME type of this document.
2015fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
2025fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#COLUMN_MIME_TYPE
2035fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
2045fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract String getType();
2055fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2065fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
2075fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Return the parent file of this document. Only defined inside of the
2085fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * user-selected tree; you can never escape above the top of the tree.
2095fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * <p>
2105fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * The underlying {@link android.provider.DocumentsProvider} only defines a
2115fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * forward mapping from parent to child, so the reverse mapping of child to
2125fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * parent offered here is purely a convenience method, and it may be
2135fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * incorrect if the underlying tree structure changes.
2145fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
2155fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public DocumentFile getParentFile() {
2165fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        return mParent;
2175fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
2185fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2195fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
2205fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Indicates if this file represents a <em>directory</em>.
2215fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
2225fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return {@code true} if this file is a directory, {@code false}
2235fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *         otherwise.
2245fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#MIME_TYPE_DIR
2255fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
2265fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract boolean isDirectory();
2275fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2285fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
2295fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Indicates if this file represents a <em>file</em>.
2305fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
2315fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return {@code true} if this file is a file, {@code false} otherwise.
2325fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#COLUMN_MIME_TYPE
2335fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
2345fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract boolean isFile();
2355fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2365fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
23726f311a9b57b9551ad58d6b7f9a571bebcebf0dcTomasz Mikolajewski     * Indicates if this file represents a <em>virtual</em> document.
23826f311a9b57b9551ad58d6b7f9a571bebcebf0dcTomasz Mikolajewski     *
23926f311a9b57b9551ad58d6b7f9a571bebcebf0dcTomasz Mikolajewski     * @return {@code true} if this file is a virtual document.
24026f311a9b57b9551ad58d6b7f9a571bebcebf0dcTomasz Mikolajewski     * @see android.provider.DocumentsContract.Document#FLAG_VIRTUAL_DOCUMENT
24126f311a9b57b9551ad58d6b7f9a571bebcebf0dcTomasz Mikolajewski     */
24226f311a9b57b9551ad58d6b7f9a571bebcebf0dcTomasz Mikolajewski    public abstract boolean isVirtual();
24326f311a9b57b9551ad58d6b7f9a571bebcebf0dcTomasz Mikolajewski
24426f311a9b57b9551ad58d6b7f9a571bebcebf0dcTomasz Mikolajewski    /**
2455fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Returns the time when this file was last modified, measured in
2465fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * milliseconds since January 1st, 1970, midnight. Returns 0 if the file
2475fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * does not exist, or if the modified time is unknown.
2485fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
2495fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return the time when this file was last modified.
2505fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#COLUMN_LAST_MODIFIED
2515fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
2525fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract long lastModified();
2535fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2545fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
2555fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Returns the length of this file in bytes. Returns 0 if the file does not
2565fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * exist, or if the length is unknown. The result for a directory is not
2575fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * defined.
2585fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
2595fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return the number of bytes in this file.
2605fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#COLUMN_SIZE
2615fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
2625fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract long length();
2635fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2645fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
2655fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Indicates whether the current context is allowed to read from this file.
2665fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
2675fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return {@code true} if this file can be read, {@code false} otherwise.
2685fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
2695fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract boolean canRead();
2705fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2715fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
2725fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Indicates whether the current context is allowed to write to this file.
2735fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
2745fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return {@code true} if this file can be written, {@code false}
2755fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *         otherwise.
2765fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#COLUMN_FLAGS
2775fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE
2785fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE
2795fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract.Document#FLAG_DIR_SUPPORTS_CREATE
2805fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
2815fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract boolean canWrite();
2825fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2835fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
2845fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Deletes this file.
2855fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * <p>
2865fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Note that this method does <i>not</i> throw {@code IOException} on
2875fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * failure. Callers must check the return value.
2885fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
2895fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return {@code true} if this file was deleted, {@code false} otherwise.
2905fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract#deleteDocument(ContentResolver,
2915fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *      Uri)
2925fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
2935fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract boolean delete();
2945fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2955fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
2965fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Returns a boolean indicating whether this file can be found.
2975fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
2985fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return {@code true} if this file exists, {@code false} otherwise.
2995fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
3005fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract boolean exists();
3015fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3025fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
3035fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Returns an array of files contained in the directory represented by this
3045fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * file.
3055fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
3065fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return an array of files or {@code null}.
3075fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @throws UnsupportedOperationException when working with a single document
3085fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *             created from {@link #fromSingleUri(Context, Uri)}.
3095fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract#buildChildDocumentsUriUsingTree(Uri,
3105fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *      String)
3115fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
3125fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract DocumentFile[] listFiles();
3135fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3145fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
3155fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Search through {@link #listFiles()} for the first document matching the
3165fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * given display name. Returns {@code null} when no matching document is
3175fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * found.
3185fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
3195fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @throws UnsupportedOperationException when working with a single document
3205fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *             created from {@link #fromSingleUri(Context, Uri)}.
3215fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
3225fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public DocumentFile findFile(String displayName) {
3235fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        for (DocumentFile doc : listFiles()) {
3245fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            if (displayName.equals(doc.getName())) {
3255fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                return doc;
3265fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            }
3275fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        }
3285fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        return null;
3295fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
3305fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3315fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    /**
3325fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Renames this file to {@code displayName}.
3335fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * <p>
3345fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Note that this method does <i>not</i> throw {@code IOException} on
3355fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * failure. Callers must check the return value.
3365fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * <p>
3375fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * Some providers may need to create a new document to reflect the rename,
3385fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * potentially with a different MIME type, so {@link #getUri()} and
3395fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * {@link #getType()} may change to reflect the rename.
3405fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * <p>
3415fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * When renaming a directory, children previously enumerated through
3425fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * {@link #listFiles()} may no longer be valid.
3435fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *
3445fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @param displayName the new display name.
3455fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @return true on success.
3465fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @throws UnsupportedOperationException when working with a single document
3475fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *             created from {@link #fromSingleUri(Context, Uri)}.
3485fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     * @see android.provider.DocumentsContract#renameDocument(ContentResolver,
3495fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     *      Uri, String)
3505fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey     */
3515fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public abstract boolean renameTo(String displayName);
3525fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey}
353