Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6bba9e14 authored by Josh Simmons's avatar Josh Simmons
Browse files

Send search result limit to DocumentProvider when supported

Certain DocumentsProviders (eg. DownloadStorageProvider and
ExternalStorageProvider) now advertise on their Roots that they allow a
max result limit to be specified rather than choosing it themselves.

When this is advertised, specify the limit so that potentially matching
search results are not artificially left out by the DocumentsProvider.

Flag: com.android.documentsui.flags.use_search_v2_read_only
Bug: 414495650
Test: atest 'DocumentsUIGoogleTests:com.android.documentsui.loaders.SearchLoaderTest'
Change-Id: I00a52c365c879780a4a71ae18e1479c027190c3c
parent 618f7c68
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -1026,8 +1026,9 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA
            int maxResults = (root == null || root.isRecents())
                    ? RecentsLoader.MAX_DOCS_FROM_ROOT : MAX_RESULTS;
            QueryOptions options = new QueryOptions(
                    maxResults, lastModifiedDelta, Duration.ofMillis(MAX_SEARCH_TIME_MS),
                    mState.showHiddenFiles, mState.acceptMimes, mSearchMgr.buildQueryArgs());
                    maxResults, maxResults, lastModifiedDelta,
                    Duration.ofMillis(MAX_SEARCH_TIME_MS), mState.showHiddenFiles,
                    mState.acceptMimes, mSearchMgr.buildQueryArgs());

            if (stack.isRecents() || mSearchMgr.isSearching()) {
                Log.d(TAG, "Creating search loader V2");
+22 −3
Original line number Diff line number Diff line
@@ -22,7 +22,26 @@ package com.android.documentsui.base
 * interchangeably. Additionally the "folderId" is rootId for the RootInfo, but documentId for
 * DocumentInfo.
 */
data class FolderInfo(val folderId: String, val authority: String) {
    constructor(folder: DocumentInfo) : this(folder.documentId, folder.authority)
    constructor(rootInfo: RootInfo) : this(rootInfo.rootId, rootInfo.authority)
data class FolderInfo(
    val folderId: String,
    val authority: String,
    // Specifies whether the Root this folder exists on supports search result limiting: this can
    // help to find more search results (increasing the limit) or improve performance (decreasing
    // the limit). We could just send the limit regardless of whether the root says it supports this
    // but this allows SearchLoader to be judicious and not starting sending new parameters that
    // it hasn't done in the past.
    //
    // TODO(b:419704219) remove this property when RootInfo/DocumentInfo have a shared interface.
    val supportsSearchResultLimiting: Boolean
) {
    constructor(rootInfo: RootInfo) : this(
        rootInfo.rootId,
        rootInfo.authority,
        rootInfo.supportsSearchResultLimit()
    )
    constructor(folder: DocumentInfo, folderRoot: RootInfo) : this(
        folder.documentId,
        folder.authority,
        folderRoot.supportsSearchResultLimit()
    )
}
+9 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.android.documentsui.base.Shared.compareToIgnoreCaseNullable;
import static com.android.documentsui.base.SharedMinimal.VERBOSE;
import static com.android.documentsui.util.Material3Config.getRes;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
@@ -390,6 +391,14 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
        return queryArgs != null && queryArgs.contains(QUERY_ARG_MIME_TYPES);
    }

    /**
     * Returns true if the DocumentsProvider hosting this root supports us specifying a limit for
     * the maximum number of search results it should return.
     */
    public boolean supportsSearchResultLimit() {
        return queryArgs != null && queryArgs.contains(ContentResolver.QUERY_ARG_LIMIT);
    }

    public boolean supportsEject() {
        return (flags & Root.FLAG_SUPPORTS_EJECT) != 0;
    }
+16 −7
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.documentsui.loaders

import android.os.Bundle
import java.time.Duration
import java.util.Objects

/**
 * The constant to be used for the maxResults parameter, if we wish to get all (unlimited) results.
@@ -25,7 +26,11 @@ const val ALL_RESULTS: Int = -1

/**
 * Common query options. These are:
 *  - maximum number to return; pass ALL_RESULTS to impose no limits.
 *  - maximum number of results to return across all queried providers; pass ALL_RESULTS to impose
 *    no limits.
 *  - maximum number of results to return *per root*; pass ALL_RESULTS to impose no limits,
 *    and note that this only works for DocumentsProviders that support QUERY_ARG_LIMIT for queries
 *    on their Roots.
 *  - maximum lastModified delta in milliseconds: the delta from now used to reject files that were
 *    not modified in the specified milliseconds; pass null for no limits.
 *  - maximum time the query should return, including empty, results; pass null for no limits.
@@ -40,6 +45,7 @@ const val ALL_RESULTS: Int = -1
 */
data class QueryOptions(
    val maxResults: Int,
    val maxResultsPerRoot: Int,
    val maxLastModifiedDelta: Duration?,
    val maxQueryTime: Duration?,
    val showHidden: Boolean,
@@ -54,6 +60,7 @@ data class QueryOptions(
        other as QueryOptions

        return maxResults == other.maxResults &&
                maxResultsPerRoot == other.maxResultsPerRoot &&
                maxLastModifiedDelta == other.maxLastModifiedDelta &&
                maxQueryTime == other.maxQueryTime &&
                showHidden == other.showHidden &&
@@ -80,11 +87,13 @@ data class QueryOptions(
    fun isQueryTimeUnlimited() = maxQueryTime == null

    override fun hashCode(): Int {
        var result = maxResults
        result = 31 * result + maxLastModifiedDelta.hashCode()
        result = 31 * result + maxQueryTime.hashCode()
        result = 31 * result + showHidden.hashCode()
        result = 31 * result + acceptableMimeTypes.contentHashCode()
        return result
        return Objects.hash(
            maxResults,
            maxResultsPerRoot,
            maxLastModifiedDelta,
            maxQueryTime,
            showHidden,
            acceptableMimeTypes.contentHashCode()
        )
    }
}
+10 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.documentsui.loaders

import android.content.ContentResolver
import android.content.Context
import android.database.Cursor
import android.net.Uri
@@ -220,7 +221,10 @@ class SearchLoader(
            )
        }

    private fun createQueryArgs(rejectBeforeTimestamp: Long): Bundle {
    private fun createQueryArgs(
        rootSupportsSearchResultLimiting: Boolean,
        rejectBeforeTimestamp: Long
    ): Bundle {
        val queryArgs = Bundle()
        sortModel.addQuerySortArgs(queryArgs)
        if (rejectBeforeTimestamp > 0L) {
@@ -232,6 +236,9 @@ class SearchLoader(
        if (!TextUtils.isEmpty(query)) {
            queryArgs.putString(DocumentsContract.QUERY_ARG_DISPLAY_NAME, query)
        }
        if (rootSupportsSearchResultLimiting && options.maxResultsPerRoot > ALL_RESULTS) {
            queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, options.maxResultsPerRoot)
        }
        queryArgs.putAll(options.otherQueryArgs)
        return queryArgs
    }
@@ -251,7 +258,8 @@ class SearchLoader(
            }
            val rootSearchUri = createContentProviderQuery(folder)
            // TODO(b:385789236): Correctly pass sort order information.
            val queryArgs = createQueryArgs(rejectBeforeTimestamp)
            val queryArgs =
                createQueryArgs(folder.supportsSearchResultLimiting, rejectBeforeTimestamp)
            sortModel.addQuerySortArgs(queryArgs)
            if (DEBUG) {
                Log.d(TAG, "Query $rootSearchUri and queryArgs $queryArgs")
Loading