From 4ec973925fc2cd18f9ec0d0ca5af588564fded27 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 10 Sep 2013 12:04:26 -0700 Subject: More UX work for thumbnails, search, management. Hide non-finished downloads from normal picker UI, but keep them around in management mode. Uses a Uri query parameter and a hidden API on DocumentsProvider. Scale thumbnails to fit viewport, always show MIME icon while waiting on thumbnails, and crossfade between them. Cancel thumbnail tasks when views are recycled. Filter directories out of search results for now. Also leave sort ordering from backend intact, since it's custom ranking. Fix SearchView interaction to dismiss properly and restore across orientation and drawer state changes. Hide most actions when drawer is open. Invalidate RootInfo cache when locale changes. Apply sort ordering when showing recent create directories. Hide recent summary string when icon is enough for user to disambiguate. Bug: 10667184, 10665663 Change-Id: I331d3272a08c497f88dc659d9e112231cb35aa69 --- core/java/android/provider/DocumentsContract.java | 11 ++ core/java/android/provider/DocumentsProvider.java | 15 ++- packages/DocumentsUI/res/layout/item_doc_grid.xml | 22 +++- packages/DocumentsUI/res/layout/item_doc_list.xml | 22 +++- .../DocumentsUI/res/layout/item_root_header.xml | 13 ++- .../com/android/documentsui/DirectoryFragment.java | 127 ++++++++++++++++----- .../com/android/documentsui/DirectoryLoader.java | 26 ++++- .../com/android/documentsui/DocumentsActivity.java | 44 ++++++- .../android/documentsui/DocumentsApplication.java | 8 +- .../documentsui/FilteringCursorWrapper.java | 7 ++ .../android/documentsui/RecentsCreateFragment.java | 4 +- .../com/android/documentsui/RecentsProvider.java | 6 +- .../src/com/android/documentsui/RootsCache.java | 17 +++ .../src/com/android/documentsui/RootsFragment.java | 3 +- .../com/android/documentsui/model/RootInfo.java | 3 +- .../externalstorage/ExternalStorageProvider.java | 9 +- 16 files changed, 270 insertions(+), 67 deletions(-) diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 91b3b48ab17e..43120c4c8901 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -459,6 +459,7 @@ public final class DocumentsContract { private static final String PATH_SEARCH = "search"; private static final String PARAM_QUERY = "query"; + private static final String PARAM_MANAGE = "manage"; /** * Build Uri representing the roots of a document provider. When queried, a @@ -583,6 +584,16 @@ public final class DocumentsContract { return searchDocumentsUri.getQueryParameter(PARAM_QUERY); } + /** {@hide} */ + public static Uri setManageMode(Uri uri) { + return uri.buildUpon().appendQueryParameter(PARAM_MANAGE, "true").build(); + } + + /** {@hide} */ + public static boolean isManageMode(Uri uri) { + return uri.getBooleanQueryParameter(PARAM_MANAGE, false); + } + /** * Return list of all documents that the calling package has "open." These * are Uris matching {@link DocumentsContract} to which persistent diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 1b0fc4d1f70d..d80182703bdf 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -167,6 +167,14 @@ public abstract class DocumentsProvider extends ContentProvider { String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException; + /** {@hide} */ + @SuppressWarnings("unused") + public Cursor queryChildDocumentsForManage( + String parentDocumentId, String[] projection, String sortOrder) + throws FileNotFoundException { + throw new UnsupportedOperationException("Manage not supported"); + } + /** * Return documents that that match the given query, starting the search at * the given directory. @@ -262,7 +270,12 @@ public abstract class DocumentsProvider extends ContentProvider { case MATCH_DOCUMENT: return queryDocument(getDocumentId(uri), projection); case MATCH_CHILDREN: - return queryChildDocuments(getDocumentId(uri), projection, sortOrder); + if (DocumentsContract.isManageMode(uri)) { + return queryChildDocumentsForManage( + getDocumentId(uri), projection, sortOrder); + } else { + return queryChildDocuments(getDocumentId(uri), projection, sortOrder); + } case MATCH_SEARCH: return querySearchDocuments( getDocumentId(uri), getSearchDocumentsQuery(uri), projection); diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml index 8d1fc9aa34fd..8b37d216298c 100644 --- a/packages/DocumentsUI/res/layout/item_doc_grid.xml +++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml @@ -32,12 +32,26 @@ android:layout_weight="1" android:background="#fff"> - + android:layout_height="match_parent"> + + + + + + - + android:layout_gravity="center_vertical"> + + + + + + - + + + + + diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index 45f028d533aa..13a84f493c21 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -38,9 +38,11 @@ import android.content.Loader; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Point; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.os.CancellationSignal; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.text.format.DateUtils; @@ -56,6 +58,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AbsListView.MultiChoiceModeListener; +import android.widget.AbsListView.RecyclerListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; @@ -162,10 +165,12 @@ public class DirectoryFragment extends Fragment { mListView = (ListView) view.findViewById(R.id.list); mListView.setOnItemClickListener(mItemListener); mListView.setMultiChoiceModeListener(mMultiListener); + mListView.setRecyclerListener(mRecycleListener); mGridView = (GridView) view.findViewById(R.id.grid); mGridView.setOnItemClickListener(mItemListener); mGridView.setMultiChoiceModeListener(mMultiListener); + mGridView.setRecyclerListener(mRecycleListener); return view; } @@ -192,13 +197,19 @@ public class DirectoryFragment extends Fragment { case TYPE_NORMAL: contentsUri = DocumentsContract.buildChildDocumentsUri( doc.authority, doc.documentId); + if (state.action == ACTION_MANAGE) { + contentsUri = DocumentsContract.setManageMode(contentsUri); + } return new DirectoryLoader( - context, root, doc, contentsUri, state.userSortOrder); + context, mType, root, doc, contentsUri, state.userSortOrder); case TYPE_SEARCH: contentsUri = DocumentsContract.buildSearchDocumentsUri( doc.authority, doc.documentId, query); + if (state.action == ACTION_MANAGE) { + contentsUri = DocumentsContract.setManageMode(contentsUri); + } return new DirectoryLoader( - context, root, doc, contentsUri, state.userSortOrder); + context, mType, root, doc, contentsUri, state.userSortOrder); case TYPE_RECENT_OPEN: final RootsCache roots = DocumentsApplication.getRootsCache(context); final List matchingRoots = roots.getMatchingRoots(state); @@ -425,6 +436,20 @@ public class DirectoryFragment extends Fragment { } }; + private RecyclerListener mRecycleListener = new RecyclerListener() { + @Override + public void onMovedToScrapHeap(View view) { + final ImageView iconThumb = (ImageView) view.findViewById(R.id.icon_thumb); + if (iconThumb != null) { + final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag(); + if (oldTask != null) { + oldTask.reallyCancel(); + iconThumb.setTag(null); + } + } + } + }; + private void onShareDocuments(List docs) { Intent intent; if (docs.size() == 1) { @@ -632,7 +657,9 @@ public class DirectoryFragment extends Fragment { final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY); final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE); - final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon); + final View icon = convertView.findViewById(android.R.id.icon); + final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime); + final ImageView iconThumb = (ImageView) convertView.findViewById(R.id.icon_thumb); final TextView title = (TextView) convertView.findViewById(android.R.id.title); final View line2 = convertView.findViewById(R.id.line2); final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1); @@ -640,30 +667,49 @@ public class DirectoryFragment extends Fragment { final TextView date = (TextView) convertView.findViewById(R.id.date); final TextView size = (TextView) convertView.findViewById(R.id.size); - final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) icon.getTag(); + final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag(); if (oldTask != null) { - oldTask.cancel(false); + oldTask.reallyCancel(); + iconThumb.setTag(null); } + iconMime.animate().cancel(); + iconThumb.animate().cancel(); + final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0; final boolean allowThumbnail = (state.derivedMode == MODE_GRID) || MimePredicate.mimeMatches(LIST_THUMBNAIL_MIMES, docMimeType); + boolean cacheHit = false; if (supportsThumbnail && allowThumbnail) { final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId); final Bitmap cachedResult = thumbs.get(uri); if (cachedResult != null) { - icon.setImageBitmap(cachedResult); + iconThumb.setImageBitmap(cachedResult); + cacheHit = true; } else { - final ThumbnailAsyncTask task = new ThumbnailAsyncTask(icon, mThumbSize); - icon.setImageBitmap(null); - icon.setTag(task); - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, uri); + iconThumb.setImageDrawable(null); + final ThumbnailAsyncTask task = new ThumbnailAsyncTask( + uri, iconMime, iconThumb, mThumbSize); + iconThumb.setTag(task); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - } else if (docIcon != 0) { - icon.setImageDrawable(IconUtils.loadPackageIcon(context, docAuthority, docIcon)); + } + + // Always throw MIME icon into place, even when a thumbnail is being + // loaded in background. + if (cacheHit) { + iconMime.setAlpha(0f); + iconThumb.setAlpha(1f); } else { - icon.setImageDrawable(IconUtils.loadMimeIcon(context, docMimeType)); + iconMime.setAlpha(1f); + iconThumb.setAlpha(0f); + if (docIcon != 0) { + iconMime.setImageDrawable( + IconUtils.loadPackageIcon(context, docAuthority, docIcon)); + } else { + iconMime.setImageDrawable(IconUtils.loadMimeIcon(context, docMimeType)); + } } title.setText(docDisplayName); @@ -672,12 +718,19 @@ public class DirectoryFragment extends Fragment { if (mType == TYPE_RECENT_OPEN) { final RootInfo root = roots.getRoot(docAuthority, docRootId); + final Drawable iconDrawable = root.loadIcon(context); icon1.setVisibility(View.VISIBLE); - icon1.setImageDrawable(root.loadIcon(context)); - summary.setText(root.getDirectoryString()); - summary.setVisibility(View.VISIBLE); - summary.setTextAlignment(TextView.TEXT_ALIGNMENT_TEXT_END); - hasLine2 = true; + icon1.setImageDrawable(iconDrawable); + + if (iconDrawable != null && roots.isIconUnique(root)) { + // No summary needed if icon speaks for itself + summary.setVisibility(View.INVISIBLE); + } else { + summary.setText(root.getDirectoryString()); + summary.setVisibility(View.VISIBLE); + summary.setTextAlignment(TextView.TEXT_ALIGNMENT_TEXT_END); + hasLine2 = true; + } } else { icon1.setVisibility(View.GONE); if (docSummary != null) { @@ -762,32 +815,39 @@ public class DirectoryFragment extends Fragment { } private static class ThumbnailAsyncTask extends AsyncTask { - private final ImageView mTarget; + private final Uri mUri; + private final ImageView mIconMime; + private final ImageView mIconThumb; private final Point mThumbSize; + private final CancellationSignal mSignal; - public ThumbnailAsyncTask(ImageView target, Point thumbSize) { - mTarget = target; + public ThumbnailAsyncTask( + Uri uri, ImageView iconMime, ImageView iconThumb, Point thumbSize) { + mUri = uri; + mIconMime = iconMime; + mIconThumb = iconThumb; mThumbSize = thumbSize; + mSignal = new CancellationSignal(); } - @Override - protected void onPreExecute() { - mTarget.setTag(this); + public void reallyCancel() { + cancel(false); + mSignal.cancel(); } @Override protected Bitmap doInBackground(Uri... params) { - final Context context = mTarget.getContext(); - final Uri uri = params[0]; + final Context context = mIconThumb.getContext(); Bitmap result = null; try { + // TODO: switch to using unstable provider result = DocumentsContract.getDocumentThumbnail( - context.getContentResolver(), uri, mThumbSize, null); + context.getContentResolver(), mUri, mThumbSize, mSignal); if (result != null) { final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache( context, mThumbSize); - thumbs.put(uri, result); + thumbs.put(mUri, result); } } catch (Exception e) { Log.w(TAG, "Failed to load thumbnail: " + e); @@ -797,9 +857,14 @@ public class DirectoryFragment extends Fragment { @Override protected void onPostExecute(Bitmap result) { - if (mTarget.getTag() == this) { - mTarget.setImageBitmap(result); - mTarget.setTag(null); + if (mIconThumb.getTag() == this && result != null) { + mIconThumb.setTag(null); + mIconThumb.setImageBitmap(result); + + mIconMime.setAlpha(1f); + mIconMime.animate().alpha(0f).start(); + mIconThumb.setAlpha(0f); + mIconThumb.animate().alpha(1f).start(); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java index 14718364d829..334e26285f6a 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java @@ -62,6 +62,7 @@ class DirectoryResult implements AutoCloseable { public class DirectoryLoader extends AsyncTaskLoader { private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver(); + private final int mType; private final RootInfo mRoot; private final DocumentInfo mDoc; private final Uri mUri; @@ -70,9 +71,10 @@ public class DirectoryLoader extends AsyncTaskLoader { private CancellationSignal mSignal; private DirectoryResult mResult; - public DirectoryLoader( - Context context, RootInfo root, DocumentInfo doc, Uri uri, int userSortOrder) { + public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri, + int userSortOrder) { super(context); + mType = type; mRoot = root; mDoc = doc; mUri = uri; @@ -128,6 +130,11 @@ public class DirectoryLoader extends AsyncTaskLoader { } } + // Search always uses ranking from provider + if (mType == DirectoryFragment.TYPE_SEARCH) { + result.sortOrder = State.SORT_ORDER_UNKNOWN; + } + Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + mUserSortOrder + " --> mode=" + result.mode + ", sortOrder=" + result.sortOrder); @@ -137,11 +144,18 @@ public class DirectoryLoader extends AsyncTaskLoader { mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal); cursor.registerContentObserver(mObserver); - final Cursor withRoot = new RootCursorWrapper( - mUri.getAuthority(), mRoot.rootId, cursor, -1); - final Cursor sorted = new SortingCursorWrapper(withRoot, result.sortOrder); + cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1); + + if (mType == DirectoryFragment.TYPE_SEARCH) { + // Filter directories out of search results, for now + cursor = new FilteringCursorWrapper(cursor, null, new String[] { + Document.MIME_TYPE_DIR }); + } else { + // Normal directories should have sorting applied + cursor = new SortingCursorWrapper(cursor, result.sortOrder); + } - result.cursor = sorted; + result.cursor = cursor; } catch (Exception e) { Log.d(TAG, "Failed to query", e); result.exception = e; diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index 79d24435d40f..e89d388688f2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -50,6 +50,7 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; +import android.view.MenuItem.OnActionExpandListener; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; @@ -87,6 +88,7 @@ public class DocumentsActivity extends Activity { private static final String EXTRA_STATE = "state"; private boolean mIgnoreNextNavigation; + private boolean mIgnoreNextCollapse; private RootsCache mRoots; private State mState; @@ -234,12 +236,14 @@ public class DocumentsActivity extends Activity { public void onDrawerOpened(View drawerView) { mDrawerToggle.onDrawerOpened(drawerView); updateActionBar(); + invalidateOptionsMenu(); } @Override public void onDrawerClosed(View drawerView) { mDrawerToggle.onDrawerClosed(drawerView); updateActionBar(); + invalidateOptionsMenu(); } @Override @@ -305,7 +309,6 @@ public class DocumentsActivity extends Activity { public boolean onQueryTextSubmit(String query) { mState.currentSearch = query; onCurrentDirectoryChanged(); - mSearchView.setIconified(true); return true; } @@ -315,12 +318,22 @@ public class DocumentsActivity extends Activity { } }); - mSearchView.setOnCloseListener(new OnCloseListener() { + searchMenu.setOnActionExpandListener(new OnActionExpandListener() { @Override - public boolean onClose() { + public boolean onMenuItemActionExpand(MenuItem item) { + return true; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + if (mIgnoreNextCollapse) { + mIgnoreNextCollapse = false; + return true; + } + mState.currentSearch = null; onCurrentDirectoryChanged(); - return false; + return true; } }); @@ -342,6 +355,18 @@ public class DocumentsActivity extends Activity { final MenuItem list = menu.findItem(R.id.menu_list); final MenuItem settings = menu.findItem(R.id.menu_settings); + // Open drawer means we hide most actions + if (mDrawerLayout.isDrawerOpen(mRootsContainer)) { + createDir.setVisible(false); + search.setVisible(false); + sort.setVisible(false); + grid.setVisible(false); + list.setVisible(false); + mIgnoreNextCollapse = true; + search.collapseActionView(); + return true; + } + if (cwd != null) { sort.setVisible(true); grid.setVisible(mState.derivedMode != MODE_GRID); @@ -352,6 +377,17 @@ public class DocumentsActivity extends Activity { list.setVisible(false); } + if (mState.currentSearch != null) { + // Search uses backend ranking; no sorting + sort.setVisible(false); + + search.expandActionView(); + mSearchView.setQuery(mState.currentSearch, false); + } else { + mIgnoreNextCollapse = true; + search.collapseActionView(); + } + // Only sort by size when visible sortSize.setVisible(mState.showSize); diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java index 0a6cbc0d4860..180ddefa9c01 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java @@ -56,7 +56,11 @@ public class DocumentsApplication extends Application { packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); packageFilter.addDataScheme("package"); - registerReceiver(mPackageReceiver, packageFilter); + registerReceiver(mCacheReceiver, packageFilter); + + final IntentFilter localeFilter = new IntentFilter(); + localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED); + registerReceiver(mCacheReceiver, localeFilter); } @Override @@ -70,7 +74,7 @@ public class DocumentsApplication extends Application { } } - private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { + private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO: narrow changed/removed to only packages that have backends diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java index 60f010380b66..5f56963ae463 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java @@ -34,6 +34,10 @@ public class FilteringCursorWrapper extends AbstractCursor { private int mCount; public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes) { + this(cursor, acceptMimes, null); + } + + public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes, String[] rejectMimes) { mCursor = cursor; final int count = cursor.getCount(); @@ -43,6 +47,9 @@ public class FilteringCursorWrapper extends AbstractCursor { while (cursor.moveToNext()) { final String mimeType = cursor.getString( cursor.getColumnIndex(Document.COLUMN_MIME_TYPE)); + if (rejectMimes != null && MimePredicate.mimeMatches(rejectMimes, mimeType)) { + continue; + } if (MimePredicate.mimeMatches(acceptMimes, mimeType)) { mPosition[mCount++] = cursor.getPosition(); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java index 3642478e24f5..140373b0c9eb 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java @@ -183,12 +183,12 @@ public class RecentsCreateFragment extends Fragment { convertView = inflater.inflate(R.layout.item_doc_list, parent, false); } - final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon); + final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime); final TextView title = (TextView) convertView.findViewById(android.R.id.title); final View line2 = convertView.findViewById(R.id.line2); final DocumentStack stack = getItem(position); - icon.setImageDrawable(stack.root.loadIcon(context)); + iconMime.setImageDrawable(stack.root.loadIcon(context)); final Drawable crumb = context.getResources() .getDrawable(R.drawable.ic_breadcrumb_arrow); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java index 1fe5d542b92a..af79c9364122 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java @@ -151,18 +151,18 @@ public class RecentsProvider extends ContentProvider { case URI_RECENT: final long cutoff = System.currentTimeMillis() - MAX_HISTORY_IN_MILLIS; return db.query(TABLE_RECENT, projection, RecentColumns.TIMESTAMP + ">" + cutoff, - null, null, null, null); + null, null, null, sortOrder); case URI_STATE: final String authority = uri.getPathSegments().get(1); final String rootId = uri.getPathSegments().get(2); final String documentId = uri.getPathSegments().get(3); return db.query(TABLE_STATE, projection, StateColumns.AUTHORITY + "=? AND " + StateColumns.ROOT_ID + "=? AND " + StateColumns.DOCUMENT_ID + "=?", - new String[] { authority, rootId, documentId }, null, null, null); + new String[] { authority, rootId, documentId }, null, null, sortOrder); case URI_RESUME: final String packageName = uri.getPathSegments().get(1); return db.query(TABLE_RESUME, projection, ResumeColumns.PACKAGE_NAME + "=?", - new String[] { packageName }, null, null, null); + new String[] { packageName }, null, null, sortOrder); default: throw new UnsupportedOperationException("Unsupported Uri " + uri); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java index adf4701884e2..b48674cff9c5 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java @@ -109,6 +109,8 @@ public class RootsCache { } } } + + Log.d(TAG, "Update found " + mRoots.size() + " roots"); } @Deprecated @@ -133,6 +135,21 @@ public class RootsCache { return null; } + @GuardedBy("ActivityThread") + public boolean isIconUnique(RootInfo root) { + for (RootInfo test : mRoots) { + if (Objects.equal(test.authority, root.authority)) { + if (Objects.equal(test.rootId, root.rootId)) { + continue; + } + if (test.icon == root.icon) { + return false; + } + } + } + return true; + } + @GuardedBy("ActivityThread") public RootInfo getRecentsRoot() { return mRecentsRoot; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java index efb972d44c0a..f3a21c657f6e 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.provider.DocumentsContract.Root; +import android.text.TextUtils; import android.text.format.Formatter; import android.view.LayoutInflater; import android.view.View; @@ -168,7 +169,7 @@ public class RootsFragment extends Fragment { } summary.setText(summaryText); - summary.setVisibility(summaryText != null ? View.VISIBLE : View.GONE); + summary.setVisibility(TextUtils.isEmpty(summaryText) ? View.GONE : View.VISIBLE); return convertView; } diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java index e0e8acf98ece..b5a198cd9c9a 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java @@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.provider.DocumentsContract.Root; +import android.text.TextUtils; import com.android.documentsui.IconUtils; import com.android.documentsui.R; @@ -203,6 +204,6 @@ public class RootInfo implements Durable, Parcelable { } public String getDirectoryString() { - return (summary != null) ? summary : title; + return !TextUtils.isEmpty(summary) ? summary : title; } } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 2326ec2c1797..ada3ad721b40 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -267,16 +267,15 @@ public class ExternalStorageProvider extends DocumentsProvider { final LinkedList pending = new LinkedList(); pending.add(parent); - while (!pending.isEmpty() && result.getCount() < 20) { + while (!pending.isEmpty() && result.getCount() < 24) { final File file = pending.removeFirst(); if (file.isDirectory()) { for (File child : file.listFiles()) { pending.add(child); } - } else { - if (file.getName().toLowerCase().contains(query)) { - includeFile(result, null, file); - } + } + if (file.getName().toLowerCase().contains(query)) { + includeFile(result, null, file); } } return result; -- cgit v1.2.3-59-g8ed1b