Loading src/com/android/documentsui/base/RootInfo.java +14 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.documentsui.base; import static android.provider.DocumentsContract.QUERY_ARG_MIME_TYPES; import static com.android.documentsui.base.DocumentInfo.getCursorInt; import static com.android.documentsui.base.DocumentInfo.getCursorLong; import static com.android.documentsui.base.DocumentInfo.getCursorString; Loading Loading @@ -55,6 +57,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { private static final int LOAD_FROM_CONTENT_RESOLVER = -1; // private static final int VERSION_INIT = 1; // Not used anymore private static final int VERSION_DROP_TYPE = 2; private static final int VERSION_SEARCH_TYPE = 3; // The values of these constants determine the sort order of various roots in the RootsFragment. @IntDef(flag = false, value = { Loading Loading @@ -91,6 +94,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { public String documentId; public long availableBytes; public String mimeTypes; public String queryArgs; /** Derived fields that aren't persisted */ public String[] derivedMimeTypes; Loading @@ -116,6 +120,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { availableBytes = -1; mimeTypes = null; ejecting = false; queryArgs = null; derivedMimeTypes = null; derivedIcon = 0; Loading @@ -126,6 +131,8 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { public void read(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_SEARCH_TYPE: queryArgs = DurableUtils.readNullableString(in); case VERSION_DROP_TYPE: authority = DurableUtils.readNullableString(in); rootId = DurableUtils.readNullableString(in); Loading @@ -145,7 +152,8 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public void write(DataOutputStream out) throws IOException { out.writeInt(VERSION_DROP_TYPE); out.writeInt(VERSION_SEARCH_TYPE); DurableUtils.writeNullableString(out, queryArgs); DurableUtils.writeNullableString(out, authority); DurableUtils.writeNullableString(out, rootId); out.writeInt(flags); Loading Loading @@ -192,6 +200,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { root.documentId = getCursorString(cursor, Root.COLUMN_DOCUMENT_ID); root.availableBytes = getCursorLong(cursor, Root.COLUMN_AVAILABLE_BYTES); root.mimeTypes = getCursorString(cursor, Root.COLUMN_MIME_TYPES); root.queryArgs = getCursorString(cursor, Root.COLUMN_QUERY_ARGS); root.deriveFields(); return root; } Loading Loading @@ -320,6 +329,10 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { return (flags & Root.FLAG_SUPPORTS_SEARCH) != 0; } public boolean supportsMimeTypesSearch() { return queryArgs != null && queryArgs.contains(QUERY_ARG_MIME_TYPES); } public boolean supportsEject() { return (flags & Root.FLAG_SUPPORTS_EJECT) != 0; } Loading src/com/android/documentsui/queries/SearchViewManager.java +2 −10 Original line number Diff line number Diff line Loading @@ -26,7 +26,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Root; import android.text.TextUtils; import android.util.Log; import android.view.Menu; Loading Loading @@ -244,7 +243,7 @@ public class SearchViewManager implements } final RootInfo root = stack != null ? stack.getRoot() : null; if (root == null || (root.flags & Root.FLAG_SUPPORTS_SEARCH) == 0) { if (root == null || !root.supportsSearch()) { supportsSearch = false; } Loading @@ -260,14 +259,7 @@ public class SearchViewManager implements // Recent root show open search bar, do not show duplicate search icon. mMenuItem.setVisible(supportsSearch && !stack.isRecents()); // Only Storage roots, Downloads root, media roots and recent root // support mime type query now. // TODO: b/121234248 add check for whether the root supports new search method. if (supportsSearch && !root.isDownloads() && !root.isStorage() && !root.isLibrary()) { supportsSearch = false; } mChipViewManager.setChipsRowVisible(supportsSearch); mChipViewManager.setChipsRowVisible(supportsSearch && root.supportsMimeTypesSearch()); } /** Loading src/com/android/documentsui/roots/ProvidersCache.java +3 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.documentsui.roots; import static android.provider.DocumentsContract.QUERY_ARG_MIME_TYPES; import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.VERBOSE; Loading Loading @@ -111,6 +113,7 @@ public class ProvidersCache implements ProvidersAccess { derivedIcon = R.drawable.ic_root_recent; derivedType = RootInfo.TYPE_RECENTS; flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_SEARCH; queryArgs = QUERY_ARG_MIME_TYPES; title = mContext.getString(R.string.root_recent); availableBytes = -1; }}; Loading tests/unit/com/android/documentsui/queries/SearchViewManagerTest.java +77 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,12 @@ package com.android.documentsui.queries; import static android.provider.DocumentsContract.QUERY_ARG_DISPLAY_NAME; import static android.provider.DocumentsContract.QUERY_ARG_FILE_SIZE_OVER; import static android.provider.DocumentsContract.QUERY_ARG_LAST_MODIFIED_AFTER; import static android.provider.DocumentsContract.QUERY_ARG_MIME_TYPES; import static android.provider.DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; import static com.android.documentsui.base.State.ACTION_GET_CONTENT; import static junit.framework.Assert.assertEquals; Loading @@ -23,22 +29,32 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.provider.DocumentsContract; import android.text.TextUtils; import android.view.ViewGroup; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.EventHandler; import com.android.documentsui.base.RootInfo; import com.android.documentsui.queries.SearchViewManager.SearchManagerListener; import com.android.documentsui.testing.TestEventHandler; import com.android.documentsui.testing.TestHandler; import com.android.documentsui.testing.TestMenu; import com.android.documentsui.testing.TestMenuItem; import com.android.documentsui.testing.TestTimer; import org.junit.Before; Loading @@ -57,6 +73,8 @@ public final class SearchViewManagerTest { private TestEventHandler<String> mTestEventHandler; private TestTimer mTestTimer; private TestHandler mTestHandler; private TestMenu mTestMenu; private TestMenuItem mSearchMenuItem; private SearchViewManager mSearchViewManager; private SearchChipViewManager mSearchChipViewManager; Loading Loading @@ -84,12 +102,13 @@ public final class SearchViewManagerTest { }; ViewGroup chipGroup = mock(ViewGroup.class); mSearchChipViewManager = new SearchChipViewManager(chipGroup); mSearchChipViewManager = spy(new SearchChipViewManager(chipGroup)); mSearchViewManager = new TestableSearchViewManager(searchListener, mTestEventHandler, mSearchChipViewManager, null /* savedState */, mTestTimer, mTestHandler); final TestMenu testMenu = TestMenu.create(); mSearchViewManager.install(testMenu, true); mTestMenu = TestMenu.create(); mSearchMenuItem = mTestMenu.findItem(R.id.option_menu_search); mSearchViewManager.install(mTestMenu, true); } private static class TestableSearchViewManager extends SearchViewManager { Loading Loading @@ -290,11 +309,65 @@ public final class SearchViewManagerTest { final Bundle queryArgs = mSearchViewManager.buildQueryArgs(); assertFalse(queryArgs.isEmpty()); final String[] mimeTypes = queryArgs.getStringArray(DocumentsContract.QUERY_ARG_MIME_TYPES); final String[] mimeTypes = queryArgs.getStringArray(QUERY_ARG_MIME_TYPES); assertTrue(mimeTypes.length > 0); assertEquals("image/*", mimeTypes[0]); } @Test public void testSupportsMimeTypesSearch_showChips() throws Exception { RootInfo root = spy(new RootInfo()); when(root.isRecents()).thenReturn(false); root.flags = FLAG_SUPPORTS_SEARCH; root.queryArgs = QUERY_ARG_MIME_TYPES; DocumentStack stack = new DocumentStack(root, new DocumentInfo()); mSearchViewManager.showMenu(stack); verify(mSearchChipViewManager, times(1)).setChipsRowVisible(true); } @Test public void testNotSupportsMimeTypesSearch_notShowChips() throws Exception { RootInfo root = spy(new RootInfo()); when(root.isRecents()).thenReturn(false); root.flags = FLAG_SUPPORTS_SEARCH; root.queryArgs = TextUtils.join("\n", new String[]{QUERY_ARG_DISPLAY_NAME, QUERY_ARG_FILE_SIZE_OVER, QUERY_ARG_LAST_MODIFIED_AFTER}); DocumentStack stack = new DocumentStack(root, new DocumentInfo()); mSearchViewManager.showMenu(stack); verify(mSearchChipViewManager, times(1)).setChipsRowVisible(false); } @Test public void testSupportsSearch_showMenu() throws Exception { RootInfo root = spy(new RootInfo()); when(root.isRecents()).thenReturn(false); root.flags = FLAG_SUPPORTS_SEARCH; DocumentStack stack = new DocumentStack(root, new DocumentInfo()); mSearchViewManager.showMenu(stack); assertTrue(mSearchMenuItem.isVisible()); } @Test public void testNotSupportsSearch_notShowMenuAndChips() throws Exception { RootInfo root = spy(new RootInfo()); when(root.isRecents()).thenReturn(false); root.queryArgs = QUERY_ARG_MIME_TYPES; DocumentStack stack = new DocumentStack(root, new DocumentInfo()); mSearchViewManager.install(mTestMenu, true); mSearchViewManager.showMenu(stack); assertFalse(mSearchMenuItem.isVisible()); verify(mSearchChipViewManager, times(1)).setChipsRowVisible(false); } private static Set<SearchChipData> getFakeSearchChipDataList() { final Set<SearchChipData> chipDataList = new HashSet<>(); chipDataList.add(new SearchChipData(0 /* chipType */, 0, new String[]{"image/*"})); Loading Loading
src/com/android/documentsui/base/RootInfo.java +14 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.documentsui.base; import static android.provider.DocumentsContract.QUERY_ARG_MIME_TYPES; import static com.android.documentsui.base.DocumentInfo.getCursorInt; import static com.android.documentsui.base.DocumentInfo.getCursorLong; import static com.android.documentsui.base.DocumentInfo.getCursorString; Loading Loading @@ -55,6 +57,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { private static final int LOAD_FROM_CONTENT_RESOLVER = -1; // private static final int VERSION_INIT = 1; // Not used anymore private static final int VERSION_DROP_TYPE = 2; private static final int VERSION_SEARCH_TYPE = 3; // The values of these constants determine the sort order of various roots in the RootsFragment. @IntDef(flag = false, value = { Loading Loading @@ -91,6 +94,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { public String documentId; public long availableBytes; public String mimeTypes; public String queryArgs; /** Derived fields that aren't persisted */ public String[] derivedMimeTypes; Loading @@ -116,6 +120,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { availableBytes = -1; mimeTypes = null; ejecting = false; queryArgs = null; derivedMimeTypes = null; derivedIcon = 0; Loading @@ -126,6 +131,8 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { public void read(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_SEARCH_TYPE: queryArgs = DurableUtils.readNullableString(in); case VERSION_DROP_TYPE: authority = DurableUtils.readNullableString(in); rootId = DurableUtils.readNullableString(in); Loading @@ -145,7 +152,8 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public void write(DataOutputStream out) throws IOException { out.writeInt(VERSION_DROP_TYPE); out.writeInt(VERSION_SEARCH_TYPE); DurableUtils.writeNullableString(out, queryArgs); DurableUtils.writeNullableString(out, authority); DurableUtils.writeNullableString(out, rootId); out.writeInt(flags); Loading Loading @@ -192,6 +200,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { root.documentId = getCursorString(cursor, Root.COLUMN_DOCUMENT_ID); root.availableBytes = getCursorLong(cursor, Root.COLUMN_AVAILABLE_BYTES); root.mimeTypes = getCursorString(cursor, Root.COLUMN_MIME_TYPES); root.queryArgs = getCursorString(cursor, Root.COLUMN_QUERY_ARGS); root.deriveFields(); return root; } Loading Loading @@ -320,6 +329,10 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { return (flags & Root.FLAG_SUPPORTS_SEARCH) != 0; } public boolean supportsMimeTypesSearch() { return queryArgs != null && queryArgs.contains(QUERY_ARG_MIME_TYPES); } public boolean supportsEject() { return (flags & Root.FLAG_SUPPORTS_EJECT) != 0; } Loading
src/com/android/documentsui/queries/SearchViewManager.java +2 −10 Original line number Diff line number Diff line Loading @@ -26,7 +26,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Root; import android.text.TextUtils; import android.util.Log; import android.view.Menu; Loading Loading @@ -244,7 +243,7 @@ public class SearchViewManager implements } final RootInfo root = stack != null ? stack.getRoot() : null; if (root == null || (root.flags & Root.FLAG_SUPPORTS_SEARCH) == 0) { if (root == null || !root.supportsSearch()) { supportsSearch = false; } Loading @@ -260,14 +259,7 @@ public class SearchViewManager implements // Recent root show open search bar, do not show duplicate search icon. mMenuItem.setVisible(supportsSearch && !stack.isRecents()); // Only Storage roots, Downloads root, media roots and recent root // support mime type query now. // TODO: b/121234248 add check for whether the root supports new search method. if (supportsSearch && !root.isDownloads() && !root.isStorage() && !root.isLibrary()) { supportsSearch = false; } mChipViewManager.setChipsRowVisible(supportsSearch); mChipViewManager.setChipsRowVisible(supportsSearch && root.supportsMimeTypesSearch()); } /** Loading
src/com/android/documentsui/roots/ProvidersCache.java +3 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.documentsui.roots; import static android.provider.DocumentsContract.QUERY_ARG_MIME_TYPES; import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.VERBOSE; Loading Loading @@ -111,6 +113,7 @@ public class ProvidersCache implements ProvidersAccess { derivedIcon = R.drawable.ic_root_recent; derivedType = RootInfo.TYPE_RECENTS; flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_SEARCH; queryArgs = QUERY_ARG_MIME_TYPES; title = mContext.getString(R.string.root_recent); availableBytes = -1; }}; Loading
tests/unit/com/android/documentsui/queries/SearchViewManagerTest.java +77 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,12 @@ package com.android.documentsui.queries; import static android.provider.DocumentsContract.QUERY_ARG_DISPLAY_NAME; import static android.provider.DocumentsContract.QUERY_ARG_FILE_SIZE_OVER; import static android.provider.DocumentsContract.QUERY_ARG_LAST_MODIFIED_AFTER; import static android.provider.DocumentsContract.QUERY_ARG_MIME_TYPES; import static android.provider.DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; import static com.android.documentsui.base.State.ACTION_GET_CONTENT; import static junit.framework.Assert.assertEquals; Loading @@ -23,22 +29,32 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.provider.DocumentsContract; import android.text.TextUtils; import android.view.ViewGroup; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.EventHandler; import com.android.documentsui.base.RootInfo; import com.android.documentsui.queries.SearchViewManager.SearchManagerListener; import com.android.documentsui.testing.TestEventHandler; import com.android.documentsui.testing.TestHandler; import com.android.documentsui.testing.TestMenu; import com.android.documentsui.testing.TestMenuItem; import com.android.documentsui.testing.TestTimer; import org.junit.Before; Loading @@ -57,6 +73,8 @@ public final class SearchViewManagerTest { private TestEventHandler<String> mTestEventHandler; private TestTimer mTestTimer; private TestHandler mTestHandler; private TestMenu mTestMenu; private TestMenuItem mSearchMenuItem; private SearchViewManager mSearchViewManager; private SearchChipViewManager mSearchChipViewManager; Loading Loading @@ -84,12 +102,13 @@ public final class SearchViewManagerTest { }; ViewGroup chipGroup = mock(ViewGroup.class); mSearchChipViewManager = new SearchChipViewManager(chipGroup); mSearchChipViewManager = spy(new SearchChipViewManager(chipGroup)); mSearchViewManager = new TestableSearchViewManager(searchListener, mTestEventHandler, mSearchChipViewManager, null /* savedState */, mTestTimer, mTestHandler); final TestMenu testMenu = TestMenu.create(); mSearchViewManager.install(testMenu, true); mTestMenu = TestMenu.create(); mSearchMenuItem = mTestMenu.findItem(R.id.option_menu_search); mSearchViewManager.install(mTestMenu, true); } private static class TestableSearchViewManager extends SearchViewManager { Loading Loading @@ -290,11 +309,65 @@ public final class SearchViewManagerTest { final Bundle queryArgs = mSearchViewManager.buildQueryArgs(); assertFalse(queryArgs.isEmpty()); final String[] mimeTypes = queryArgs.getStringArray(DocumentsContract.QUERY_ARG_MIME_TYPES); final String[] mimeTypes = queryArgs.getStringArray(QUERY_ARG_MIME_TYPES); assertTrue(mimeTypes.length > 0); assertEquals("image/*", mimeTypes[0]); } @Test public void testSupportsMimeTypesSearch_showChips() throws Exception { RootInfo root = spy(new RootInfo()); when(root.isRecents()).thenReturn(false); root.flags = FLAG_SUPPORTS_SEARCH; root.queryArgs = QUERY_ARG_MIME_TYPES; DocumentStack stack = new DocumentStack(root, new DocumentInfo()); mSearchViewManager.showMenu(stack); verify(mSearchChipViewManager, times(1)).setChipsRowVisible(true); } @Test public void testNotSupportsMimeTypesSearch_notShowChips() throws Exception { RootInfo root = spy(new RootInfo()); when(root.isRecents()).thenReturn(false); root.flags = FLAG_SUPPORTS_SEARCH; root.queryArgs = TextUtils.join("\n", new String[]{QUERY_ARG_DISPLAY_NAME, QUERY_ARG_FILE_SIZE_OVER, QUERY_ARG_LAST_MODIFIED_AFTER}); DocumentStack stack = new DocumentStack(root, new DocumentInfo()); mSearchViewManager.showMenu(stack); verify(mSearchChipViewManager, times(1)).setChipsRowVisible(false); } @Test public void testSupportsSearch_showMenu() throws Exception { RootInfo root = spy(new RootInfo()); when(root.isRecents()).thenReturn(false); root.flags = FLAG_SUPPORTS_SEARCH; DocumentStack stack = new DocumentStack(root, new DocumentInfo()); mSearchViewManager.showMenu(stack); assertTrue(mSearchMenuItem.isVisible()); } @Test public void testNotSupportsSearch_notShowMenuAndChips() throws Exception { RootInfo root = spy(new RootInfo()); when(root.isRecents()).thenReturn(false); root.queryArgs = QUERY_ARG_MIME_TYPES; DocumentStack stack = new DocumentStack(root, new DocumentInfo()); mSearchViewManager.install(mTestMenu, true); mSearchViewManager.showMenu(stack); assertFalse(mSearchMenuItem.isVisible()); verify(mSearchChipViewManager, times(1)).setChipsRowVisible(false); } private static Set<SearchChipData> getFakeSearchChipDataList() { final Set<SearchChipData> chipDataList = new HashSet<>(); chipDataList.add(new SearchChipData(0 /* chipType */, 0, new String[]{"image/*"})); Loading