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

Commit 0d6fc0de authored by Bo Majewski's avatar Bo Majewski
Browse files

[DocsUI, Search]: Add extras about slow search.

Collects information about cursors being ready. Records it in the extras
of the search cursor. Adds the test. Fixes RootCursorWrapper to
correctly handle extras. Adds tests for RootCursorWrapper to confirm the
fix and core RootCursorWrapper properties.

Bug: 417818526
Test: m DocumentsUIGoogle
Flag: com.android.documentsui.flags.use_search_v2_read_only
Change-Id: If5296fed706ca06d95c74aabcd9f27400cdd125b
parent c8f5434e
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -164,6 +164,7 @@ class SearchLoader(
        }

        // Step 4: Collect cursors from done tasks.
        var allDone = true
        val cursorList = mutableListOf<Cursor>()
        for (task in mSearchTaskList) {
            if (DEBUG) {
@@ -174,7 +175,9 @@ class SearchLoader(
            }
            // TODO(b:388336095): Record a metric for each done and not done task.
            val cursor = task.cursor
            if (task.isDone && cursor != null) {
            if (!task.isDone) {
                allDone = false
            } else if (cursor != null) {
                // TODO(b:388336095): Record a metric for null and not null cursor.
                if (DEBUG) {
                    Log.d(TAG, "Task ${task.taskId} has ${cursor.count} results")
@@ -187,7 +190,12 @@ class SearchLoader(
        }

        // Step 5: Assign the cursor, after adding filtering and sorting, to the results.
        val mergedCursor = toSingleCursor(cursorList)
        val cursorExtras = Bundle().apply {
            putBoolean(DocumentsContract.EXTRA_LOADING, !allDone)
        }
        val mergedCursor = toSingleCursor(cursorList).apply {
            setExtras(cursorExtras)
        }
        mergedCursor.registerContentObserver(observer)
        val filteringCursor = FilteringCursorWrapper(mergedCursor)
        filteringCursor.filterHiddenFiles(options.showHidden)
+7 −2
Original line number Diff line number Diff line
@@ -16,14 +16,14 @@

package com.android.documentsui.roots;

import static com.android.documentsui.base.SharedMinimal.VERBOSE;

import android.database.AbstractCursor;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;

import static com.android.documentsui.base.SharedMinimal.VERBOSE;

import com.android.documentsui.base.UserId;

/**
@@ -92,6 +92,11 @@ public class RootCursorWrapper extends AbstractCursor {
        return extras;
    }

    @Override
    public void setExtras(Bundle bundle) {
        mCursor.setExtras(bundle);
    }

    @Override
    public void close() {
        super.close();
+34 −0
Original line number Diff line number Diff line
@@ -218,5 +218,39 @@ class SearchLoaderTest {
                "document-$index.png"
            })
        }

        @Test
        fun testExtraArgs() {
            mEnv.mockProviders.apply {
                get(TestProvidersAccess.PICKLES.authority)!!.setNextChildDocumentsReturns(
                    *generateDocuments(2, 1, arrayOf("png", "avi"))
                )
            }
            val folderInfo = listOf(
                FolderInfo(
                    TestProvidersAccess.PICKLES.rootId,
                    TestProvidersAccess.PICKLES.authority
                ),
            )
            val loader = SearchLoader(
                mActivity,
                listOf(TestProvidersAccess.PICKLES.userId, TestProvidersAccess.HOME.userId),
                TestFileTypeLookup(),
                mContentObserver,
                folderInfo,
                "document",
                QueryOptions(10, null, null, false, arrayOf("image/png"), Bundle()),
                mEnv.state.sortModel,
                mExecutor,
            )
            val result = loader.loadInBackground()
            expect.that(result!!.cursor).isNotNull()
            val extras = result.cursor.extras
            expect.that(extras).isNotNull()
            expect.that(extras.containsKey(DocumentsContract.EXTRA_LOADING)).isTrue()
            // TODO(417818526): Add ability to force mock providers to be extra slow, so that
            // we can test for the case when they do not finish on time.
            expect.that(extras.getBoolean(DocumentsContract.EXTRA_LOADING)).isFalse()
        }
    }
}
+82 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.documentsui.roots

import android.database.MatrixCursor
import android.os.Bundle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.documentsui.base.UserId
import com.google.common.truth.Expect
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
@SmallTest
class RootCursorWrapperTest {
    @get:Rule
    val expect: Expect = Expect.create()

    val baseCursor = MatrixCursor(arrayOf("column-a", "column-b"))
    val rootCursor =
        RootCursorWrapper(UserId.CURRENT_USER, "com.example.authority", "root-id", baseCursor, 10)

    @Before
    fun setUp() {
        baseCursor.newRow().add(0, "column-a-value").add(1, 1)
    }

    @Test
    fun testSetExtras() {
        expect.that(rootCursor.extras.isEmpty).isTrue()
        rootCursor.extras = Bundle().apply {
            putString("key", "value")
        }
        expect.that(rootCursor.extras.isEmpty).isFalse()
        expect.that(rootCursor.extras.containsKey("key")).isTrue()
        expect.that(rootCursor.extras.getString("key")).isEqualTo("value")
        rootCursor.extras.putString("key", "different-value")
        expect.that(rootCursor.extras.getString("key")).isEqualTo("different-value")

        // Setting extras (via setExtras() method) swaps null for an empty bundle.
        rootCursor.extras = null
        expect.that(rootCursor.extras).isNotNull()
        expect.that(rootCursor.extras.isEmpty).isTrue()
    }

    @Test
    fun testRootId() {
        val rootIdColumnIndex = rootCursor.getColumnIndex(RootCursorWrapper.COLUMN_ROOT_ID)
        expect.that(rootIdColumnIndex).isGreaterThan(-1)
        expect.that(rootCursor.getString(rootIdColumnIndex)).isEqualTo("root-id")
    }

    @Test
    fun testAuthority() {
        val authorityColumnIndex = rootCursor.getColumnIndex(RootCursorWrapper.COLUMN_AUTHORITY)
        expect.that(authorityColumnIndex).isGreaterThan(-1)
        expect.that(rootCursor.getString(authorityColumnIndex)).isEqualTo("com.example.authority")
    }

    @Test
    fun testUserId() {
        val userIdColumnIndex = rootCursor.getColumnIndex(RootCursorWrapper.COLUMN_USER_ID)
        expect.that(userIdColumnIndex).isGreaterThan(-1)
        expect.that(rootCursor.getInt(userIdColumnIndex)).isEqualTo(UserId.CURRENT_USER.identifier)
    }
}