Merge "Don't show recents as copy/move destination." into nyc-dev
This commit is contained in:
@@ -34,7 +34,6 @@ import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@@ -74,8 +73,6 @@ public class DocumentsActivity extends BaseActivity {
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
final Resources res = getResources();
|
||||
|
||||
if (mState.action == ACTION_CREATE) {
|
||||
final String mimeType = getIntent().getType();
|
||||
final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
|
||||
|
||||
@@ -66,7 +66,7 @@ public class RootsCache {
|
||||
private final ContentObserver mObserver;
|
||||
private OnCacheUpdateListener mCacheUpdateListener;
|
||||
|
||||
private final RootInfo mRecentsRoot = new RootInfo();
|
||||
private final RootInfo mRecentsRoot;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final CountDownLatch mFirstLoad = new CountDownLatch(1);
|
||||
@@ -82,6 +82,18 @@ public class RootsCache {
|
||||
public RootsCache(Context context) {
|
||||
mContext = context;
|
||||
mObserver = new RootsChangedObserver();
|
||||
|
||||
// Create a new anonymous "Recents" RootInfo. It's a faker.
|
||||
mRecentsRoot = new RootInfo() {{
|
||||
// Special root for recents
|
||||
authority = null;
|
||||
rootId = null;
|
||||
derivedIcon = R.drawable.ic_root_recent;
|
||||
derivedType = RootInfo.TYPE_RECENTS;
|
||||
flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD;
|
||||
title = mContext.getString(R.string.root_recent);
|
||||
availableBytes = -1;
|
||||
}};
|
||||
}
|
||||
|
||||
private class RootsChangedObserver extends ContentObserver {
|
||||
@@ -104,16 +116,6 @@ public class RootsCache {
|
||||
* Gather roots from all known storage providers.
|
||||
*/
|
||||
public void updateAsync() {
|
||||
// Special root for recents
|
||||
mRecentsRoot.authority = null;
|
||||
mRecentsRoot.rootId = null;
|
||||
mRecentsRoot.derivedIcon = R.drawable.ic_root_recent;
|
||||
mRecentsRoot.derivedType = RootInfo.TYPE_RECENTS;
|
||||
mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE
|
||||
| Root.FLAG_SUPPORTS_IS_CHILD;
|
||||
mRecentsRoot.title = mContext.getString(R.string.root_recent);
|
||||
mRecentsRoot.availableBytes = -1;
|
||||
|
||||
new UpdateTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
@@ -360,7 +362,7 @@ public class RootsCache {
|
||||
}
|
||||
|
||||
public boolean isRecentsRoot(RootInfo root) {
|
||||
return mRecentsRoot == root;
|
||||
return mRecentsRoot.equals(root);
|
||||
}
|
||||
|
||||
public Collection<RootInfo> getRootsBlocking() {
|
||||
@@ -400,27 +402,22 @@ public class RootsCache {
|
||||
static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
|
||||
final List<RootInfo> matching = new ArrayList<>();
|
||||
for (RootInfo root : roots) {
|
||||
final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
|
||||
final boolean supportsIsChild = (root.flags & Root.FLAG_SUPPORTS_IS_CHILD) != 0;
|
||||
final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
|
||||
final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
|
||||
final boolean empty = (root.flags & Root.FLAG_EMPTY) != 0;
|
||||
|
||||
// Exclude read-only devices when creating
|
||||
if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
|
||||
if (state.action == State.ACTION_PICK_COPY_DESTINATION && !supportsCreate) continue;
|
||||
if (state.action == State.ACTION_CREATE && !root.supportsCreate()) continue;
|
||||
if (state.action == State.ACTION_PICK_COPY_DESTINATION
|
||||
&& !root.supportsCreate()) continue;
|
||||
// Exclude roots that don't support directory picking
|
||||
if (state.action == State.ACTION_OPEN_TREE && !supportsIsChild) continue;
|
||||
if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) continue;
|
||||
// Exclude advanced devices when not requested
|
||||
if (!state.showAdvanced && advanced) continue;
|
||||
if (!state.showAdvanced && root.isAdvanced()) continue;
|
||||
// Exclude non-local devices when local only
|
||||
if (state.localOnly && !localOnly) continue;
|
||||
if (state.localOnly && !root.isLocalOnly()) continue;
|
||||
// Exclude downloads roots that don't support directory creation
|
||||
// TODO: Add flag to check the root supports directory creation or not.
|
||||
if (state.directoryCopy && root.isDownloads()) continue;
|
||||
if (state.directoryCopy && !root.supportsChildren()) continue;
|
||||
|
||||
// Only show empty roots when creating, or in browse mode.
|
||||
if (empty && (state.action == State.ACTION_OPEN
|
||||
if (root.isEmpty() && (state.action == State.ACTION_OPEN
|
||||
|| state.action == State.ACTION_GET_CONTENT)) {
|
||||
if (DEBUG) Log.i(TAG, "Skipping empty root: " + root);
|
||||
continue;
|
||||
@@ -436,10 +433,13 @@ public class RootsCache {
|
||||
|
||||
// Exclude roots from the calling package.
|
||||
if (state.excludedAuthorities.contains(root.authority)) {
|
||||
if (DEBUG) Log.d(TAG, "Excluding root " + root.authority + " from calling package.");
|
||||
if (DEBUG) Log.d(
|
||||
TAG, "Excluding root " + root.authority + " from calling package.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(
|
||||
TAG, "Including root " + root + " in roots list.");
|
||||
matching.add(root);
|
||||
}
|
||||
return matching;
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.Log;
|
||||
@@ -86,7 +87,6 @@ public class RootsFragment extends Fragment {
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final Context context = inflater.getContext();
|
||||
|
||||
final View view = inflater.inflate(R.layout.fragment_roots, container, false);
|
||||
mList = (ListView) view.findViewById(R.id.roots_list);
|
||||
@@ -112,11 +112,13 @@ public class RootsFragment extends Fragment {
|
||||
@Override
|
||||
public void onLoadFinished(
|
||||
Loader<Collection<RootInfo>> loader, Collection<RootInfo> result) {
|
||||
if (!isAdded()) return;
|
||||
if (!isAdded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Intent includeApps = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
|
||||
Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
|
||||
|
||||
mAdapter = new RootsAdapter(context, result, includeApps);
|
||||
mAdapter = new RootsAdapter(context, result, handlerAppIntent);
|
||||
mList.setAdapter(mAdapter);
|
||||
|
||||
onCurrentRootChanged();
|
||||
@@ -151,7 +153,9 @@ public class RootsFragment extends Fragment {
|
||||
}
|
||||
|
||||
public void onCurrentRootChanged() {
|
||||
if (mAdapter == null) return;
|
||||
if (mAdapter == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final RootInfo root = ((BaseActivity) getActivity()).getCurrentRoot();
|
||||
for (int i = 0; i < mAdapter.getCount(); i++) {
|
||||
@@ -300,7 +304,13 @@ public class RootsFragment extends Fragment {
|
||||
}
|
||||
|
||||
private static class RootsAdapter extends ArrayAdapter<Item> {
|
||||
public RootsAdapter(Context context, Collection<RootInfo> roots, Intent includeApps) {
|
||||
|
||||
/**
|
||||
* @param handlerAppIntent When not null, apps capable of handling the original
|
||||
* intent will be included in list of roots (in special section at bottom).
|
||||
*/
|
||||
public RootsAdapter(
|
||||
Context context, Collection<RootInfo> roots, @Nullable Intent handlerAppIntent) {
|
||||
super(context, 0);
|
||||
|
||||
final List<RootItem> libraries = new ArrayList<>();
|
||||
@@ -322,27 +332,39 @@ public class RootsFragment extends Fragment {
|
||||
Collections.sort(others, comp);
|
||||
|
||||
addAll(libraries);
|
||||
add(new SpacerItem());
|
||||
// Only add the spacer if it is actually separating something.
|
||||
if (!libraries.isEmpty() && !others.isEmpty()) {
|
||||
add(new SpacerItem());
|
||||
}
|
||||
addAll(others);
|
||||
|
||||
if (includeApps != null) {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final List<ResolveInfo> infos = pm.queryIntentActivities(
|
||||
includeApps, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
// Include apps that can handle this intent too.
|
||||
if (handlerAppIntent != null) {
|
||||
includeHandlerApps(context, handlerAppIntent);
|
||||
}
|
||||
}
|
||||
|
||||
final List<AppItem> apps = new ArrayList<>();
|
||||
/**
|
||||
* Adds apps capable of handling the original intent will be included
|
||||
* in list of roots (in special section at bottom).
|
||||
*/
|
||||
private void includeHandlerApps(Context context, Intent handlerAppIntent) {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final List<ResolveInfo> infos = pm.queryIntentActivities(
|
||||
handlerAppIntent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
|
||||
// Omit ourselves from the list
|
||||
for (ResolveInfo info : infos) {
|
||||
if (!context.getPackageName().equals(info.activityInfo.packageName)) {
|
||||
apps.add(new AppItem(info));
|
||||
}
|
||||
final List<AppItem> apps = new ArrayList<>();
|
||||
|
||||
// Omit ourselves from the list
|
||||
for (ResolveInfo info : infos) {
|
||||
if (!context.getPackageName().equals(info.activityInfo.packageName)) {
|
||||
apps.add(new AppItem(info));
|
||||
}
|
||||
}
|
||||
|
||||
if (apps.size() > 0) {
|
||||
add(new SpacerItem());
|
||||
addAll(apps);
|
||||
}
|
||||
if (apps.size() > 0) {
|
||||
add(new SpacerItem());
|
||||
addAll(apps);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ public class RootsLoader extends AsyncTaskLoader<Collection<RootInfo>> {
|
||||
if (isReset()) {
|
||||
return;
|
||||
}
|
||||
Collection<RootInfo> oldResult = mResult;
|
||||
|
||||
mResult = result;
|
||||
|
||||
if (isStarted()) {
|
||||
|
||||
@@ -985,7 +985,8 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
|
||||
}
|
||||
|
||||
private void copyDocuments(final List<DocumentInfo> docs, final DocumentInfo destination) {
|
||||
if (!canCopy(docs, destination)) {
|
||||
BaseActivity activity = (BaseActivity) getActivity();
|
||||
if (!canCopy(docs, activity.getCurrentRoot(), destination)) {
|
||||
Snackbars.makeSnackbar(
|
||||
getActivity(),
|
||||
R.string.clipboard_files_cannot_paste,
|
||||
@@ -1065,13 +1066,13 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
|
||||
*
|
||||
* @return true if the list of files can be copied to destination.
|
||||
*/
|
||||
boolean canCopy(List<DocumentInfo> files, DocumentInfo dest) {
|
||||
BaseActivity activity = (BaseActivity) getActivity();
|
||||
private boolean canCopy(List<DocumentInfo> files, RootInfo root, DocumentInfo dest) {
|
||||
if (dest == null || !dest.isDirectory() || !dest.isCreateSupported()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final RootInfo root = activity.getCurrentRoot();
|
||||
|
||||
// Can't copy folders to Downloads.
|
||||
if (root.isDownloads()) {
|
||||
// Can't copy folders to roots that don't support children.
|
||||
if (!root.supportsChildren()) {
|
||||
for (DocumentInfo docs : files) {
|
||||
if (docs.isDirectory()) {
|
||||
return false;
|
||||
@@ -1079,7 +1080,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
|
||||
}
|
||||
}
|
||||
|
||||
return dest != null && dest.isDirectory() && dest.isCreateSupported();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void selectAllFiles() {
|
||||
|
||||
@@ -249,6 +249,26 @@ public class RootInfo implements Durable, Parcelable {
|
||||
return (flags & Root.FLAG_HAS_SETTINGS) != 0;
|
||||
}
|
||||
|
||||
public boolean supportsChildren() {
|
||||
return (flags & Root.FLAG_SUPPORTS_IS_CHILD) != 0;
|
||||
}
|
||||
|
||||
public boolean supportsCreate() {
|
||||
return (flags & Root.FLAG_SUPPORTS_CREATE) != 0;
|
||||
}
|
||||
|
||||
public boolean isAdvanced() {
|
||||
return (flags & Root.FLAG_ADVANCED) != 0;
|
||||
}
|
||||
|
||||
public boolean isLocalOnly() {
|
||||
return (flags & Root.FLAG_LOCAL_ONLY) != 0;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return (flags & Root.FLAG_EMPTY) != 0;
|
||||
}
|
||||
|
||||
public Drawable loadIcon(Context context) {
|
||||
if (derivedIcon != 0) {
|
||||
return context.getDrawable(derivedIcon);
|
||||
|
||||
Reference in New Issue
Block a user