diff options
7 files changed, 130 insertions, 33 deletions
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index c24341e4202f..5b23ca5956e8 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -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); diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index da790cc20d46..f569f5ae3e84 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -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; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java index 5f6fd1337598..756a29796039 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java @@ -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); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java index ac3b74089275..0b10f197f82b 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java @@ -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)) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java index 3102b8847271..ef3a31d86ee9 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java @@ -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; diff --git a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java index f6548e860fc5..2405cb576977 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java @@ -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); } }); diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index de8c29ad694c..bbe3b455f54c 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -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); |