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

Commit a4d1fdee authored by George Lin's avatar George Lin Committed by Android (Google) Code Review
Browse files

Merge changes from topic "expose_is_shade_layout_wide" into main

* changes:
  Expose sysui runtime values to wallpaper picker (2/2)
  Format files
parents 4b4c56ad 78feb3d5
Loading
Loading
Loading
Loading
+72 −79
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.database.ContentObserver
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.annotation.DrawableRes
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
@@ -51,10 +52,7 @@ interface CustomizationProviderClient {
     * selected affordances on the slot will move the selected affordance to the newest location in
     * the slot.
     */
    suspend fun insertSelection(
        slotId: String,
        affordanceId: String,
    )
    suspend fun insertSelection(slotId: String, affordanceId: String)

    /** Returns all available slots supported by the device. */
    suspend fun querySlots(): List<Slot>
@@ -62,6 +60,11 @@ interface CustomizationProviderClient {
    /** Returns the list of flags. */
    suspend fun queryFlags(): List<Flag>

    /**
     * Returns [Bundle] where the keys are from [CustomizationProviderContract.RuntimeValuesTable]
     */
    suspend fun queryRuntimeValues(): Bundle

    /**
     * Returns [Flow] for observing the collection of slots.
     *
@@ -76,6 +79,13 @@ interface CustomizationProviderClient {
     */
    fun observeFlags(): Flow<List<Flag>>

    /**
     * Returns [Flow] for observing the variables from the System UI.
     *
     * @see [queryRuntimeValues]
     */
    fun observeRuntimeValues(): Flow<Bundle>

    /**
     * Returns all available affordances supported by the device, regardless of current slot
     * placement.
@@ -100,15 +110,10 @@ interface CustomizationProviderClient {
    fun observeSelections(): Flow<List<Selection>>

    /** Unselects an affordance with the given ID from the slot with the given ID. */
    suspend fun deleteSelection(
        slotId: String,
        affordanceId: String,
    )
    suspend fun deleteSelection(slotId: String, affordanceId: String)

    /** Unselects all affordances from the slot with the given ID. */
    suspend fun deleteAllSelections(
        slotId: String,
    )
    suspend fun deleteAllSelections(slotId: String)

    /** Returns a [Drawable] with the given ID, loaded from the system UI package. */
    suspend fun getAffordanceIcon(
@@ -200,10 +205,7 @@ class CustomizationProviderClientImpl(
    private val backgroundDispatcher: CoroutineDispatcher,
) : CustomizationProviderClient {

    override suspend fun insertSelection(
        slotId: String,
        affordanceId: String,
    ) {
    override suspend fun insertSelection(slotId: String, affordanceId: String) {
        withContext(backgroundDispatcher) {
            context.contentResolver.insert(
                Contract.LockScreenQuickAffordances.SelectionTable.URI,
@@ -211,9 +213,9 @@ class CustomizationProviderClientImpl(
                    put(Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID, slotId)
                    put(
                        Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID,
                        affordanceId
                        affordanceId,
                    )
                }
                },
            )
        }
    }
@@ -221,13 +223,7 @@ class CustomizationProviderClientImpl(
    override suspend fun querySlots(): List<CustomizationProviderClient.Slot> {
        return withContext(backgroundDispatcher) {
            context.contentResolver
                .query(
                    Contract.LockScreenQuickAffordances.SlotTable.URI,
                    null,
                    null,
                    null,
                    null,
                )
                .query(Contract.LockScreenQuickAffordances.SlotTable.URI, null, null, null, null)
                ?.use { cursor ->
                    buildList {
                        val idColumnIndex =
@@ -252,26 +248,16 @@ class CustomizationProviderClientImpl(
                        }
                    }
                }
        }
            ?: emptyList()
        } ?: emptyList()
    }

    override suspend fun queryFlags(): List<CustomizationProviderClient.Flag> {
        return withContext(backgroundDispatcher) {
            context.contentResolver
                .query(
                    Contract.FlagsTable.URI,
                    null,
                    null,
                    null,
                    null,
                )
                ?.use { cursor ->
            context.contentResolver.query(Contract.FlagsTable.URI, null, null, null, null)?.use {
                cursor ->
                buildList {
                        val nameColumnIndex =
                            cursor.getColumnIndex(Contract.FlagsTable.Columns.NAME)
                        val valueColumnIndex =
                            cursor.getColumnIndex(Contract.FlagsTable.Columns.VALUE)
                    val nameColumnIndex = cursor.getColumnIndex(Contract.FlagsTable.Columns.NAME)
                    val valueColumnIndex = cursor.getColumnIndex(Contract.FlagsTable.Columns.VALUE)
                    if (nameColumnIndex == -1 || valueColumnIndex == -1) {
                        return@buildList
                    }
@@ -286,8 +272,31 @@ class CustomizationProviderClientImpl(
                    }
                }
            }
        } ?: emptyList()
    }

    override suspend fun queryRuntimeValues(): Bundle {
        return withContext(backgroundDispatcher) {
            Bundle().apply {
                context.contentResolver
                    .query(Contract.RuntimeValuesTable.URI, null, null, null, null)
                    ?.use { cursor ->
                        val nameColumnIndex =
                            cursor.getColumnIndex(Contract.FlagsTable.Columns.NAME)
                        val valueColumnIndex =
                            cursor.getColumnIndex(Contract.FlagsTable.Columns.VALUE)
                        if (nameColumnIndex >= 0 && valueColumnIndex >= 0) {
                            while (cursor.moveToNext()) {
                                when (val name = cursor.getString(nameColumnIndex)) {
                                    Contract.RuntimeValuesTable.KEY_IS_SHADE_LAYOUT_WIDE -> {
                                        putBoolean(name, cursor.getInt(valueColumnIndex) == 1)
                                    }
                                }
                            }
                        }
                    }
            }
        }
            ?: emptyList()
    }

    override fun observeSlots(): Flow<List<CustomizationProviderClient.Slot>> {
@@ -298,6 +307,10 @@ class CustomizationProviderClientImpl(
        return observeUri(Contract.FlagsTable.URI).map { queryFlags() }
    }

    override fun observeRuntimeValues(): Flow<Bundle> {
        return observeUri(Contract.RuntimeValuesTable.URI).map { queryRuntimeValues() }
    }

    override suspend fun queryAffordances(): List<CustomizationProviderClient.Affordance> {
        return withContext(backgroundDispatcher) {
            context.contentResolver
@@ -375,22 +388,17 @@ class CustomizationProviderClientImpl(
                                    enablementActionIntent =
                                        cursor
                                            .getString(enablementActionIntentColumnIndex)
                                            ?.toIntent(
                                                affordanceId = affordanceId,
                                            ),
                                            ?.toIntent(affordanceId = affordanceId),
                                    configureIntent =
                                        cursor
                                            .getString(configureIntentColumnIndex)
                                            ?.toIntent(
                                                affordanceId = affordanceId,
                                            ),
                                            ?.toIntent(affordanceId = affordanceId),
                                )
                            )
                        }
                    }
                }
        }
            ?: emptyList()
        } ?: emptyList()
    }

    override fun observeAffordances(): Flow<List<CustomizationProviderClient.Affordance>> {
@@ -444,8 +452,7 @@ class CustomizationProviderClientImpl(
                        }
                    }
                }
        }
            ?: emptyList()
        } ?: emptyList()
    }

    override fun observeSelections(): Flow<List<CustomizationProviderClient.Selection>> {
@@ -454,34 +461,24 @@ class CustomizationProviderClientImpl(
        }
    }

    override suspend fun deleteSelection(
        slotId: String,
        affordanceId: String,
    ) {
    override suspend fun deleteSelection(slotId: String, affordanceId: String) {
        withContext(backgroundDispatcher) {
            context.contentResolver.delete(
                Contract.LockScreenQuickAffordances.SelectionTable.URI,
                "${Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID} = ? AND" +
                    " ${Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID}" +
                    " = ?",
                arrayOf(
                    slotId,
                    affordanceId,
                ),
                arrayOf(slotId, affordanceId),
            )
        }
    }

    override suspend fun deleteAllSelections(
        slotId: String,
    ) {
    override suspend fun deleteAllSelections(slotId: String) {
        withContext(backgroundDispatcher) {
            context.contentResolver.delete(
                Contract.LockScreenQuickAffordances.SelectionTable.URI,
                Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID,
                arrayOf(
                    slotId,
                ),
                arrayOf(slotId),
            )
        }
    }
@@ -499,9 +496,7 @@ class CustomizationProviderClientImpl(
        }
    }

    private fun observeUri(
        uri: Uri,
    ): Flow<Unit> {
    private fun observeUri(uri: Uri): Flow<Unit> {
        return callbackFlow {
                val observer =
                    object : ContentObserver(null) {
@@ -522,9 +517,7 @@ class CustomizationProviderClientImpl(
            .flowOn(backgroundDispatcher)
    }

    private fun String.toIntent(
        affordanceId: String,
    ): Intent? {
    private fun String.toIntent(affordanceId: String): Intent? {
        return try {
            Intent.parseUri(this, Intent.URI_INTENT_SCHEME)
        } catch (e: URISyntaxException) {
+23 −0
Original line number Diff line number Diff line
@@ -198,4 +198,27 @@ object CustomizationProviderContract {
            const val VALUE = "value"
        }
    }

    object RuntimeValuesTable {
        const val TABLE_NAME = "runtime_values"
        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()

        /**
         * This key corresponds to an Int value, where `1` means `true` and `0` means `false`.
         *
         * Whether the shade layout should be wide (true) or narrow (false).
         *
         * In a wide layout, notifications and quick settings each take up only half the screen
         * width (whether they are shown at the same time or not). In a narrow layout, they can each
         * be as wide as the entire screen.
         */
        const val KEY_IS_SHADE_LAYOUT_WIDE = "is_shade_layout_wide"

        object Columns {
            /** String. Unique ID for the value. */
            const val NAME = "name"
            /** Type depends on the key name. */
            const val VALUE = "value"
        }
    }
}
+16 −4
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.shared.customization.data.content

import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -64,11 +65,13 @@ class FakeCustomizationProviderClient(
                value = true,
            )
        ),
    runtimeValues: Bundle = Bundle(),
) : CustomizationProviderClient {

    private val slots = MutableStateFlow(slots)
    private val affordances = MutableStateFlow(affordances)
    private val flags = MutableStateFlow(flags)
    private val runtimeValues = MutableStateFlow(runtimeValues)

    private val selections = MutableStateFlow<Map<String, List<String>>>(emptyMap())

@@ -93,6 +96,10 @@ class FakeCustomizationProviderClient(
        return flags.value
    }

    override suspend fun queryRuntimeValues(): Bundle {
        return runtimeValues.value
    }

    override fun observeSlots(): Flow<List<CustomizationProviderClient.Slot>> {
        return slots.asStateFlow()
    }
@@ -101,6 +108,10 @@ class FakeCustomizationProviderClient(
        return flags.asStateFlow()
    }

    override fun observeRuntimeValues(): Flow<Bundle> {
        return runtimeValues.asStateFlow()
    }

    override suspend fun queryAffordances(): List<CustomizationProviderClient.Affordance> {
        return affordances.value
    }
@@ -139,10 +150,7 @@ class FakeCustomizationProviderClient(
        }
    }

    fun setFlag(
        name: String,
        value: Boolean,
    ) {
    fun setFlag(name: String, value: Boolean) {
        flags.value =
            flags.value.toMutableList().apply {
                removeIf { it.name == name }
@@ -150,6 +158,10 @@ class FakeCustomizationProviderClient(
            }
    }

    fun setRuntimeValues(runtimeValues: Bundle) {
        this.runtimeValues.value = runtimeValues
    }

    fun setSlotCapacity(slotId: String, capacity: Int) {
        slots.value =
            slots.value.toMutableList().apply {
+29 −1
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCall
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -44,6 +45,7 @@ class CustomizationProvider :
    ContentProvider(), SystemUIAppComponentFactoryBase.ContextInitializer {

    @Inject lateinit var interactor: KeyguardQuickAffordanceInteractor
    @Inject lateinit var shadeModeInteractor: ShadeModeInteractor
    @Inject lateinit var previewManager: KeyguardRemotePreviewManager
    @Inject @Main lateinit var mainDispatcher: CoroutineDispatcher

@@ -73,6 +75,11 @@ class CustomizationProvider :
                MATCH_CODE_ALL_SELECTIONS,
            )
            addURI(Contract.AUTHORITY, Contract.FlagsTable.TABLE_NAME, MATCH_CODE_ALL_FLAGS)
            addURI(
                Contract.AUTHORITY,
                Contract.RuntimeValuesTable.TABLE_NAME,
                MATCH_CODE_ALL_RUNTIME_VALUES,
            )
        }

    override fun onCreate(): Boolean {
@@ -94,7 +101,8 @@ class CustomizationProvider :
                MATCH_CODE_ALL_SLOTS,
                MATCH_CODE_ALL_AFFORDANCES,
                MATCH_CODE_ALL_FLAGS,
                MATCH_CODE_ALL_SELECTIONS -> "vnd.android.cursor.dir/vnd."
                MATCH_CODE_ALL_SELECTIONS,
                MATCH_CODE_ALL_RUNTIME_VALUES -> "vnd.android.cursor.dir/vnd."
                else -> null
            }

@@ -113,6 +121,7 @@ class CustomizationProvider :
                        Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME
                    )
                MATCH_CODE_ALL_FLAGS -> Contract.FlagsTable.TABLE_NAME
                MATCH_CODE_ALL_RUNTIME_VALUES -> Contract.RuntimeValuesTable.TABLE_NAME
                else -> null
            }

@@ -146,6 +155,7 @@ class CustomizationProvider :
                MATCH_CODE_ALL_SLOTS -> querySlots()
                MATCH_CODE_ALL_SELECTIONS -> querySelections()
                MATCH_CODE_ALL_FLAGS -> queryFlags()
                MATCH_CODE_ALL_RUNTIME_VALUES -> queryRuntimeValues()
                else -> null
            }
        }
@@ -334,6 +344,23 @@ class CustomizationProvider :
            }
    }

    private fun queryRuntimeValues(): Cursor {
        return MatrixCursor(
                arrayOf(
                    Contract.RuntimeValuesTable.Columns.NAME,
                    Contract.RuntimeValuesTable.Columns.VALUE,
                )
            )
            .apply {
                addRow(
                    arrayOf(
                        Contract.RuntimeValuesTable.KEY_IS_SHADE_LAYOUT_WIDE,
                        if (shadeModeInteractor.isShadeLayoutWide.value) 1 else 0,
                    )
                )
            }
    }

    private suspend fun deleteSelection(uri: Uri, selectionArgs: Array<out String>?): Int {
        if (selectionArgs == null) {
            throw IllegalArgumentException(
@@ -370,5 +397,6 @@ class CustomizationProvider :
        private const val MATCH_CODE_ALL_AFFORDANCES = 2
        private const val MATCH_CODE_ALL_SELECTIONS = 3
        private const val MATCH_CODE_ALL_FLAGS = 4
        private const val MATCH_CODE_ALL_RUNTIME_VALUES = 5
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -273,6 +273,12 @@ class CustomizationProviderTest : SysuiTestCase() {
                    "${Contract.AUTHORITY}." +
                    Contract.FlagsTable.TABLE_NAME
            )
        assertThat(underTest.getType(Contract.RuntimeValuesTable.URI))
            .isEqualTo(
                "vnd.android.cursor.dir/vnd." +
                    "${Contract.AUTHORITY}." +
                    Contract.RuntimeValuesTable.TABLE_NAME
            )
    }

    @Test