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

Commit 0566b412 authored by Binyi Wu's avatar Binyi Wu
Browse files

Add row-based API to SPA search

Bug: 253981143
Test: manual, unit test
Change-Id: I59e9d2242a81a043ed6732a6699ae1bdf98cf193
parent 8e73ebe7
Loading
Loading
Loading
Loading
+37 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,13 @@ const val SEARCH_IMMUTABLE_STATUS = "search_immutable_status"
/** ContentProvider path for search mutable status */
/** ContentProvider path for search mutable status */
const val SEARCH_MUTABLE_STATUS = "search_mutable_status"
const val SEARCH_MUTABLE_STATUS = "search_mutable_status"


/** ContentProvider path for search static row */
const val SEARCH_STATIC_ROW = "search_static_row"

/** ContentProvider path for search dynamic row */
const val SEARCH_DYNAMIC_ROW = "search_dynamic_row"


/** Enum to define all column names in provider. */
/** Enum to define all column names in provider. */
enum class ColumnEnum(val id: String) {
enum class ColumnEnum(val id: String) {
    ENTRY_ID("entryId"),
    ENTRY_ID("entryId"),
@@ -95,4 +102,34 @@ enum class QueryEnum(
            ColumnEnum.ENTRY_DISABLED,
            ColumnEnum.ENTRY_DISABLED,
        )
        )
    ),
    ),
    SEARCH_STATIC_ROW_QUERY(
        SEARCH_STATIC_ROW,
        listOf(
            ColumnEnum.ENTRY_ID,
            ColumnEnum.SEARCH_TITLE,
            ColumnEnum.SEARCH_KEYWORD,
            ColumnEnum.SEARCH_PATH,
            ColumnEnum.INTENT_TARGET_PACKAGE,
            ColumnEnum.INTENT_TARGET_CLASS,
            ColumnEnum.INTENT_EXTRAS,
            ColumnEnum.SLICE_URI,
            ColumnEnum.LEGACY_KEY,
            ColumnEnum.ENTRY_DISABLED,
        )
    ),
    SEARCH_DYNAMIC_ROW_QUERY(
        SEARCH_DYNAMIC_ROW,
        listOf(
            ColumnEnum.ENTRY_ID,
            ColumnEnum.SEARCH_TITLE,
            ColumnEnum.SEARCH_KEYWORD,
            ColumnEnum.SEARCH_PATH,
            ColumnEnum.INTENT_TARGET_PACKAGE,
            ColumnEnum.INTENT_TARGET_CLASS,
            ColumnEnum.INTENT_EXTRAS,
            ColumnEnum.SLICE_URI,
            ColumnEnum.LEGACY_KEY,
            ColumnEnum.ENTRY_DISABLED,
        )
    ),
}
}
+63 −3
Original line number Original line Diff line number Diff line
@@ -28,7 +28,6 @@ import android.os.Parcel
import android.os.Parcelable
import android.os.Parcelable
import android.util.Log
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.annotation.VisibleForTesting
import com.android.settingslib.spa.framework.common.EntryStatusData
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.util.SESSION_SEARCH
import com.android.settingslib.spa.framework.util.SESSION_SEARCH
@@ -49,6 +48,8 @@ private const val TAG = "SpaSearchProvider"
 *   $ adb shell content query --uri content://<AuthorityPath>/search_dynamic_data
 *   $ adb shell content query --uri content://<AuthorityPath>/search_dynamic_data
 *   $ adb shell content query --uri content://<AuthorityPath>/search_immutable_status
 *   $ adb shell content query --uri content://<AuthorityPath>/search_immutable_status
 *   $ adb shell content query --uri content://<AuthorityPath>/search_mutable_status
 *   $ adb shell content query --uri content://<AuthorityPath>/search_mutable_status
 *   $ adb shell content query --uri content://<AuthorityPath>/search_static_row
 *   $ adb shell content query --uri content://<AuthorityPath>/search_dynamic_row
 */
 */
class SpaSearchProvider : ContentProvider() {
class SpaSearchProvider : ContentProvider() {
    private val spaEnvironment get() = SpaEnvironmentFactory.instance
    private val spaEnvironment get() = SpaEnvironmentFactory.instance
@@ -58,7 +59,9 @@ class SpaSearchProvider : ContentProvider() {
        SEARCH_STATIC_DATA to 301,
        SEARCH_STATIC_DATA to 301,
        SEARCH_DYNAMIC_DATA to 302,
        SEARCH_DYNAMIC_DATA to 302,
        SEARCH_MUTABLE_STATUS to 303,
        SEARCH_MUTABLE_STATUS to 303,
        SEARCH_IMMUTABLE_STATUS to 304
        SEARCH_IMMUTABLE_STATUS to 304,
        SEARCH_STATIC_ROW to 305,
        SEARCH_DYNAMIC_ROW to 306
    )
    )


    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
@@ -114,6 +117,8 @@ class SpaSearchProvider : ContentProvider() {
                    querySearchMutableStatusData()
                    querySearchMutableStatusData()
                queryMatchCode[SEARCH_IMMUTABLE_STATUS] ->
                queryMatchCode[SEARCH_IMMUTABLE_STATUS] ->
                    querySearchImmutableStatusData()
                    querySearchImmutableStatusData()
                queryMatchCode[SEARCH_STATIC_ROW] -> querySearchStaticRow()
                queryMatchCode[SEARCH_DYNAMIC_ROW] -> querySearchDynamicRow()
                else -> throw UnsupportedOperationException("Unknown Uri $uri")
                else -> throw UnsupportedOperationException("Unknown Uri $uri")
            }
            }
        } catch (e: UnsupportedOperationException) {
        } catch (e: UnsupportedOperationException) {
@@ -168,6 +173,31 @@ class SpaSearchProvider : ContentProvider() {
        return cursor
        return cursor
    }
    }


    @VisibleForTesting
    fun querySearchStaticRow(): Cursor {
        val entryRepository by spaEnvironment.entryRepository
        val cursor = MatrixCursor(QueryEnum.SEARCH_STATIC_ROW_QUERY.getColumns())
        for (entry in entryRepository.getAllEntries()) {
            if (!entry.isAllowSearch || entry.isSearchDataDynamic || entry.hasMutableStatus)
                continue
            fetchSearchRow(entry, cursor)
        }
        return cursor
    }

    @VisibleForTesting
    fun querySearchDynamicRow(): Cursor {
        val entryRepository by spaEnvironment.entryRepository
        val cursor = MatrixCursor(QueryEnum.SEARCH_DYNAMIC_ROW_QUERY.getColumns())
        for (entry in entryRepository.getAllEntries()) {
            if (!entry.isAllowSearch || (!entry.isSearchDataDynamic && !entry.hasMutableStatus))
                continue
            fetchSearchRow(entry, cursor)
        }
        return cursor
    }


    private fun fetchSearchData(entry: SettingsEntry, cursor: MatrixCursor) {
    private fun fetchSearchData(entry: SettingsEntry, cursor: MatrixCursor) {
        val entryRepository by spaEnvironment.entryRepository
        val entryRepository by spaEnvironment.entryRepository


@@ -196,12 +226,42 @@ class SpaSearchProvider : ContentProvider() {


    private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
    private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
        // Fetch status data. We can add runtime arguments later if necessary
        // Fetch status data. We can add runtime arguments later if necessary
        val statusData = entry.getStatusData() ?: EntryStatusData()
        val statusData = entry.getStatusData() ?: return
        cursor.newRow()
        cursor.newRow()
            .add(ColumnEnum.ENTRY_ID.id, entry.id)
            .add(ColumnEnum.ENTRY_ID.id, entry.id)
            .add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
            .add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
    }
    }


    private fun fetchSearchRow(entry: SettingsEntry, cursor: MatrixCursor) {
        val entryRepository by spaEnvironment.entryRepository

        // Fetch search data. We can add runtime arguments later if necessary
        val searchData = entry.getSearchData() ?: return
        val intent = entry.createIntent(SESSION_SEARCH)
        val row = cursor.newRow().add(ColumnEnum.ENTRY_ID.id, entry.id)
            .add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
            .add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
            .add(
                ColumnEnum.SEARCH_PATH.id,
                entryRepository.getEntryPathWithTitle(entry.id, searchData.title)
            )
        intent?.let {
            row.add(ColumnEnum.INTENT_TARGET_PACKAGE.id, spaEnvironment.appContext.packageName)
                .add(ColumnEnum.INTENT_TARGET_CLASS.id, spaEnvironment.browseActivityClass?.name)
                .add(ColumnEnum.INTENT_EXTRAS.id, marshall(intent.extras))
        }
        if (entry.hasSliceSupport)
            row.add(
                ColumnEnum.SLICE_URI.id, Uri.Builder()
                    .fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
            )
        // TODO: support legacy key

        // Fetch status data. We can add runtime arguments later if necessary
        val statusData = entry.getStatusData() ?: return
        row.add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
    }

    private fun QueryEnum.getColumns(): Array<String> {
    private fun QueryEnum.getColumns(): Array<String> {
        return columnNames.map { it.id }.toTypedArray()
        return columnNames.map { it.id }.toTypedArray()
    }
    }
+94 −13
Original line number Original line Diff line number Diff line
@@ -46,6 +46,8 @@ class SpaSearchProviderTest {
            .containsExactlyElementsIn(QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.columnNames)
            .containsExactlyElementsIn(QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.columnNames)
        Truth.assertThat(QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.columnNames)
        Truth.assertThat(QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.columnNames)
            .containsExactlyElementsIn(QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.columnNames)
            .containsExactlyElementsIn(QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.columnNames)
        Truth.assertThat(QueryEnum.SEARCH_STATIC_ROW_QUERY.columnNames)
            .containsExactlyElementsIn(QueryEnum.SEARCH_DYNAMIC_ROW_QUERY.columnNames)
    }
    }


    @Test
    @Test
@@ -53,20 +55,8 @@ class SpaSearchProviderTest {
        SpaEnvironmentFactory.reset(spaEnvironment)
        SpaEnvironmentFactory.reset(spaEnvironment)


        val immutableStatus = searchProvider.querySearchImmutableStatusData()
        val immutableStatus = searchProvider.querySearchImmutableStatusData()
        Truth.assertThat(immutableStatus.count).isEqualTo(2)
        Truth.assertThat(immutableStatus.count).isEqualTo(1)
        immutableStatus.moveToFirst()
        immutableStatus.moveToFirst()
        immutableStatus.checkValue(
            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
            ColumnEnum.ENTRY_ID,
            pageOwner.getEntryId("SearchStaticWithNoStatus")
        )
        immutableStatus.checkValue(
            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
            ColumnEnum.ENTRY_DISABLED,
            false.toString()
        )

        immutableStatus.moveToNext()
        immutableStatus.checkValue(
        immutableStatus.checkValue(
            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
            ColumnEnum.ENTRY_ID,
            ColumnEnum.ENTRY_ID,
@@ -171,6 +161,97 @@ class SpaSearchProviderTest {
            listOf("kw1", "kw2").toString()
            listOf("kw1", "kw2").toString()
        )
        )
    }
    }

    @Test
    fun testQuerySearchIndexRow() {
        SpaEnvironmentFactory.reset(spaEnvironment)

        val staticRow = searchProvider.querySearchStaticRow()
        Truth.assertThat(staticRow.count).isEqualTo(1)
        staticRow.moveToFirst()
        staticRow.checkValue(
            QueryEnum.SEARCH_STATIC_ROW_QUERY,
            ColumnEnum.ENTRY_ID,
            pageOwner.getEntryId("SearchStaticWithNoStatus")
        )
        staticRow.checkValue(
            QueryEnum.SEARCH_STATIC_ROW_QUERY, ColumnEnum.SEARCH_TITLE, "SearchStaticWithNoStatus"
        )
        staticRow.checkValue(
            QueryEnum.SEARCH_STATIC_ROW_QUERY, ColumnEnum.SEARCH_KEYWORD, listOf("").toString()
        )
        staticRow.checkValue(
            QueryEnum.SEARCH_STATIC_ROW_QUERY,
            ColumnEnum.SEARCH_PATH,
            listOf("SearchStaticWithNoStatus", "SppForSearch").toString()
        )
        staticRow.checkValue(
            QueryEnum.SEARCH_STATIC_ROW_QUERY,
            ColumnEnum.INTENT_TARGET_PACKAGE,
            spaEnvironment.appContext.packageName
        )
        staticRow.checkValue(
            QueryEnum.SEARCH_STATIC_ROW_QUERY,
            ColumnEnum.INTENT_TARGET_CLASS,
            "com.android.settingslib.spa.tests.testutils.BlankActivity"
        )

        // Check extras in intent
        val bundle =
            staticRow.getExtras(QueryEnum.SEARCH_STATIC_ROW_QUERY, ColumnEnum.INTENT_EXTRAS)
        Truth.assertThat(bundle).isNotNull()
        Truth.assertThat(bundle!!.size()).isEqualTo(3)
        Truth.assertThat(bundle.getString("spaActivityDestination")).isEqualTo("SppForSearch")
        Truth.assertThat(bundle.getString("highlightEntry"))
            .isEqualTo(pageOwner.getEntryId("SearchStaticWithNoStatus"))
        Truth.assertThat(bundle.getString("sessionSource")).isEqualTo("search")

        Truth.assertThat(
            staticRow.getString(
                QueryEnum.SEARCH_STATIC_ROW_QUERY.columnNames.indexOf(
                    ColumnEnum.ENTRY_DISABLED
                )
            )
        ).isNull()

        val dynamicRow = searchProvider.querySearchDynamicRow()
        Truth.assertThat(dynamicRow.count).isEqualTo(3)
        dynamicRow.moveToFirst()
        dynamicRow.checkValue(
            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
            ColumnEnum.ENTRY_ID,
            pageOwner.getEntryId("SearchStaticWithMutableStatus")
        )
        dynamicRow.checkValue(
            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, false.toString()
        )

        dynamicRow.moveToNext()
        dynamicRow.checkValue(
            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
            ColumnEnum.ENTRY_ID,
            pageOwner.getEntryId("SearchDynamicWithMutableStatus")
        )
        dynamicRow.checkValue(
            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
        )


        dynamicRow.moveToNext()
        dynamicRow.checkValue(
            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
            ColumnEnum.ENTRY_ID,
            pageOwner.getEntryId("SearchDynamicWithImmutableStatus")
        )
        dynamicRow.checkValue(
            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
            ColumnEnum.SEARCH_KEYWORD,
            listOf("kw1", "kw2").toString()
        )
        dynamicRow.checkValue(
            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
        )
    }
}
}


private fun Cursor.checkValue(query: QueryEnum, column: ColumnEnum, value: String) {
private fun Cursor.checkValue(query: QueryEnum, column: ColumnEnum, value: String) {