am af4d039f: Merge "More UX work for thumbnails, search, management." into klp-dev
* commit 'af4d039fb3a45d4a74683a69ee48071b8338a13d': More UX work for thumbnails, search, management.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -32,12 +32,26 @@
|
||||
android:layout_weight="1"
|
||||
android:background="#fff">
|
||||
|
||||
<ImageView
|
||||
<FrameLayout
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerInside"
|
||||
android:contentDescription="@null" />
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_mime"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerInside"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_thumb"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -25,15 +25,29 @@
|
||||
android:paddingBottom="8dip"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
<FrameLayout
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:scaleType="centerInside"
|
||||
android:contentDescription="@null" />
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_mime"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerInside"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_thumb"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dip"
|
||||
|
||||
@@ -14,6 +14,13 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/title"
|
||||
style="?android:attr/listSeparatorTextViewStyle" />
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
style="?android:attr/listSeparatorTextViewStyle" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@@ -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<RootInfo> 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<DocumentInfo> 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<Uri, Void, Bitmap> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ class DirectoryResult implements AutoCloseable {
|
||||
public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
|
||||
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<DirectoryResult> {
|
||||
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<DirectoryResult> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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<DirectoryResult> {
|
||||
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);
|
||||
|
||||
result.cursor = sorted;
|
||||
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 = cursor;
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Failed to query", e);
|
||||
result.exception = e;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,16 +267,15 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
|
||||
final LinkedList<File> pending = new LinkedList<File>();
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user