Loading src/com/android/documentsui/loaders/SearchLoader.kt +10 −2 Original line number Original line Diff line number Diff line Loading @@ -165,6 +165,7 @@ class SearchLoader( } } // Step 4: Collect cursors from done tasks. // Step 4: Collect cursors from done tasks. var allDone = true val cursorList = mutableListOf<Cursor>() val cursorList = mutableListOf<Cursor>() for (task in mSearchTaskList) { for (task in mSearchTaskList) { if (DEBUG) { if (DEBUG) { Loading @@ -175,7 +176,9 @@ class SearchLoader( } } // TODO(b:388336095): Record a metric for each done and not done task. // TODO(b:388336095): Record a metric for each done and not done task. val cursor = task.cursor 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. // TODO(b:388336095): Record a metric for null and not null cursor. if (DEBUG) { if (DEBUG) { Log.d(TAG, "Task ${task.taskId} has ${cursor.count} results") Log.d(TAG, "Task ${task.taskId} has ${cursor.count} results") Loading @@ -188,7 +191,12 @@ class SearchLoader( } } // Step 5: Assign the cursor, after adding filtering and sorting, to the results. // 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) mergedCursor.registerContentObserver(observer) val filteringCursor = FilteringCursorWrapper(mergedCursor) val filteringCursor = FilteringCursorWrapper(mergedCursor) filteringCursor.filterHiddenFiles(options.showHidden) filteringCursor.filterHiddenFiles(options.showHidden) Loading src/com/android/documentsui/roots/RootCursorWrapper.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -16,14 +16,14 @@ package com.android.documentsui.roots; package com.android.documentsui.roots; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import android.database.AbstractCursor; import android.database.AbstractCursor; import android.database.ContentObserver; import android.database.ContentObserver; import android.database.Cursor; import android.database.Cursor; import android.os.Bundle; import android.os.Bundle; import android.util.Log; import android.util.Log; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import com.android.documentsui.base.UserId; import com.android.documentsui.base.UserId; /** /** Loading Loading @@ -92,6 +92,11 @@ public class RootCursorWrapper extends AbstractCursor { return extras; return extras; } } @Override public void setExtras(Bundle bundle) { mCursor.setExtras(bundle); } @Override @Override public void close() { public void close() { super.close(); super.close(); Loading tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt +35 −0 Original line number Original line Diff line number Diff line Loading @@ -272,5 +272,40 @@ class SearchLoaderTest { "document-$index.png" "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, TestProvidersAccess.PICKLES.supportsSearchResultLimit(), ), ) val loader = SearchLoader( mActivity, listOf(TestProvidersAccess.PICKLES.userId, TestProvidersAccess.HOME.userId), TestFileTypeLookup(), mContentObserver, folderInfo, "document", QueryOptions(10, ALL_RESULTS, 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() } } } } } tests/unit/com/android/documentsui/roots/RootCursorWrapperTest.kt 0 → 100644 +82 −0 Original line number Original line 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) } } Loading
src/com/android/documentsui/loaders/SearchLoader.kt +10 −2 Original line number Original line Diff line number Diff line Loading @@ -165,6 +165,7 @@ class SearchLoader( } } // Step 4: Collect cursors from done tasks. // Step 4: Collect cursors from done tasks. var allDone = true val cursorList = mutableListOf<Cursor>() val cursorList = mutableListOf<Cursor>() for (task in mSearchTaskList) { for (task in mSearchTaskList) { if (DEBUG) { if (DEBUG) { Loading @@ -175,7 +176,9 @@ class SearchLoader( } } // TODO(b:388336095): Record a metric for each done and not done task. // TODO(b:388336095): Record a metric for each done and not done task. val cursor = task.cursor 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. // TODO(b:388336095): Record a metric for null and not null cursor. if (DEBUG) { if (DEBUG) { Log.d(TAG, "Task ${task.taskId} has ${cursor.count} results") Log.d(TAG, "Task ${task.taskId} has ${cursor.count} results") Loading @@ -188,7 +191,12 @@ class SearchLoader( } } // Step 5: Assign the cursor, after adding filtering and sorting, to the results. // 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) mergedCursor.registerContentObserver(observer) val filteringCursor = FilteringCursorWrapper(mergedCursor) val filteringCursor = FilteringCursorWrapper(mergedCursor) filteringCursor.filterHiddenFiles(options.showHidden) filteringCursor.filterHiddenFiles(options.showHidden) Loading
src/com/android/documentsui/roots/RootCursorWrapper.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -16,14 +16,14 @@ package com.android.documentsui.roots; package com.android.documentsui.roots; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import android.database.AbstractCursor; import android.database.AbstractCursor; import android.database.ContentObserver; import android.database.ContentObserver; import android.database.Cursor; import android.database.Cursor; import android.os.Bundle; import android.os.Bundle; import android.util.Log; import android.util.Log; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import com.android.documentsui.base.UserId; import com.android.documentsui.base.UserId; /** /** Loading Loading @@ -92,6 +92,11 @@ public class RootCursorWrapper extends AbstractCursor { return extras; return extras; } } @Override public void setExtras(Bundle bundle) { mCursor.setExtras(bundle); } @Override @Override public void close() { public void close() { super.close(); super.close(); Loading
tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt +35 −0 Original line number Original line Diff line number Diff line Loading @@ -272,5 +272,40 @@ class SearchLoaderTest { "document-$index.png" "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, TestProvidersAccess.PICKLES.supportsSearchResultLimit(), ), ) val loader = SearchLoader( mActivity, listOf(TestProvidersAccess.PICKLES.userId, TestProvidersAccess.HOME.userId), TestFileTypeLookup(), mContentObserver, folderInfo, "document", QueryOptions(10, ALL_RESULTS, 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() } } } } }
tests/unit/com/android/documentsui/roots/RootCursorWrapperTest.kt 0 → 100644 +82 −0 Original line number Original line 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) } }