summaryrefslogtreecommitdiffstats
path: root/packages/DocumentsUI/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/DocumentsUI/src')
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java29
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java59
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java18
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentChangedReceiver.java5
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java65
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java118
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java45
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/Document.java21
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java17
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DocumentsProviderInfo.java121
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/Root.java123
13 files changed, 170 insertions, 461 deletions
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index 575947f..6bc554f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -20,14 +20,14 @@ 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.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.net.Uri;
import android.os.Bundle;
-import android.provider.DocumentsContract.DocumentColumns;
+import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Documents;
import android.view.LayoutInflater;
import android.view.View;
@@ -36,8 +36,6 @@ import android.widget.Toast;
import com.android.documentsui.model.Document;
-import java.io.FileNotFoundException;
-
/**
* Dialog to create a new directory.
*/
@@ -58,7 +56,7 @@ public class CreateDirectoryFragment extends DialogFragment {
final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
final View view = dialogInflater.inflate(R.layout.dialog_create_dir, null, false);
- final EditText text1 = (EditText)view.findViewById(android.R.id.text1);
+ final EditText text1 = (EditText) view.findViewById(android.R.id.text1);
builder.setTitle(R.string.menu_create_dir);
builder.setView(view);
@@ -68,24 +66,25 @@ public class CreateDirectoryFragment extends DialogFragment {
public void onClick(DialogInterface dialog, int which) {
final String displayName = text1.getText().toString();
- final ContentValues values = new ContentValues();
- values.put(DocumentColumns.MIME_TYPE, Documents.MIME_TYPE_DIR);
- values.put(DocumentColumns.DISPLAY_NAME, displayName);
-
final DocumentsActivity activity = (DocumentsActivity) getActivity();
final Document cwd = activity.getCurrentDirectory();
- Uri childUri = resolver.insert(cwd.uri, values);
+ final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+ cwd.uri.getAuthority());
try {
+ final String docId = DocumentsContract.createDocument(client,
+ DocumentsContract.getDocId(cwd.uri), Documents.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);
activity.onDocumentPicked(childDoc);
- } catch (FileNotFoundException e) {
- childUri = null;
- }
-
- if (childUri == null) {
+ } catch (Exception e) {
Toast.makeText(context, R.string.save_error, Toast.LENGTH_SHORT).show();
+ } finally {
+ ContentProviderClient.closeQuietly(client);
}
}
});
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index dd9aee5..783b6ff 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -20,8 +20,8 @@ import static com.android.documentsui.DocumentsActivity.TAG;
import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE;
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID;
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST;
-import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DATE;
-import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_NAME;
+import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_LAST_MODIFIED;
import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_SIZE;
import android.app.Fragment;
@@ -32,7 +32,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
-import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.net.Uri;
@@ -55,7 +54,6 @@ import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
-import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ListView;
@@ -64,7 +62,6 @@ import android.widget.Toast;
import com.android.documentsui.DocumentsActivity.DisplayState;
import com.android.documentsui.model.Document;
-import com.android.documentsui.model.Root;
import com.android.internal.util.Predicate;
import com.google.android.collect.Lists;
@@ -81,7 +78,6 @@ public class DirectoryFragment extends Fragment {
private View mEmptyView;
private ListView mListView;
private GridView mGridView;
- private Button mMoreView;
private AbsListView mCurrentView;
@@ -110,7 +106,8 @@ public class DirectoryFragment extends Fragment {
}
public static void showSearch(FragmentManager fm, Uri uri, String query) {
- final Uri searchUri = DocumentsContract.buildSearchUri(uri, query);
+ final Uri searchUri = DocumentsContract.buildSearchUri(
+ uri.getAuthority(), DocumentsContract.getDocId(uri), query);
show(fm, TYPE_SEARCH, searchUri);
}
@@ -153,8 +150,6 @@ public class DirectoryFragment extends Fragment {
mGridView.setOnItemClickListener(mItemListener);
mGridView.setMultiChoiceModeListener(mMultiListener);
- mMoreView = (Button) view.findViewById(R.id.more);
-
mAdapter = new DocumentsAdapter();
final Uri uri = getArguments().getParcelable(EXTRA_URI);
@@ -168,22 +163,19 @@ public class DirectoryFragment extends Fragment {
Uri contentsUri;
if (mType == TYPE_NORMAL) {
- contentsUri = DocumentsContract.buildContentsUri(uri);
+ contentsUri = DocumentsContract.buildChildrenUri(
+ uri.getAuthority(), DocumentsContract.getDocId(uri));
} else if (mType == TYPE_RECENT_OPEN) {
contentsUri = RecentsProvider.buildRecentOpen();
} else {
contentsUri = uri;
}
- if (state.localOnly) {
- contentsUri = DocumentsContract.setLocalOnly(contentsUri);
- }
-
final Comparator<Document> sortOrder;
- if (state.sortOrder == SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
- sortOrder = new Document.DateComparator();
- } else if (state.sortOrder == SORT_ORDER_NAME) {
- sortOrder = new Document.NameComparator();
+ if (state.sortOrder == SORT_ORDER_LAST_MODIFIED || mType == TYPE_RECENT_OPEN) {
+ sortOrder = new Document.LastModifiedComparator();
+ } else if (state.sortOrder == SORT_ORDER_DISPLAY_NAME) {
+ sortOrder = new Document.DisplayNameComparator();
} else if (state.sortOrder == SORT_ORDER_SIZE) {
sortOrder = new Document.SizeComparator();
} else {
@@ -196,28 +188,6 @@ public class DirectoryFragment extends Fragment {
@Override
public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
mAdapter.swapDocuments(result.contents);
-
- final Cursor cursor = result.cursor;
- if (cursor != null && cursor.getExtras()
- .getBoolean(DocumentsContract.EXTRA_HAS_MORE, false)) {
- mMoreView.setText(R.string.more);
- mMoreView.setVisibility(View.VISIBLE);
- mMoreView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mMoreView.setText(R.string.loading);
- final Bundle bundle = new Bundle();
- bundle.putBoolean(DocumentsContract.EXTRA_REQUEST_MORE, true);
- try {
- cursor.respond(bundle);
- } catch (Exception e) {
- Log.w(TAG, "Failed to respond: " + e);
- }
- }
- });
- } else {
- mMoreView.setVisibility(View.GONE);
- }
}
@Override
@@ -489,8 +459,7 @@ public class DirectoryFragment extends Fragment {
task.execute(doc.uri);
}
} else {
- icon.setImageDrawable(roots.resolveDocumentIcon(
- context, doc.uri.getAuthority(), doc.mimeType));
+ icon.setImageDrawable(RootsCache.resolveDocumentIcon(context, doc.mimeType));
}
title.setText(doc.displayName);
@@ -504,11 +473,7 @@ public class DirectoryFragment extends Fragment {
summary.setVisibility(View.INVISIBLE);
}
} else if (mType == TYPE_RECENT_OPEN) {
- final Root root = roots.findRoot(doc);
- icon1.setVisibility(View.VISIBLE);
- icon1.setImageDrawable(root.icon);
- summary.setText(root.getDirectoryString());
- summary.setVisibility(View.VISIBLE);
+ // TODO: resolve storage root
}
if (summaryGrid != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 14d6fd5..4ce5ef8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -26,7 +26,6 @@ import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.CancellationSignal;
-import android.provider.DocumentsContract.DocumentColumns;
import android.util.Log;
import com.android.documentsui.model.Document;
@@ -77,9 +76,10 @@ public class DirectoryLoader extends UriDerivativeLoader<Uri, DirectoryResult> {
}
private void loadInBackgroundInternal(
- DirectoryResult result, Uri uri, CancellationSignal signal) {
+ DirectoryResult result, Uri uri, CancellationSignal signal) throws RuntimeException {
+ // TODO: switch to using unstable CPC
final ContentResolver resolver = getContext().getContentResolver();
- final Cursor cursor = resolver.query(uri, null, null, null, getQuerySortOrder(), signal);
+ final Cursor cursor = resolver.query(uri, null, null, null, null, signal);
result.cursor = cursor;
result.cursor.registerContentObserver(mObserver);
@@ -110,16 +110,4 @@ public class DirectoryLoader extends UriDerivativeLoader<Uri, DirectoryResult> {
Collections.sort(result.contents, mSortOrder);
}
}
-
- private String getQuerySortOrder() {
- if (mSortOrder instanceof Document.DateComparator) {
- return DocumentColumns.LAST_MODIFIED + " DESC";
- } else if (mSortOrder instanceof Document.NameComparator) {
- return DocumentColumns.DISPLAY_NAME + " ASC";
- } else if (mSortOrder instanceof Document.SizeComparator) {
- return DocumentColumns.SIZE + " DESC";
- } else {
- return null;
- }
- }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentChangedReceiver.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentChangedReceiver.java
index 72afd9e..0ce5968 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentChangedReceiver.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentChangedReceiver.java
@@ -21,12 +21,11 @@ import static com.android.documentsui.DocumentsActivity.TAG;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.provider.DocumentsContract.DocumentRoot;
import android.util.Log;
-import com.android.documentsui.model.Root;
-
/**
- * Handles {@link Root} changes which invalidate cached data.
+ * Handles {@link DocumentRoot} changes which invalidate cached data.
*/
public class DocumentChangedReceiver extends BroadcastReceiver {
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 22e3b98..73ca8fa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -22,7 +22,7 @@ import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANA
import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_OPEN;
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID;
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST;
-import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DATE;
+import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_LAST_MODIFIED;
import android.app.ActionBar;
import android.app.ActionBar.OnNavigationListener;
@@ -32,6 +32,7 @@ import android.app.FragmentManager;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ComponentName;
+import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
@@ -41,7 +42,7 @@ import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.DocumentColumns;
+import android.provider.DocumentsContract.DocumentRoot;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
@@ -61,7 +62,6 @@ import android.widget.Toast;
import com.android.documentsui.model.Document;
import com.android.documentsui.model.DocumentStack;
-import com.android.documentsui.model.Root;
import java.io.FileNotFoundException;
import java.util.Arrays;
@@ -101,7 +101,7 @@ public class DocumentsActivity extends Activity {
mAction = ACTION_CREATE;
} else if (Intent.ACTION_GET_CONTENT.equals(action)) {
mAction = ACTION_GET_CONTENT;
- } else if (Intent.ACTION_MANAGE_DOCUMENT.equals(action)) {
+ } else if (DocumentsContract.ACTION_MANAGE_DOCUMENTS.equals(action)) {
mAction = ACTION_MANAGE;
}
@@ -143,7 +143,7 @@ public class DocumentsActivity extends Activity {
}
if (mAction == ACTION_MANAGE) {
- mDisplayState.sortOrder = SORT_ORDER_DATE;
+ mDisplayState.sortOrder = SORT_ORDER_LAST_MODIFIED;
}
mRootsContainer = findViewById(R.id.container_roots);
@@ -160,10 +160,7 @@ public class DocumentsActivity extends Activity {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
final Uri rootUri = intent.getData();
- final String authority = rootUri.getAuthority();
- final String rootId = DocumentsContract.getRootId(rootUri);
-
- final Root root = mRoots.findRoot(authority, rootId);
+ final DocumentRoot root = mRoots.findRoot(rootUri);
if (root != null) {
onRootPicked(root, true);
} else {
@@ -255,10 +252,10 @@ public class DocumentsActivity extends Activity {
mDrawerToggle.setDrawerIndicatorEnabled(true);
} else {
- final Root root = getCurrentRoot();
- actionBar.setIcon(root != null ? root.icon : null);
+ final DocumentRoot root = getCurrentRoot();
+ actionBar.setIcon(root != null ? root.loadIcon(this) : null);
- if (root.isRecents) {
+ if (mRoots.isRecentsRoot(root)) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setTitle(root.title);
} else {
@@ -441,9 +438,8 @@ public class DocumentsActivity extends Activity {
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
- final Document cwd = getCurrentDirectory();
- if (cwd != null) {
- title.setText(cwd.displayName);
+ if (mStack.size() > 0) {
+ title.setText(mStack.getTitle(mRoots));
} else {
// No directory means recents
title.setText(R.string.root_recent);
@@ -477,10 +473,9 @@ public class DocumentsActivity extends Activity {
}
};
- public Root getCurrentRoot() {
- final Document cwd = getCurrentDirectory();
- if (cwd != null) {
- return mRoots.findRoot(cwd);
+ public DocumentRoot getCurrentRoot() {
+ if (mStack.size() > 0) {
+ return mStack.getRoot(mRoots);
} else {
return mRoots.getRecentsRoot();
}
@@ -538,13 +533,14 @@ public class DocumentsActivity extends Activity {
onCurrentDirectoryChanged();
}
- public void onRootPicked(Root root, boolean closeDrawer) {
+ public void onRootPicked(DocumentRoot root, boolean closeDrawer) {
// Clear entire backstack and start in new root
mStack.clear();
- if (!root.isRecents) {
+ if (!mRoots.isRecentsRoot(root)) {
try {
- onDocumentPicked(Document.fromRoot(getContentResolver(), root));
+ final Uri uri = DocumentsContract.buildDocumentUri(root.authority, root.docId);
+ onDocumentPicked(Document.fromUri(getContentResolver(), uri));
} catch (FileNotFoundException e) {
}
} else {
@@ -611,16 +607,21 @@ public class DocumentsActivity extends Activity {
}
public void onSaveRequested(String mimeType, String displayName) {
- final ContentValues values = new ContentValues();
- values.put(DocumentColumns.MIME_TYPE, mimeType);
- values.put(DocumentColumns.DISPLAY_NAME, displayName);
-
final Document cwd = getCurrentDirectory();
- final Uri childUri = getContentResolver().insert(cwd.uri, values);
- if (childUri != null) {
+ final String authority = cwd.uri.getAuthority();
+
+ final ContentProviderClient client = getContentResolver()
+ .acquireUnstableContentProviderClient(authority);
+ try {
+ final String docId = DocumentsContract.createDocument(client,
+ DocumentsContract.getDocId(cwd.uri), mimeType, displayName);
+
+ final Uri childUri = DocumentsContract.buildDocumentUri(authority, docId);
onFinished(childUri);
- } else {
+ } catch (Exception e) {
Toast.makeText(this, R.string.save_error, Toast.LENGTH_SHORT).show();
+ } finally {
+ ContentProviderClient.closeQuietly(client);
}
}
@@ -680,7 +681,7 @@ public class DocumentsActivity extends Activity {
public int action;
public int mode = MODE_LIST;
public String[] acceptMimes;
- public int sortOrder = SORT_ORDER_NAME;
+ public int sortOrder = SORT_ORDER_DISPLAY_NAME;
public boolean allowMultiple = false;
public boolean showSize = false;
public boolean localOnly = false;
@@ -693,8 +694,8 @@ public class DocumentsActivity extends Activity {
public static final int MODE_LIST = 0;
public static final int MODE_GRID = 1;
- public static final int SORT_ORDER_NAME = 0;
- public static final int SORT_ORDER_DATE = 1;
+ public static final int SORT_ORDER_DISPLAY_NAME = 0;
+ public static final int SORT_ORDER_LAST_MODIFIED = 1;
public static final int SORT_ORDER_SIZE = 2;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 5466dbf..3447a51 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -29,6 +29,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.provider.DocumentsContract.DocumentRoot;
import android.text.TextUtils.TruncateAt;
import android.util.Log;
import android.view.LayoutInflater;
@@ -42,7 +43,6 @@ import android.widget.ListView;
import android.widget.TextView;
import com.android.documentsui.model.DocumentStack;
-import com.android.documentsui.model.Root;
import com.google.android.collect.Lists;
import libcore.io.IoUtils;
@@ -181,8 +181,8 @@ public class RecentsCreateFragment extends Fragment {
final View summaryList = convertView.findViewById(R.id.summary_list);
final DocumentStack stack = getItem(position);
- final Root root = roots.findRoot(stack.peek());
- icon.setImageDrawable(root != null ? root.icon : null);
+ final DocumentRoot root = stack.getRoot(roots);
+ icon.setImageDrawable(root.loadIcon(context));
final StringBuilder builder = new StringBuilder();
for (int i = stack.size() - 1; i >= 0; i--) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index c3b498e..aa21457 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -18,30 +18,24 @@ package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
-import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.DocumentRoot;
import android.provider.DocumentsContract.Documents;
import android.util.Log;
-import android.util.Pair;
-import com.android.documentsui.model.Document;
-import com.android.documentsui.model.DocumentsProviderInfo;
-import com.android.documentsui.model.DocumentsProviderInfo.Icon;
-import com.android.documentsui.model.Root;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Objects;
import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
/**
@@ -54,14 +48,9 @@ public class RootsCache {
private final Context mContext;
- /** Map from authority to cached info */
- private HashMap<String, DocumentsProviderInfo> mProviders = Maps.newHashMap();
- /** Map from (authority+rootId) to cached info */
- private HashMap<Pair<String, String>, Root> mRoots = Maps.newHashMap();
+ public List<DocumentRoot> mRoots = Lists.newArrayList();
- public ArrayList<Root> mRootsList = Lists.newArrayList();
-
- private Root mRecentsRoot;
+ private DocumentRoot mRecentsRoot;
public RootsCache(Context context) {
mContext = context;
@@ -73,95 +62,78 @@ public class RootsCache {
*/
@GuardedBy("ActivityThread")
public void update() {
- mProviders.clear();
mRoots.clear();
- mRootsList.clear();
{
// Create special root for recents
- final Root root = Root.buildRecents(mContext);
- mRootsList.add(root);
+ final DocumentRoot root = new DocumentRoot();
+ root.rootType = DocumentRoot.ROOT_TYPE_SHORTCUT;
+ root.docId = null;
+ root.icon = R.drawable.ic_dir;
+ root.title = mContext.getString(R.string.root_recent);
+ root.summary = null;
+ root.availableBytes = -1;
+
+ mRoots.add(root);
mRecentsRoot = root;
}
// Query for other storage backends
+ final ContentResolver resolver = mContext.getContentResolver();
final PackageManager pm = mContext.getPackageManager();
final List<ProviderInfo> providers = pm.queryContentProviders(
null, -1, PackageManager.GET_META_DATA);
- for (ProviderInfo providerInfo : providers) {
- if (providerInfo.metaData != null && providerInfo.metaData.containsKey(
+ for (ProviderInfo info : providers) {
+ if (info.metaData != null && info.metaData.containsKey(
DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
- final DocumentsProviderInfo info = DocumentsProviderInfo.parseInfo(
- mContext, providerInfo);
- if (info == null) {
- Log.w(TAG, "Missing info for " + providerInfo);
- continue;
- }
-
- mProviders.put(info.providerInfo.authority, info);
+ // TODO: remove deprecated customRoots flag
+ // TODO: populate roots on background thread, and cache results
+ final ContentProviderClient client = resolver
+ .acquireUnstableContentProviderClient(info.authority);
try {
- // TODO: remove deprecated customRoots flag
- // TODO: populate roots on background thread, and cache results
- final Uri uri = DocumentsContract.buildRootsUri(providerInfo.authority);
- final Cursor cursor = mContext.getContentResolver()
- .query(uri, null, null, null, null);
- try {
- while (cursor.moveToNext()) {
- final Root root = Root.fromCursor(mContext, info, cursor);
- mRoots.put(Pair.create(info.providerInfo.authority, root.rootId), root);
- mRootsList.add(root);
- }
- } finally {
- cursor.close();
+ final List<DocumentRoot> roots = DocumentsContract.getDocumentRoots(client);
+ for (DocumentRoot root : roots) {
+ root.authority = info.authority;
}
+ mRoots.addAll(roots);
} catch (Exception e) {
- Log.w(TAG, "Failed to load some roots from " + info.providerInfo.authority
- + ": " + e);
+ Log.w(TAG, "Failed to load some roots from " + info.authority + ": " + e);
+ } finally {
+ ContentProviderClient.closeQuietly(client);
}
}
}
}
- @GuardedBy("ActivityThread")
- public DocumentsProviderInfo findProvider(String authority) {
- return mProviders.get(authority);
- }
-
- @GuardedBy("ActivityThread")
- public Root findRoot(String authority, String rootId) {
- return mRoots.get(Pair.create(authority, rootId));
+ public DocumentRoot findRoot(Uri uri) {
+ final String authority = uri.getAuthority();
+ final String docId = DocumentsContract.getDocId(uri);
+ for (DocumentRoot root : mRoots) {
+ if (Objects.equal(root.authority, authority) && Objects.equal(root.docId, docId)) {
+ return root;
+ }
+ }
+ return null;
}
@GuardedBy("ActivityThread")
- public Root findRoot(Document doc) {
- final String authority = doc.uri.getAuthority();
- final String rootId = DocumentsContract.getRootId(doc.uri);
- return findRoot(authority, rootId);
+ public DocumentRoot getRecentsRoot() {
+ return mRecentsRoot;
}
@GuardedBy("ActivityThread")
- public Root getRecentsRoot() {
- return mRecentsRoot;
+ public boolean isRecentsRoot(DocumentRoot root) {
+ return mRecentsRoot == root;
}
@GuardedBy("ActivityThread")
- public Collection<Root> getRoots() {
- return mRootsList;
+ public List<DocumentRoot> getRoots() {
+ return mRoots;
}
@GuardedBy("ActivityThread")
- public Drawable resolveDocumentIcon(Context context, String authority, String mimeType) {
- // Custom icons take precedence
- final DocumentsProviderInfo info = mProviders.get(authority);
- if (info != null) {
- for (Icon icon : info.customIcons) {
- if (MimePredicate.mimeMatches(icon.mimeType, mimeType)) {
- return icon.icon;
- }
- }
- }
-
+ public static Drawable resolveDocumentIcon(Context context, String mimeType) {
if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
return context.getResources().getDrawable(R.drawable.ic_dir);
} else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 8a48e2a..2cfa841 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -26,7 +26,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
-import android.provider.DocumentsContract.Roots;
+import android.provider.DocumentsContract.DocumentRoot;
import android.text.format.Formatter;
import android.util.Log;
import android.view.LayoutInflater;
@@ -40,10 +40,9 @@ import android.widget.ListView;
import android.widget.TextView;
import com.android.documentsui.SectionedListAdapter.SectionAdapter;
-import com.android.documentsui.model.Root;
-import com.android.documentsui.model.Root.RootComparator;
+import com.android.documentsui.model.Document;
-import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
/**
@@ -102,8 +101,8 @@ public class RootsFragment extends Fragment {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
final Object item = mAdapter.getItem(position);
- if (item instanceof Root) {
- activity.onRootPicked((Root) item, true);
+ if (item instanceof DocumentRoot) {
+ activity.onRootPicked((DocumentRoot) item, true);
} else if (item instanceof ResolveInfo) {
activity.onAppPicked((ResolveInfo) item);
} else {
@@ -112,7 +111,7 @@ public class RootsFragment extends Fragment {
}
};
- private static class RootsAdapter extends ArrayAdapter<Root> implements SectionAdapter {
+ private static class RootsAdapter extends ArrayAdapter<DocumentRoot> implements SectionAdapter {
private int mHeaderId;
public RootsAdapter(Context context, int headerId) {
@@ -132,14 +131,14 @@ public class RootsFragment extends Fragment {
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
- final Root root = getItem(position);
- icon.setImageDrawable(root.icon);
+ final DocumentRoot root = getItem(position);
+ icon.setImageDrawable(root.loadIcon(context));
title.setText(root.title);
// Device summary is always available space
final String summaryText;
- if ((root.rootType == Roots.ROOT_TYPE_DEVICE
- || root.rootType == Roots.ROOT_TYPE_DEVICE_ADVANCED)
+ if ((root.rootType == DocumentRoot.ROOT_TYPE_DEVICE
+ || root.rootType == DocumentRoot.ROOT_TYPE_DEVICE_ADVANCED)
&& root.availableBytes >= 0) {
summaryText = context.getString(R.string.root_available_bytes,
Formatter.formatFileSize(context, root.availableBytes));
@@ -216,27 +215,27 @@ public class RootsFragment extends Fragment {
private final RootsAdapter mDevicesAdvanced;
private final AppsAdapter mApps;
- public SectionedRootsAdapter(Context context, Collection<Root> roots, Intent includeApps) {
+ public SectionedRootsAdapter(Context context, List<DocumentRoot> roots, Intent includeApps) {
mServices = new RootsAdapter(context, R.string.root_type_service);
mShortcuts = new RootsAdapter(context, R.string.root_type_shortcut);
mDevices = new RootsAdapter(context, R.string.root_type_device);
mDevicesAdvanced = new RootsAdapter(context, R.string.root_type_device);
mApps = new AppsAdapter(context);
- for (Root root : roots) {
+ for (DocumentRoot root : roots) {
Log.d(TAG, "Found rootType=" + root.rootType);
switch (root.rootType) {
- case Roots.ROOT_TYPE_SERVICE:
+ case DocumentRoot.ROOT_TYPE_SERVICE:
mServices.add(root);
break;
- case Roots.ROOT_TYPE_SHORTCUT:
+ case DocumentRoot.ROOT_TYPE_SHORTCUT:
mShortcuts.add(root);
break;
- case Roots.ROOT_TYPE_DEVICE:
+ case DocumentRoot.ROOT_TYPE_DEVICE:
mDevices.add(root);
mDevicesAdvanced.add(root);
break;
- case Roots.ROOT_TYPE_DEVICE_ADVANCED:
+ case DocumentRoot.ROOT_TYPE_DEVICE_ADVANCED:
mDevicesAdvanced.add(root);
break;
}
@@ -281,4 +280,16 @@ public class RootsFragment extends Fragment {
}
}
}
+
+ public static class RootComparator implements Comparator<DocumentRoot> {
+ @Override
+ public int compare(DocumentRoot lhs, DocumentRoot rhs) {
+ final int score = Document.compareToIgnoreCaseNullable(lhs.title, rhs.title);
+ if (score != 0) {
+ return score;
+ } else {
+ return Document.compareToIgnoreCaseNullable(lhs.summary, rhs.summary);
+ }
+ }
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index 8eb81b8..7e1a297 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -73,8 +73,8 @@ public class SaveFragment extends Fragment {
final View view = inflater.inflate(R.layout.fragment_save, container, false);
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
- icon.setImageDrawable(roots.resolveDocumentIcon(
- context, null, getArguments().getString(EXTRA_MIME_TYPE)));
+ icon.setImageDrawable(
+ RootsCache.resolveDocumentIcon(context, getArguments().getString(EXTRA_MIME_TYPE)));
mDisplayName = (EditText) view.findViewById(android.R.id.title);
mDisplayName.addTextChangedListener(mDisplayNameWatcher);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
index c0f21cb..692d171 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
@@ -53,17 +53,11 @@ public class Document {
this.size = size;
}
- public static Document fromRoot(ContentResolver resolver, Root root)
- throws FileNotFoundException {
- return fromUri(resolver, root.uri);
- }
-
public static Document fromDirectoryCursor(Uri parent, Cursor cursor) {
final String authority = parent.getAuthority();
- final String rootId = DocumentsContract.getRootId(parent);
final String docId = getCursorString(cursor, DocumentColumns.DOC_ID);
- final Uri uri = DocumentsContract.buildDocumentUri(authority, rootId, docId);
+ final Uri uri = DocumentsContract.buildDocumentUri(authority, docId);
final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
final long lastModified = getCursorLong(cursor, DocumentColumns.LAST_MODIFIED);
@@ -74,6 +68,7 @@ public class Document {
return new Document(uri, mimeType, displayName, lastModified, flags, summary, size);
}
+ @Deprecated
public static Document fromRecentOpenCursor(ContentResolver resolver, Cursor recentCursor)
throws FileNotFoundException {
final Uri uri = Uri.parse(getCursorString(recentCursor, RecentsProvider.COL_URI));
@@ -176,7 +171,7 @@ public class Document {
return (index != -1) ? cursor.getInt(index) : 0;
}
- public static class NameComparator implements Comparator<Document> {
+ public static class DisplayNameComparator implements Comparator<Document> {
@Override
public int compare(Document lhs, Document rhs) {
final boolean leftDir = lhs.isDirectory();
@@ -185,12 +180,12 @@ public class Document {
if (leftDir != rightDir) {
return leftDir ? -1 : 1;
} else {
- return Root.compareToIgnoreCaseNullable(lhs.displayName, rhs.displayName);
+ return compareToIgnoreCaseNullable(lhs.displayName, rhs.displayName);
}
}
}
- public static class DateComparator implements Comparator<Document> {
+ public static class LastModifiedComparator implements Comparator<Document> {
@Override
public int compare(Document lhs, Document rhs) {
return Long.compare(rhs.lastModified, lhs.lastModified);
@@ -213,4 +208,10 @@ public class Document {
fnfe.initCause(t);
throw fnfe;
}
+
+ public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
+ if (lhs == null) return -1;
+ if (rhs == null) return 1;
+ return lhs.compareToIgnoreCase(rhs);
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
index d6c852e..81f75d2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
@@ -21,8 +21,11 @@ import static com.android.documentsui.model.Document.asFileNotFoundException;
import android.content.ContentResolver;
import android.net.Uri;
+import android.provider.DocumentsContract.DocumentRoot;
import android.util.Log;
+import com.android.documentsui.RootsCache;
+
import org.json.JSONArray;
import org.json.JSONException;
@@ -62,4 +65,18 @@ public class DocumentStack extends LinkedList<Document> {
// TODO: handle roots that have gone missing
return stack;
}
+
+ public DocumentRoot getRoot(RootsCache roots) {
+ return roots.findRoot(getLast().uri);
+ }
+
+ public String getTitle(RootsCache roots) {
+ if (size() == 1) {
+ return getRoot(roots).title;
+ } else if (size() > 1) {
+ return peek().displayName;
+ } else {
+ return null;
+ }
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentsProviderInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentsProviderInfo.java
deleted file mode 100644
index 96eb58e..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentsProviderInfo.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2013 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.android.documentsui.model;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ProviderInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.graphics.drawable.Drawable;
-import android.provider.DocumentsContract;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Xml;
-
-import com.android.documentsui.DocumentsActivity;
-import com.google.android.collect.Lists;
-
-import libcore.io.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Representation of a storage backend.
- */
-public class DocumentsProviderInfo {
- private static final String TAG = DocumentsActivity.TAG;
-
- public ProviderInfo providerInfo;
- public boolean customRoots;
- public List<Icon> customIcons;
-
- public static class Icon {
- public String mimeType;
- public Drawable icon;
- }
-
- private static final String TAG_DOCUMENTS_PROVIDER = "documents-provider";
- private static final String TAG_ICON = "icon";
-
- public static DocumentsProviderInfo buildRecents(Context context, ProviderInfo providerInfo) {
- final DocumentsProviderInfo info = new DocumentsProviderInfo();
- info.providerInfo = providerInfo;
- info.customRoots = false;
- return info;
- }
-
- public static DocumentsProviderInfo parseInfo(Context context, ProviderInfo providerInfo) {
- final DocumentsProviderInfo info = new DocumentsProviderInfo();
- info.providerInfo = providerInfo;
- info.customIcons = Lists.newArrayList();
-
- final PackageManager pm = context.getPackageManager();
- final Resources res;
- try {
- res = pm.getResourcesForApplication(providerInfo.applicationInfo);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Failed to find resources for " + providerInfo, e);
- return null;
- }
-
- XmlResourceParser parser = null;
- try {
- parser = providerInfo.loadXmlMetaData(
- pm, DocumentsContract.META_DATA_DOCUMENT_PROVIDER);
- AttributeSet attrs = Xml.asAttributeSet(parser);
-
- int type = 0;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- final String tag = parser.getName();
- if (type == XmlPullParser.START_TAG && TAG_DOCUMENTS_PROVIDER.equals(tag)) {
- final TypedArray a = res.obtainAttributes(
- attrs, com.android.internal.R.styleable.DocumentsProviderInfo);
- info.customRoots = a.getBoolean(
- com.android.internal.R.styleable.DocumentsProviderInfo_customRoots,
- false);
- a.recycle();
-
- } else if (type == XmlPullParser.START_TAG && TAG_ICON.equals(tag)) {
- final TypedArray a = res.obtainAttributes(
- attrs, com.android.internal.R.styleable.Icon);
- final Icon icon = new Icon();
- icon.mimeType = a.getString(com.android.internal.R.styleable.Icon_mimeType);
- icon.icon = a.getDrawable(com.android.internal.R.styleable.Icon_icon);
- info.customIcons.add(icon);
- a.recycle();
- }
- }
- } catch (IOException e) {
- Log.w(TAG, "Failed to parse metadata", e);
- return null;
- } catch (XmlPullParserException e) {
- Log.w(TAG, "Failed to parse metadata", e);
- return null;
- } finally {
- IoUtils.closeQuietly(parser);
- }
-
- return info;
- }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java b/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
deleted file mode 100644
index 23d16df..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2013 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.android.documentsui.model;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources.NotFoundException;
-import android.database.Cursor;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Documents;
-import android.provider.DocumentsContract.RootColumns;
-import android.provider.DocumentsContract.Roots;
-
-import com.android.documentsui.R;
-
-import java.util.Comparator;
-
-/**
- * Representation of a root under a storage backend.
- */
-public class Root {
- public String rootId;
- public int rootType;
- public Uri uri;
- public Drawable icon;
- public String title;
- public String summary;
- public long availableBytes = -1;
- public boolean isRecents;
-
- public static Root buildRecents(Context context) {
- final PackageManager pm = context.getPackageManager();
- final Root root = new Root();
- root.rootId = null;
- root.rootType = Roots.ROOT_TYPE_SHORTCUT;
- root.uri = null;
- root.icon = context.getResources().getDrawable(R.drawable.ic_dir);
- root.title = context.getString(R.string.root_recent);
- root.summary = null;
- root.availableBytes = -1;
- root.isRecents = true;
- return root;
- }
-
- public static Root fromCursor(
- Context context, DocumentsProviderInfo info, Cursor cursor) {
- final PackageManager pm = context.getPackageManager();
-
- final Root root = new Root();
- root.rootId = cursor.getString(cursor.getColumnIndex(RootColumns.ROOT_ID));
- root.rootType = cursor.getInt(cursor.getColumnIndex(RootColumns.ROOT_TYPE));
- root.uri = DocumentsContract.buildDocumentUri(
- info.providerInfo.authority, root.rootId, Documents.DOC_ID_ROOT);
- root.icon = info.providerInfo.loadIcon(pm);
- root.title = info.providerInfo.loadLabel(pm).toString();
- root.availableBytes = cursor.getLong(cursor.getColumnIndex(RootColumns.AVAILABLE_BYTES));
- root.summary = null;
-
- final int icon = cursor.getInt(cursor.getColumnIndex(RootColumns.ICON));
- if (icon != 0) {
- try {
- root.icon = pm.getResourcesForApplication(info.providerInfo.applicationInfo)
- .getDrawable(icon);
- } catch (NotFoundException e) {
- throw new RuntimeException(e);
- } catch (NameNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
-
- final String title = cursor.getString(cursor.getColumnIndex(RootColumns.TITLE));
- if (title != null) {
- root.title = title;
- }
-
- root.summary = cursor.getString(cursor.getColumnIndex(RootColumns.SUMMARY));
- root.isRecents = false;
-
- return root;
- }
-
- /**
- * Return string most suited to showing in a directory listing.
- */
- public String getDirectoryString() {
- return (summary != null) ? summary : title;
- }
-
- public static class RootComparator implements Comparator<Root> {
- @Override
- public int compare(Root lhs, Root rhs) {
- final int score = compareToIgnoreCaseNullable(lhs.title, rhs.title);
- if (score != 0) {
- return score;
- } else {
- return compareToIgnoreCaseNullable(lhs.summary, rhs.summary);
- }
- }
- }
-
- public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
- if (lhs == null) return -1;
- if (rhs == null) return 1;
- return lhs.compareToIgnoreCase(rhs);
- }
-}