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:
Jeff Sharkey
2013-09-02 20:55:12 -07:00
committed by Android Git Automerger
7 changed files with 130 additions and 33 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)) {

View File

@@ -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;

View File

@@ -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);
}
});

View File

@@ -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);