Merge "Fix roots filtering for move operations." into nyc-dev

This commit is contained in:
Steve McKay
2016-03-02 01:33:31 +00:00
committed by Android (Google) Code Review
2 changed files with 114 additions and 60 deletions

View File

@@ -17,7 +17,6 @@
package com.android.documentsui; package com.android.documentsui;
import static com.android.documentsui.Shared.DEBUG; import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.TAG;
import android.content.ContentProviderClient; import android.content.ContentProviderClient;
import android.content.ContentResolver; import android.content.ContentResolver;
@@ -62,6 +61,8 @@ public class RootsCache {
public static final Uri sNotificationUri = Uri.parse( public static final Uri sNotificationUri = Uri.parse(
"content://com.android.documentsui.roots/"); "content://com.android.documentsui.roots/");
private static final String TAG = "RootsCache";
private final Context mContext; private final Context mContext;
private final ContentObserver mObserver; private final ContentObserver mObserver;
private OnCacheUpdateListener mCacheUpdateListener; private OnCacheUpdateListener mCacheUpdateListener;
@@ -417,25 +418,56 @@ public class RootsCache {
static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) { static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
final List<RootInfo> matching = new ArrayList<>(); final List<RootInfo> matching = new ArrayList<>();
for (RootInfo root : roots) { for (RootInfo root : roots) {
// Exclude read-only devices when creating
if (state.action == State.ACTION_CREATE && !root.supportsCreate()) continue; if (DEBUG) Log.d(TAG, "Evaluating " + root);
if (state.action == State.ACTION_CREATE && !root.supportsCreate()) {
if (DEBUG) Log.d(TAG, "Excluding read-only root because: ACTION_CREATE.");
continue;
}
if (state.action == State.ACTION_PICK_COPY_DESTINATION if (state.action == State.ACTION_PICK_COPY_DESTINATION
&& !root.supportsCreate()) continue; && !root.supportsCreate()) {
// Exclude roots that don't support directory picking if (DEBUG) Log.d(
if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) continue; TAG, "Excluding read-only root because: ACTION_PICK_COPY_DESTINATION.");
// Exclude advanced devices when not requested continue;
if (!state.showAdvanced && root.isAdvanced()) continue; }
if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) {
if (DEBUG) Log.d(
TAG, "Excluding root !supportsChildren because: ACTION_OPEN_TREE.");
continue;
}
if (!state.showAdvanced && root.isAdvanced()) {
if (DEBUG) Log.d(TAG, "Excluding root because: unwanted advanced device.");
continue;
}
// Exclude non-local devices when local only // Exclude non-local devices when local only
if (state.localOnly && !root.isLocalOnly()) continue; if (state.localOnly && !root.isLocalOnly()) {
if (DEBUG) Log.d(TAG, "Excluding root because: unwanted non-local device.");
continue;
}
// Exclude downloads roots as it doesn't support directory creation (actually // Exclude downloads roots as it doesn't support directory creation (actually
// we just don't show them). // we just don't show them).
// TODO: Add flag to check the root supports directory creation. // TODO: Add flag to check the root supports directory creation.
if (state.directoryCopy && !root.isDownloads()) continue; if (state.directoryCopy && root.isDownloads()) {
if (DEBUG) Log.d(
TAG, "Excluding downloads root because: unsupported directory copy.");
continue;
}
// Only show empty roots when creating, or in browse mode. // Only show empty roots when creating, or in browse mode.
if (root.isEmpty() && (state.action == State.ACTION_OPEN if (state.action == State.ACTION_OPEN && root.isEmpty()) {
|| state.action == State.ACTION_GET_CONTENT)) { if (DEBUG) Log.d(TAG, "Excluding empty root because: ACTION_OPEN.");
if (DEBUG) Log.i(TAG, "Skipping empty root: " + root); continue;
}
// Only show empty roots when creating, or in browse mode.
if (state.action == State.ACTION_GET_CONTENT && root.isEmpty()) {
if (DEBUG) Log.d(TAG, "Excluding empty root because: ACTION_GET_CONTENT.");
continue; continue;
} }
@@ -444,18 +476,19 @@ public class RootsCache {
MimePredicate.mimeMatches(root.derivedMimeTypes, state.acceptMimes) || MimePredicate.mimeMatches(root.derivedMimeTypes, state.acceptMimes) ||
MimePredicate.mimeMatches(state.acceptMimes, root.derivedMimeTypes); MimePredicate.mimeMatches(state.acceptMimes, root.derivedMimeTypes);
if (!overlap) { if (!overlap) {
if (DEBUG) Log.d(
TAG, "Excluding root because: unsupported content types > "
+ state.acceptMimes);
continue; continue;
} }
// Exclude roots from the calling package. // Exclude roots from the calling package.
if (state.excludedAuthorities.contains(root.authority)) { if (state.excludedAuthorities.contains(root.authority)) {
if (DEBUG) Log.d( if (DEBUG) Log.d(TAG, "Excluding root because: calling package.");
TAG, "Excluding root " + root.authority + " from calling package.");
continue; continue;
} }
if (DEBUG) Log.d( if (DEBUG) Log.d(TAG, "Including " + root);
TAG, "Including root " + root + " in roots list.");
matching.add(root); matching.add(root);
} }
return matching; return matching;

View File

@@ -16,6 +16,9 @@
package com.android.documentsui; package com.android.documentsui;
import static com.android.documentsui.RootsCache.getMatchingRoots;
import static com.google.common.collect.Lists.newArrayList;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
@@ -28,23 +31,18 @@ import java.util.List;
@SmallTest @SmallTest
public class RootsCacheTest extends AndroidTestCase { public class RootsCacheTest extends AndroidTestCase {
private static RootInfo buildForMimeTypes(String... mimeTypes) { private static RootInfo mNull = new RootInfo();
final RootInfo root = new RootInfo(); private static RootInfo mEmpty = buildForMimeTypes();
root.derivedMimeTypes = mimeTypes; private static RootInfo mWild = buildForMimeTypes("*/*");
return root; private static RootInfo mImages = buildForMimeTypes("image/*");
} private static RootInfo mAudio = buildForMimeTypes(
"audio/*", "application/ogg", "application/x-flac");
private static RootInfo mDocs = buildForMimeTypes(
"application/msword", "application/vnd.ms-excel");
private static RootInfo mMalformed1 = buildForMimeTypes("meow");
private static RootInfo mMalformed2 = buildForMimeTypes("*/meow");
private RootInfo mNull = new RootInfo(); private List<RootInfo> mRoots;
private RootInfo mEmpty = buildForMimeTypes();
private RootInfo mWild = buildForMimeTypes("*/*");
private RootInfo mImages = buildForMimeTypes("image/*");
private RootInfo mAudio = buildForMimeTypes("audio/*", "application/ogg", "application/x-flac");
private RootInfo mDocs = buildForMimeTypes("application/msword", "application/vnd.ms-excel");
private RootInfo mMalformed1 = buildForMimeTypes("meow");
private RootInfo mMalformed2 = buildForMimeTypes("*/meow");
private List<RootInfo> mRoots = Lists.newArrayList(
mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2);
private State mState; private State mState;
@@ -52,70 +50,87 @@ public class RootsCacheTest extends AndroidTestCase {
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
mRoots = Lists.newArrayList(
mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2);
mState = new State(); mState = new State();
mState.action = State.ACTION_OPEN; mState.action = State.ACTION_OPEN;
mState.showAdvanced = true; mState.showAdvanced = true;
mState.localOnly = false; mState.localOnly = false;
} }
public void testMatchingRootsEverything() throws Exception { public void testMatchingRoots_Everything() throws Exception {
mState.acceptMimes = new String[] { "*/*" }; mState.acceptMimes = new String[] { "*/*" };
assertContainsExactly( assertContainsExactly(
Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2), newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
RootsCache.getMatchingRoots(mRoots, mState)); getMatchingRoots(mRoots, mState));
} }
public void testMatchingRootsPngOrWild() throws Exception { public void testMatchingRoots_DirectoryCopy() throws Exception {
RootInfo downloads = buildForMimeTypes("*/*");
downloads.authority = "com.android.providers.downloads.documents";
mRoots.add(downloads);
mState.acceptMimes = new String[] { "*/*" };
mState.directoryCopy = true;
// basically we're asserting that the results don't contain downloads
assertContainsExactly(
newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
getMatchingRoots(mRoots, mState));
}
public void testMatchingRoots_PngOrWild() throws Exception {
mState.acceptMimes = new String[] { "image/png", "*/*" }; mState.acceptMimes = new String[] { "image/png", "*/*" };
assertContainsExactly( assertContainsExactly(
Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2), newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
RootsCache.getMatchingRoots(mRoots, mState)); getMatchingRoots(mRoots, mState));
} }
public void testMatchingRootsAudioWild() throws Exception { public void testMatchingRoots_AudioWild() throws Exception {
mState.acceptMimes = new String[] { "audio/*" }; mState.acceptMimes = new String[] { "audio/*" };
assertContainsExactly( assertContainsExactly(
Lists.newArrayList(mNull, mWild, mAudio), newArrayList(mNull, mWild, mAudio),
RootsCache.getMatchingRoots(mRoots, mState)); getMatchingRoots(mRoots, mState));
} }
public void testMatchingRootsAudioWildOrImageWild() throws Exception { public void testMatchingRoots_AudioWildOrImageWild() throws Exception {
mState.acceptMimes = new String[] { "audio/*", "image/*" }; mState.acceptMimes = new String[] { "audio/*", "image/*" };
assertContainsExactly( assertContainsExactly(
Lists.newArrayList(mNull, mWild, mAudio, mImages), newArrayList(mNull, mWild, mAudio, mImages),
RootsCache.getMatchingRoots(mRoots, mState)); getMatchingRoots(mRoots, mState));
} }
public void testMatchingRootsAudioSpecific() throws Exception { public void testMatchingRoots_AudioSpecific() throws Exception {
mState.acceptMimes = new String[] { "audio/mpeg" }; mState.acceptMimes = new String[] { "audio/mpeg" };
assertContainsExactly( assertContainsExactly(
Lists.newArrayList(mNull, mWild, mAudio), newArrayList(mNull, mWild, mAudio),
RootsCache.getMatchingRoots(mRoots, mState)); getMatchingRoots(mRoots, mState));
} }
public void testMatchingRootsDocument() throws Exception { public void testMatchingRoots_Document() throws Exception {
mState.acceptMimes = new String[] { "application/msword" }; mState.acceptMimes = new String[] { "application/msword" };
assertContainsExactly( assertContainsExactly(
Lists.newArrayList(mNull, mWild, mDocs), newArrayList(mNull, mWild, mDocs),
RootsCache.getMatchingRoots(mRoots, mState)); getMatchingRoots(mRoots, mState));
} }
public void testMatchingRootsApplication() throws Exception { public void testMatchingRoots_Application() throws Exception {
mState.acceptMimes = new String[] { "application/*" }; mState.acceptMimes = new String[] { "application/*" };
assertContainsExactly( assertContainsExactly(
Lists.newArrayList(mNull, mWild, mAudio, mDocs), newArrayList(mNull, mWild, mAudio, mDocs),
RootsCache.getMatchingRoots(mRoots, mState)); getMatchingRoots(mRoots, mState));
} }
public void testMatchingRootsFlacOrPng() throws Exception { public void testMatchingRoots_FlacOrPng() throws Exception {
mState.acceptMimes = new String[] { "application/x-flac", "image/png" }; mState.acceptMimes = new String[] { "application/x-flac", "image/png" };
assertContainsExactly( assertContainsExactly(
Lists.newArrayList(mNull, mWild, mAudio, mImages), newArrayList(mNull, mWild, mAudio, mImages),
RootsCache.getMatchingRoots(mRoots, mState)); getMatchingRoots(mRoots, mState));
} }
public void testExcludedAuthorities() throws Exception { public void testExcludedAuthorities() throws Exception {
final List<RootInfo> roots = Lists.newArrayList(); final List<RootInfo> roots = newArrayList();
// Set up some roots // Set up some roots
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
@@ -124,7 +139,7 @@ public class RootsCacheTest extends AndroidTestCase {
roots.add(root); roots.add(root);
} }
// Make some allowed authorities // Make some allowed authorities
List<RootInfo> allowedRoots = Lists.newArrayList( List<RootInfo> allowedRoots = newArrayList(
roots.get(0), roots.get(2), roots.get(4)); roots.get(0), roots.get(2), roots.get(4));
// Set up the excluded authority list // Set up the excluded authority list
for (RootInfo root: roots) { for (RootInfo root: roots) {
@@ -136,7 +151,7 @@ public class RootsCacheTest extends AndroidTestCase {
assertContainsExactly( assertContainsExactly(
allowedRoots, allowedRoots,
RootsCache.getMatchingRoots(roots, mState)); getMatchingRoots(roots, mState));
} }
private static void assertContainsExactly(List<?> expected, List<?> actual) { private static void assertContainsExactly(List<?> expected, List<?> actual) {
@@ -145,4 +160,10 @@ public class RootsCacheTest extends AndroidTestCase {
assertTrue(actual.contains(o)); assertTrue(actual.contains(o));
} }
} }
private static RootInfo buildForMimeTypes(String... mimeTypes) {
final RootInfo root = new RootInfo();
root.derivedMimeTypes = mimeTypes;
return root;
}
} }