am 118cb035: Merge "Filter roots based on incoming request." into klp-dev
* commit '118cb0353f6dabce1a1d6b550f7fc9eb78c7de87': Filter roots based on incoming request.
This commit is contained in:
@@ -191,7 +191,9 @@ public class DirectoryFragment extends Fragment {
|
||||
authority, docId, query);
|
||||
return new DirectoryLoader(context, rootId, contentsUri, state.sortOrder);
|
||||
case TYPE_RECENT_OPEN:
|
||||
return new RecentLoader(context);
|
||||
final RootsCache roots = DocumentsApplication.getRootsCache(context);
|
||||
final List<RootInfo> matchingRoots = roots.getMatchingRoots(state);
|
||||
return new RecentLoader(context, matchingRoots);
|
||||
default:
|
||||
throw new IllegalStateException("Unknown type " + mType);
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ public class DocumentsActivity extends Activity {
|
||||
}
|
||||
|
||||
mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
|
||||
mState.showAdvanced = SettingsActivity.getDisplayAdvancedDevices(this);
|
||||
|
||||
if (mState.action == ACTION_MANAGE) {
|
||||
mState.sortOrder = SORT_ORDER_LAST_MODIFIED;
|
||||
@@ -701,6 +702,7 @@ public class DocumentsActivity extends Activity {
|
||||
public boolean allowMultiple = false;
|
||||
public boolean showSize = false;
|
||||
public boolean localOnly = false;
|
||||
public boolean showAdvanced = false;
|
||||
|
||||
/** Current user navigation stack; empty implies recents. */
|
||||
public DocumentStack stack = new DocumentStack();
|
||||
@@ -733,6 +735,7 @@ public class DocumentsActivity extends Activity {
|
||||
out.writeInt(allowMultiple ? 1 : 0);
|
||||
out.writeInt(showSize ? 1 : 0);
|
||||
out.writeInt(localOnly ? 1 : 0);
|
||||
out.writeInt(showAdvanced ? 1 : 0);
|
||||
DurableUtils.writeToParcel(out, stack);
|
||||
out.writeString(currentSearch);
|
||||
}
|
||||
@@ -748,6 +751,7 @@ public class DocumentsActivity extends Activity {
|
||||
state.allowMultiple = in.readInt() != 0;
|
||||
state.showSize = in.readInt() != 0;
|
||||
state.localOnly = in.readInt() != 0;
|
||||
state.showAdvanced = in.readInt() != 0;
|
||||
DurableUtils.readFromParcel(in, state.stack);
|
||||
state.currentSearch = in.readString();
|
||||
return state;
|
||||
|
||||
@@ -78,6 +78,8 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
|
||||
return executor;
|
||||
}
|
||||
|
||||
private final List<RootInfo> mRoots;
|
||||
|
||||
private final HashMap<RootInfo, RecentTask> mTasks = Maps.newHashMap();
|
||||
|
||||
private final int mSortOrder = State.SORT_ORDER_LAST_MODIFIED;
|
||||
@@ -133,8 +135,9 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
|
||||
}
|
||||
}
|
||||
|
||||
public RecentLoader(Context context) {
|
||||
public RecentLoader(Context context, List<RootInfo> roots) {
|
||||
super(context);
|
||||
mRoots = roots;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -143,8 +146,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
|
||||
// First time through we kick off all the recent tasks, and wait
|
||||
// around to see if everyone finishes quickly.
|
||||
|
||||
final RootsCache roots = DocumentsApplication.getRootsCache(getContext());
|
||||
for (RootInfo root : roots.getRoots()) {
|
||||
for (RootInfo root : mRoots) {
|
||||
if ((root.flags & Root.FLAG_SUPPORTS_RECENTS) != 0) {
|
||||
final RecentTask task = new RecentTask(root.authority, root.rootId);
|
||||
mTasks.put(root, task);
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.provider.DocumentsContract.Document;
|
||||
import android.provider.DocumentsContract.Root;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.documentsui.DocumentsActivity.State;
|
||||
import com.android.documentsui.model.RootInfo;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.Objects;
|
||||
@@ -40,6 +41,7 @@ import com.google.android.collect.Lists;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -75,6 +77,7 @@ public class RootsCache {
|
||||
final RootInfo root = new RootInfo();
|
||||
root.rootType = Root.ROOT_TYPE_SHORTCUT;
|
||||
root.icon = R.drawable.ic_dir;
|
||||
root.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE;
|
||||
root.title = mContext.getString(R.string.root_recent);
|
||||
root.availableBytes = -1;
|
||||
|
||||
@@ -150,6 +153,60 @@ public class RootsCache {
|
||||
return mRoots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags that declare explicit content types.
|
||||
*/
|
||||
private static final int FLAGS_CONTENT_MASK = Root.FLAG_PROVIDES_IMAGES
|
||||
| Root.FLAG_PROVIDES_AUDIO | Root.FLAG_PROVIDES_VIDEO;
|
||||
|
||||
@GuardedBy("ActivityThread")
|
||||
public List<RootInfo> getMatchingRoots(State state) {
|
||||
|
||||
// Determine acceptable content flags
|
||||
int includeFlags = 0;
|
||||
for (String acceptMime : state.acceptMimes) {
|
||||
final String[] type = acceptMime.split("/");
|
||||
if (type.length != 2) continue;
|
||||
|
||||
if ("image".equals(type[0])) {
|
||||
includeFlags |= Root.FLAG_PROVIDES_IMAGES;
|
||||
} else if ("audio".equals(type[0])) {
|
||||
includeFlags |= Root.FLAG_PROVIDES_AUDIO;
|
||||
} else if ("video".equals(type[0])) {
|
||||
includeFlags |= Root.FLAG_PROVIDES_VIDEO;
|
||||
} else if ("*".equals(type[0])) {
|
||||
includeFlags |= Root.FLAG_PROVIDES_IMAGES | Root.FLAG_PROVIDES_AUDIO
|
||||
| Root.FLAG_PROVIDES_VIDEO;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<RootInfo> matching = Lists.newArrayList();
|
||||
for (RootInfo root : mRoots) {
|
||||
final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
|
||||
final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
|
||||
final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
|
||||
|
||||
// Exclude read-only devices when creating
|
||||
if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
|
||||
// Exclude advanced devices when not requested
|
||||
if (!state.showAdvanced && advanced) continue;
|
||||
// Exclude non-local devices when local only
|
||||
if (state.localOnly && !localOnly) continue;
|
||||
|
||||
if ((root.flags & FLAGS_CONTENT_MASK) != 0) {
|
||||
// This root offers specific content, so only include if the
|
||||
// caller asked for that content type.
|
||||
if ((root.flags & includeFlags) == 0) {
|
||||
// Sorry, no overlap.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
matching.add(root);
|
||||
}
|
||||
return matching;
|
||||
}
|
||||
|
||||
@GuardedBy("ActivityThread")
|
||||
public static Drawable resolveDocumentIcon(Context context, String mimeType) {
|
||||
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import static com.android.documentsui.DocumentsActivity.TAG;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
@@ -28,7 +26,6 @@ import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.provider.DocumentsContract.Root;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -39,6 +36,7 @@ import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.documentsui.DocumentsActivity.State;
|
||||
import com.android.documentsui.SectionedListAdapter.SectionAdapter;
|
||||
import com.android.documentsui.model.DocumentInfo;
|
||||
import com.android.documentsui.model.RootInfo;
|
||||
@@ -76,24 +74,31 @@ public class RootsFragment extends Fragment {
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final Context context = inflater.getContext();
|
||||
final RootsCache roots = DocumentsApplication.getRootsCache(context);
|
||||
|
||||
final View view = inflater.inflate(R.layout.fragment_roots, container, false);
|
||||
mList = (ListView) view.findViewById(android.R.id.list);
|
||||
mList.setOnItemClickListener(mItemListener);
|
||||
|
||||
final Intent includeApps = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
|
||||
mAdapter = new SectionedRootsAdapter(context, roots.getRoots(), includeApps);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
updateRootsAdapter();
|
||||
}
|
||||
|
||||
private void updateRootsAdapter() {
|
||||
final Context context = getActivity();
|
||||
mAdapter.updateVisible(SettingsActivity.getDisplayAdvancedDevices(context));
|
||||
|
||||
final State state = ((DocumentsActivity) context).getDisplayState();
|
||||
state.showAdvanced = SettingsActivity.getDisplayAdvancedDevices(context);
|
||||
|
||||
final RootsCache roots = DocumentsApplication.getRootsCache(context);
|
||||
final List<RootInfo> matchingRoots = roots.getMatchingRoots(state);
|
||||
final Intent includeApps = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
|
||||
|
||||
mAdapter = new SectionedRootsAdapter(context, matchingRoots, includeApps);
|
||||
mList.setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
@@ -211,18 +216,15 @@ public class RootsFragment extends Fragment {
|
||||
private final RootsAdapter mServices;
|
||||
private final RootsAdapter mShortcuts;
|
||||
private final RootsAdapter mDevices;
|
||||
private final RootsAdapter mDevicesAdvanced;
|
||||
private final AppsAdapter mApps;
|
||||
|
||||
public SectionedRootsAdapter(Context context, List<RootInfo> 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 (RootInfo root : roots) {
|
||||
Log.d(TAG, "Found rootType=" + root.rootType);
|
||||
switch (root.rootType) {
|
||||
case Root.ROOT_TYPE_SERVICE:
|
||||
mServices.add(root);
|
||||
@@ -231,10 +233,7 @@ public class RootsFragment extends Fragment {
|
||||
mShortcuts.add(root);
|
||||
break;
|
||||
case Root.ROOT_TYPE_DEVICE:
|
||||
mDevicesAdvanced.add(root);
|
||||
if ((root.flags & Root.FLAG_ADVANCED) == 0) {
|
||||
mDevices.add(root);
|
||||
}
|
||||
mDevices.add(root);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -256,23 +255,16 @@ public class RootsFragment extends Fragment {
|
||||
mServices.sort(comp);
|
||||
mShortcuts.sort(comp);
|
||||
mDevices.sort(comp);
|
||||
mDevicesAdvanced.sort(comp);
|
||||
}
|
||||
|
||||
public void updateVisible(boolean showAdvanced) {
|
||||
clearSections();
|
||||
if (mServices.getCount() > 0) {
|
||||
addSection(mServices);
|
||||
}
|
||||
if (mShortcuts.getCount() > 0) {
|
||||
addSection(mShortcuts);
|
||||
}
|
||||
|
||||
final RootsAdapter devices = showAdvanced ? mDevicesAdvanced : mDevices;
|
||||
if (devices.getCount() > 0) {
|
||||
addSection(devices);
|
||||
if (mDevices.getCount() > 0) {
|
||||
addSection(mDevices);
|
||||
}
|
||||
|
||||
if (mApps.getCount() > 0) {
|
||||
addSection(mApps);
|
||||
}
|
||||
@@ -282,6 +274,12 @@ public class RootsFragment extends Fragment {
|
||||
public static class RootComparator implements Comparator<RootInfo> {
|
||||
@Override
|
||||
public int compare(RootInfo lhs, RootInfo rhs) {
|
||||
if (lhs.authority == null) {
|
||||
return -1;
|
||||
} else if (rhs.authority == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
final int score = DocumentInfo.compareToIgnoreCaseNullable(lhs.title, rhs.title);
|
||||
if (score != 0) {
|
||||
return score;
|
||||
|
||||
@@ -32,7 +32,6 @@ import android.widget.TextView;
|
||||
import libcore.io.IoUtils;
|
||||
import libcore.io.Streams;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class TestActivity extends Activity {
|
||||
@@ -50,8 +49,11 @@ public class TestActivity extends Activity {
|
||||
view.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
final CheckBox multiple = new CheckBox(context);
|
||||
multiple.setText("ALLOW_MULTIPLE");
|
||||
multiple.setText("\nALLOW_MULTIPLE\n");
|
||||
view.addView(multiple);
|
||||
final CheckBox localOnly = new CheckBox(context);
|
||||
localOnly.setText("\nLOCAL_ONLY\n");
|
||||
view.addView(localOnly);
|
||||
|
||||
Button button;
|
||||
button = new Button(context);
|
||||
@@ -65,6 +67,9 @@ public class TestActivity extends Activity {
|
||||
if (multiple.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}
|
||||
if (localOnly.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
||||
}
|
||||
startActivityForResult(intent, 42);
|
||||
}
|
||||
});
|
||||
@@ -81,6 +86,28 @@ public class TestActivity extends Activity {
|
||||
if (multiple.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}
|
||||
if (localOnly.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
||||
}
|
||||
startActivityForResult(intent, 42);
|
||||
}
|
||||
});
|
||||
view.addView(button);
|
||||
|
||||
button = new Button(context);
|
||||
button.setText("OPEN_DOC audio/ogg");
|
||||
button.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("audio/ogg");
|
||||
if (multiple.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}
|
||||
if (localOnly.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
||||
}
|
||||
startActivityForResult(intent, 42);
|
||||
}
|
||||
});
|
||||
@@ -99,6 +126,9 @@ public class TestActivity extends Activity {
|
||||
if (multiple.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}
|
||||
if (localOnly.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
||||
}
|
||||
startActivityForResult(intent, 42);
|
||||
}
|
||||
});
|
||||
@@ -113,6 +143,9 @@ public class TestActivity extends Activity {
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(Intent.EXTRA_TITLE, "foobar.txt");
|
||||
if (localOnly.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
||||
}
|
||||
startActivityForResult(intent, 42);
|
||||
}
|
||||
});
|
||||
@@ -129,6 +162,9 @@ public class TestActivity extends Activity {
|
||||
if (multiple.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}
|
||||
if (localOnly.isChecked()) {
|
||||
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
||||
}
|
||||
startActivityForResult(Intent.createChooser(intent, "Kittens!"), 42);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -87,9 +87,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
final RootInfo root = new RootInfo();
|
||||
root.rootId = "primary";
|
||||
root.rootType = Root.ROOT_TYPE_DEVICE;
|
||||
root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
|
||||
| Root.FLAG_PROVIDES_AUDIO | Root.FLAG_PROVIDES_VIDEO
|
||||
| Root.FLAG_PROVIDES_IMAGES;
|
||||
root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED;
|
||||
root.icon = R.drawable.ic_pdf;
|
||||
root.title = getContext().getString(R.string.root_internal_storage);
|
||||
root.docId = getDocIdForFile(path);
|
||||
|
||||
Reference in New Issue
Block a user