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

Commit ae9b51bf authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Refactoring of DocumentsContract.

Combines related columns and constants onto the same class so they
are easier to discover.  Move back to surfacing roots with columns
so they are consistent with documents.

Advanced roots are represented with a flag instead of distinct
types.  Flags to indicate supporting of well-known media types,
instead of arbitrary an MIME filter.  Reintroduce well-formed rootId
to support recents.

Always use the expanded version of "documents" in constants, methods,
and argument names.

Refactor DocumentProvider method names to clearly distinguish if
a single item or multiple could be returned, and of which type.  Add
documentation to clearly define which methods have already been
overridden.

Bug: 10567506, 10567557
Change-Id: I981f26ab82f2b520a19aa1ce66f659de50d7fac0
parent aeb16e24
Loading
Loading
Loading
Loading
+47 −44
Original line number Diff line number Diff line
@@ -20781,67 +20781,69 @@ package android.provider {
  }
  public final class DocumentsContract {
    method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String);
    method public static java.lang.String getDocId(android.net.Uri);
    method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildRootsUri(java.lang.String);
    method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
    method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
    method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
    method public static java.lang.String getDocumentId(android.net.Uri);
    method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal);
    method public static android.net.Uri[] getOpenDocuments(android.content.Context);
    method public static java.lang.String getRootId(android.net.Uri);
    method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
    field public static final java.lang.String EXTRA_ERROR = "error";
    field public static final java.lang.String EXTRA_INFO = "info";
    field public static final java.lang.String EXTRA_LOADING = "loading";
  }
  public static abstract interface DocumentsContract.DocumentColumns implements android.provider.OpenableColumns {
    field public static final java.lang.String DOC_ID = "doc_id";
    field public static final java.lang.String FLAGS = "flags";
    field public static final java.lang.String ICON = "icon";
    field public static final java.lang.String LAST_MODIFIED = "last_modified";
    field public static final java.lang.String MIME_TYPE = "mime_type";
    field public static final java.lang.String SUMMARY = "summary";
  }
  public static final class DocumentsContract.DocumentRoot implements android.os.Parcelable {
    ctor public DocumentsContract.DocumentRoot();
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
  public static final class DocumentsContract.Document {
    field public static final java.lang.String COLUMN_DISPLAY_NAME = "_display_name";
    field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
    field public static final java.lang.String COLUMN_FLAGS = "flags";
    field public static final java.lang.String COLUMN_ICON = "icon";
    field public static final java.lang.String COLUMN_LAST_MODIFIED = "last_modified";
    field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
    field public static final java.lang.String COLUMN_SIZE = "_size";
    field public static final java.lang.String COLUMN_SUMMARY = "summary";
    field public static final int FLAG_DIR_PREFERS_GRID = 32; // 0x20
    field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
    field public static final int FLAG_DIR_SUPPORTS_SEARCH = 16; // 0x10
    field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
    field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
    field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
    field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
  }
  public static final class DocumentsContract.Root {
    field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
    field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
    field public static final java.lang.String COLUMN_FLAGS = "flags";
    field public static final java.lang.String COLUMN_ICON = "icon";
    field public static final java.lang.String COLUMN_ROOT_ID = "root_id";
    field public static final java.lang.String COLUMN_ROOT_TYPE = "root_type";
    field public static final java.lang.String COLUMN_SUMMARY = "summary";
    field public static final java.lang.String COLUMN_TITLE = "title";
    field public static final int FLAG_ADVANCED = 4; // 0x4
    field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
    field public static final int FLAG_PROVIDES_AUDIO = 8; // 0x8
    field public static final int FLAG_PROVIDES_IMAGES = 32; // 0x20
    field public static final int FLAG_PROVIDES_VIDEO = 16; // 0x10
    field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
    field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
    field public static final int ROOT_TYPE_DEVICE_ADVANCED = 4; // 0x4
    field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
    field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
    field public long availableBytes;
    field public java.lang.String docId;
    field public int flags;
    field public int icon;
    field public java.lang.String[] mimeTypes;
    field public java.lang.String recentDocId;
    field public int rootType;
    field public java.lang.String summary;
    field public java.lang.String title;
  }
  public static final class DocumentsContract.Documents {
    field public static final int FLAG_PREFERS_GRID = 64; // 0x40
    field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
    field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
    field public static final int FLAG_SUPPORTS_RENAME = 2; // 0x2
    field public static final int FLAG_SUPPORTS_SEARCH = 16; // 0x10
    field public static final int FLAG_SUPPORTS_THUMBNAIL = 8; // 0x8
    field public static final int FLAG_SUPPORTS_WRITE = 32; // 0x20
    field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.doc/dir";
  }
  public abstract class DocumentsProvider extends android.content.ContentProvider {
    ctor public DocumentsProvider();
    method public final android.os.Bundle callFromPackage(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle);
    method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
    method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
    method public abstract java.util.List<android.provider.DocumentsContract.DocumentRoot> getDocumentRoots();
    method public java.lang.String getType(java.lang.String) throws java.io.FileNotFoundException;
    method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
    method public final java.lang.String getType(android.net.Uri);
    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
    method public void notifyDocumentRootsChanged();
    method public abstract android.os.ParcelFileDescriptor openDocument(java.lang.String, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    method public android.content.res.AssetFileDescriptor openDocumentThumbnail(java.lang.String, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
@@ -20849,10 +20851,11 @@ package android.provider {
    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    method public abstract android.database.Cursor queryDocument(java.lang.String) throws java.io.FileNotFoundException;
    method public abstract android.database.Cursor queryDocumentChildren(java.lang.String) throws java.io.FileNotFoundException;
    method public android.database.Cursor querySearch(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
    method public void renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
    method public abstract android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], java.lang.String) throws java.io.FileNotFoundException;
    method public abstract android.database.Cursor queryDocument(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
    method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
    method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
    method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
    method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
  }
+402 −349

File changed.

Preview size limit exceeded, changes collapsed.

+132 −97

File changed.

Preview size limit exceeded, changes collapsed.

+6 −14
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
@@ -28,13 +27,13 @@ import android.content.DialogInterface.OnClickListener;
import android.net.Uri;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Documents;
import android.provider.DocumentsContract.Document;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.android.documentsui.model.Document;
import com.android.documentsui.model.DocumentInfo;

/**
 * Dialog to create a new directory.
@@ -67,24 +66,17 @@ public class CreateDirectoryFragment extends DialogFragment {
                final String displayName = text1.getText().toString();

                final DocumentsActivity activity = (DocumentsActivity) getActivity();
                final Document cwd = activity.getCurrentDirectory();
                final DocumentInfo cwd = activity.getCurrentDirectory();

                final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
                        cwd.uri.getAuthority());
                try {
                    final String docId = DocumentsContract.createDocument(client,
                            DocumentsContract.getDocId(cwd.uri), Documents.MIME_TYPE_DIR,
                            displayName);
                    final Uri childUri = DocumentsContract.createDocument(
                            resolver, cwd.uri, Document.MIME_TYPE_DIR, displayName);

                    // Navigate into newly created child
                    final Uri childUri = DocumentsContract.buildDocumentUri(
                            cwd.uri.getAuthority(), docId);
                    final Document childDoc = Document.fromUri(resolver, childUri);
                    final DocumentInfo childDoc = DocumentInfo.fromUri(resolver, childUri);
                    activity.onDocumentPicked(childDoc);
                } catch (Exception e) {
                    Toast.makeText(context, R.string.save_error, Toast.LENGTH_SHORT).show();
                } finally {
                    ContentProviderClient.closeQuietly(client);
                }
            }
        });
+24 −24
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ import android.widget.TextView;
import android.widget.Toast;

import com.android.documentsui.DocumentsActivity.DisplayState;
import com.android.documentsui.model.Document;
import com.android.documentsui.model.DocumentInfo;
import com.android.internal.util.Predicate;
import com.google.android.collect.Lists;

@@ -81,7 +81,7 @@ public class DirectoryFragment extends Fragment {

    private AbsListView mCurrentView;

    private Predicate<Document> mFilter;
    private Predicate<DocumentInfo> mFilter;

    public static final int TYPE_NORMAL = 1;
    public static final int TYPE_SEARCH = 2;
@@ -106,8 +106,8 @@ public class DirectoryFragment extends Fragment {
    }

    public static void showSearch(FragmentManager fm, Uri uri, String query) {
        final Uri searchUri = DocumentsContract.buildSearchUri(
                uri.getAuthority(), DocumentsContract.getDocId(uri), query);
        final Uri searchUri = DocumentsContract.buildSearchDocumentsUri(
                uri.getAuthority(), DocumentsContract.getDocumentId(uri), query);
        show(fm, TYPE_SEARCH, searchUri);
    }

@@ -163,21 +163,21 @@ public class DirectoryFragment extends Fragment {

                Uri contentsUri;
                if (mType == TYPE_NORMAL) {
                    contentsUri = DocumentsContract.buildChildrenUri(
                            uri.getAuthority(), DocumentsContract.getDocId(uri));
                    contentsUri = DocumentsContract.buildChildDocumentsUri(
                            uri.getAuthority(), DocumentsContract.getDocumentId(uri));
                } else if (mType == TYPE_RECENT_OPEN) {
                    contentsUri = RecentsProvider.buildRecentOpen();
                } else {
                    contentsUri = uri;
                }

                final Comparator<Document> sortOrder;
                final Comparator<DocumentInfo> sortOrder;
                if (state.sortOrder == SORT_ORDER_LAST_MODIFIED || mType == TYPE_RECENT_OPEN) {
                    sortOrder = new Document.LastModifiedComparator();
                    sortOrder = new DocumentInfo.LastModifiedComparator();
                } else if (state.sortOrder == SORT_ORDER_DISPLAY_NAME) {
                    sortOrder = new Document.DisplayNameComparator();
                    sortOrder = new DocumentInfo.DisplayNameComparator();
                } else if (state.sortOrder == SORT_ORDER_SIZE) {
                    sortOrder = new Document.SizeComparator();
                    sortOrder = new DocumentInfo.SizeComparator();
                } else {
                    throw new IllegalArgumentException("Unknown sort order " + state.sortOrder);
                }
@@ -258,7 +258,7 @@ public class DirectoryFragment extends Fragment {
    private OnItemClickListener mItemListener = new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            final Document doc = mAdapter.getItem(position);
            final DocumentInfo doc = mAdapter.getItem(position);
            if (mFilter.apply(doc)) {
                ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
            }
@@ -291,11 +291,11 @@ public class DirectoryFragment extends Fragment {
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
            final ArrayList<Document> docs = Lists.newArrayList();
            final ArrayList<DocumentInfo> docs = Lists.newArrayList();
            final int size = checked.size();
            for (int i = 0; i < size; i++) {
                if (checked.valueAt(i)) {
                    final Document doc = mAdapter.getItem(checked.keyAt(i));
                    final DocumentInfo doc = mAdapter.getItem(checked.keyAt(i));
                    docs.add(doc);
                }
            }
@@ -328,7 +328,7 @@ public class DirectoryFragment extends Fragment {
                ActionMode mode, int position, long id, boolean checked) {
            if (checked) {
                // Directories cannot be checked
                final Document doc = mAdapter.getItem(position);
                final DocumentInfo doc = mAdapter.getItem(position);
                if (doc.isDirectory()) {
                    mCurrentView.setItemChecked(position, false);
                }
@@ -339,9 +339,9 @@ public class DirectoryFragment extends Fragment {
        }
    };

    private void onShareDocuments(List<Document> docs) {
    private void onShareDocuments(List<DocumentInfo> docs) {
        final ArrayList<Uri> uris = Lists.newArrayList();
        for (Document doc : docs) {
        for (DocumentInfo doc : docs) {
            uris.add(doc.uri);
        }

@@ -363,12 +363,12 @@ public class DirectoryFragment extends Fragment {
        startActivity(intent);
    }

    private void onDeleteDocuments(List<Document> docs) {
    private void onDeleteDocuments(List<DocumentInfo> docs) {
        final Context context = getActivity();
        final ContentResolver resolver = context.getContentResolver();

        boolean hadTrouble = false;
        for (Document doc : docs) {
        for (DocumentInfo doc : docs) {
            if (!doc.isDeleteSupported()) {
                Log.w(TAG, "Skipping " + doc);
                hadTrouble = true;
@@ -396,12 +396,12 @@ public class DirectoryFragment extends Fragment {
    }

    private class DocumentsAdapter extends BaseAdapter {
        private List<Document> mDocuments;
        private List<DocumentInfo> mDocuments;

        public DocumentsAdapter() {
        }

        public void swapDocuments(List<Document> documents) {
        public void swapDocuments(List<DocumentInfo> documents) {
            mDocuments = documents;

            if (mDocuments != null && mDocuments.isEmpty()) {
@@ -433,7 +433,7 @@ public class DirectoryFragment extends Fragment {
                }
            }

            final Document doc = getItem(position);
            final DocumentInfo doc = getItem(position);

            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
@@ -507,7 +507,7 @@ public class DirectoryFragment extends Fragment {
        }

        @Override
        public Document getItem(int position) {
        public DocumentInfo getItem(int position) {
            return mDocuments.get(position);
        }

@@ -538,8 +538,8 @@ public class DirectoryFragment extends Fragment {

            Bitmap result = null;
            try {
                result = DocumentsContract.getThumbnail(
                        context.getContentResolver(), uri, mThumbSize);
                result = DocumentsContract.getDocumentThumbnail(
                        context.getContentResolver(), uri, mThumbSize, null);
                if (result != null) {
                    final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
                            context, mThumbSize);
Loading