diff options
Diffstat (limited to 'packages/DocumentsUI/src')
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); - } -} |