Merge "Renames customization content provider (1/7)." into tm-qpr-dev

This commit is contained in:
Ale Nijamkin
2022-12-28 17:42:20 +00:00
committed by Android (Google) Code Review
18 changed files with 466 additions and 356 deletions

View File

@@ -193,7 +193,7 @@
<permission android:name="com.android.systemui.permission.FLAGS" <permission android:name="com.android.systemui.permission.FLAGS"
android:protectionLevel="signature" /> android:protectionLevel="signature" />
<permission android:name="android.permission.ACCESS_KEYGUARD_QUICK_AFFORDANCES" <permission android:name="android.permission.CUSTOMIZE_SYSTEM_UI"
android:protectionLevel="signature|privileged" /> android:protectionLevel="signature|privileged" />
<!-- Adding Quick Settings tiles --> <!-- Adding Quick Settings tiles -->
@@ -1003,10 +1003,10 @@
</receiver> </receiver>
<provider <provider
android:authorities="com.android.systemui.keyguard.quickaffordance" android:authorities="com.android.systemui.customization"
android:name="com.android.systemui.keyguard.KeyguardQuickAffordanceProvider" android:name="com.android.systemui.keyguard.CustomizationProvider"
android:exported="true" android:exported="true"
android:permission="android.permission.ACCESS_KEYGUARD_QUICK_AFFORDANCES" android:permission="android.permission.CUSTOMIZE_SYSTEM_UI"
/> />
</application> </application>
</manifest> </manifest>

View File

@@ -35,7 +35,7 @@
android:enabled="false" android:enabled="false"
tools:replace="android:authorities" tools:replace="android:authorities"
tools:node="remove" /> tools:node="remove" />
<provider android:name="com.android.systemui.keyguard.KeyguardQuickAffordanceProvider" <provider android:name="com.android.systemui.keyguard.CustomizationProvider"
android:authorities="com.android.systemui.test.keyguard.quickaffordance.disabled" android:authorities="com.android.systemui.test.keyguard.quickaffordance.disabled"
android:enabled="false" android:enabled="false"
tools:replace="android:authorities" tools:replace="android:authorities"

View File

@@ -15,7 +15,7 @@
* *
*/ */
package com.android.systemui.shared.quickaffordance.data.content package com.android.systemui.shared.customization.data.content
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.ContentValues import android.content.ContentValues
@@ -25,7 +25,7 @@ import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@@ -35,7 +35,7 @@ import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
/** Client for using a content provider implementing the [Contract]. */ /** Client for using a content provider implementing the [Contract]. */
interface KeyguardQuickAffordanceProviderClient { interface CustomizationProviderClient {
/** /**
* Selects an affordance with the given ID for a slot on the lock screen with the given ID. * Selects an affordance with the given ID for a slot on the lock screen with the given ID.
@@ -190,10 +190,10 @@ interface KeyguardQuickAffordanceProviderClient {
) )
} }
class KeyguardQuickAffordanceProviderClientImpl( class CustomizationProviderClientImpl(
private val context: Context, private val context: Context,
private val backgroundDispatcher: CoroutineDispatcher, private val backgroundDispatcher: CoroutineDispatcher,
) : KeyguardQuickAffordanceProviderClient { ) : CustomizationProviderClient {
override suspend fun insertSelection( override suspend fun insertSelection(
slotId: String, slotId: String,
@@ -201,20 +201,23 @@ class KeyguardQuickAffordanceProviderClientImpl(
) { ) {
withContext(backgroundDispatcher) { withContext(backgroundDispatcher) {
context.contentResolver.insert( context.contentResolver.insert(
Contract.SelectionTable.URI, Contract.LockScreenQuickAffordances.SelectionTable.URI,
ContentValues().apply { ContentValues().apply {
put(Contract.SelectionTable.Columns.SLOT_ID, slotId) put(Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID, slotId)
put(Contract.SelectionTable.Columns.AFFORDANCE_ID, affordanceId) put(
Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID,
affordanceId
)
} }
) )
} }
} }
override suspend fun querySlots(): List<KeyguardQuickAffordanceProviderClient.Slot> { override suspend fun querySlots(): List<CustomizationProviderClient.Slot> {
return withContext(backgroundDispatcher) { return withContext(backgroundDispatcher) {
context.contentResolver context.contentResolver
.query( .query(
Contract.SlotTable.URI, Contract.LockScreenQuickAffordances.SlotTable.URI,
null, null,
null, null,
null, null,
@@ -222,16 +225,21 @@ class KeyguardQuickAffordanceProviderClientImpl(
) )
?.use { cursor -> ?.use { cursor ->
buildList { buildList {
val idColumnIndex = cursor.getColumnIndex(Contract.SlotTable.Columns.ID) val idColumnIndex =
cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SlotTable.Columns.ID
)
val capacityColumnIndex = val capacityColumnIndex =
cursor.getColumnIndex(Contract.SlotTable.Columns.CAPACITY) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SlotTable.Columns.CAPACITY
)
if (idColumnIndex == -1 || capacityColumnIndex == -1) { if (idColumnIndex == -1 || capacityColumnIndex == -1) {
return@buildList return@buildList
} }
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
add( add(
KeyguardQuickAffordanceProviderClient.Slot( CustomizationProviderClient.Slot(
id = cursor.getString(idColumnIndex), id = cursor.getString(idColumnIndex),
capacity = cursor.getInt(capacityColumnIndex), capacity = cursor.getInt(capacityColumnIndex),
) )
@@ -243,7 +251,7 @@ class KeyguardQuickAffordanceProviderClientImpl(
?: emptyList() ?: emptyList()
} }
override suspend fun queryFlags(): List<KeyguardQuickAffordanceProviderClient.Flag> { override suspend fun queryFlags(): List<CustomizationProviderClient.Flag> {
return withContext(backgroundDispatcher) { return withContext(backgroundDispatcher) {
context.contentResolver context.contentResolver
.query( .query(
@@ -265,7 +273,7 @@ class KeyguardQuickAffordanceProviderClientImpl(
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
add( add(
KeyguardQuickAffordanceProviderClient.Flag( CustomizationProviderClient.Flag(
name = cursor.getString(nameColumnIndex), name = cursor.getString(nameColumnIndex),
value = cursor.getInt(valueColumnIndex) == 1, value = cursor.getInt(valueColumnIndex) == 1,
) )
@@ -277,20 +285,19 @@ class KeyguardQuickAffordanceProviderClientImpl(
?: emptyList() ?: emptyList()
} }
override fun observeSlots(): Flow<List<KeyguardQuickAffordanceProviderClient.Slot>> { override fun observeSlots(): Flow<List<CustomizationProviderClient.Slot>> {
return observeUri(Contract.SlotTable.URI).map { querySlots() } return observeUri(Contract.LockScreenQuickAffordances.SlotTable.URI).map { querySlots() }
} }
override fun observeFlags(): Flow<List<KeyguardQuickAffordanceProviderClient.Flag>> { override fun observeFlags(): Flow<List<CustomizationProviderClient.Flag>> {
return observeUri(Contract.FlagsTable.URI).map { queryFlags() } return observeUri(Contract.FlagsTable.URI).map { queryFlags() }
} }
override suspend fun queryAffordances(): override suspend fun queryAffordances(): List<CustomizationProviderClient.Affordance> {
List<KeyguardQuickAffordanceProviderClient.Affordance> {
return withContext(backgroundDispatcher) { return withContext(backgroundDispatcher) {
context.contentResolver context.contentResolver
.query( .query(
Contract.AffordanceTable.URI, Contract.LockScreenQuickAffordances.AffordanceTable.URI,
null, null,
null, null,
null, null,
@@ -299,24 +306,36 @@ class KeyguardQuickAffordanceProviderClientImpl(
?.use { cursor -> ?.use { cursor ->
buildList { buildList {
val idColumnIndex = val idColumnIndex =
cursor.getColumnIndex(Contract.AffordanceTable.Columns.ID) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns.ID
)
val nameColumnIndex = val nameColumnIndex =
cursor.getColumnIndex(Contract.AffordanceTable.Columns.NAME) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns.NAME
)
val iconColumnIndex = val iconColumnIndex =
cursor.getColumnIndex(Contract.AffordanceTable.Columns.ICON) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns.ICON
)
val isEnabledColumnIndex = val isEnabledColumnIndex =
cursor.getColumnIndex(Contract.AffordanceTable.Columns.IS_ENABLED) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns
.IS_ENABLED
)
val enablementInstructionsColumnIndex = val enablementInstructionsColumnIndex =
cursor.getColumnIndex( cursor.getColumnIndex(
Contract.AffordanceTable.Columns.ENABLEMENT_INSTRUCTIONS Contract.LockScreenQuickAffordances.AffordanceTable.Columns
.ENABLEMENT_INSTRUCTIONS
) )
val enablementActionTextColumnIndex = val enablementActionTextColumnIndex =
cursor.getColumnIndex( cursor.getColumnIndex(
Contract.AffordanceTable.Columns.ENABLEMENT_ACTION_TEXT Contract.LockScreenQuickAffordances.AffordanceTable.Columns
.ENABLEMENT_ACTION_TEXT
) )
val enablementComponentNameColumnIndex = val enablementComponentNameColumnIndex =
cursor.getColumnIndex( cursor.getColumnIndex(
Contract.AffordanceTable.Columns.ENABLEMENT_COMPONENT_NAME Contract.LockScreenQuickAffordances.AffordanceTable.Columns
.ENABLEMENT_COMPONENT_NAME
) )
if ( if (
idColumnIndex == -1 || idColumnIndex == -1 ||
@@ -332,7 +351,7 @@ class KeyguardQuickAffordanceProviderClientImpl(
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
add( add(
KeyguardQuickAffordanceProviderClient.Affordance( CustomizationProviderClient.Affordance(
id = cursor.getString(idColumnIndex), id = cursor.getString(idColumnIndex),
name = cursor.getString(nameColumnIndex), name = cursor.getString(nameColumnIndex),
iconResourceId = cursor.getInt(iconColumnIndex), iconResourceId = cursor.getInt(iconColumnIndex),
@@ -341,7 +360,7 @@ class KeyguardQuickAffordanceProviderClientImpl(
cursor cursor
.getString(enablementInstructionsColumnIndex) .getString(enablementInstructionsColumnIndex)
?.split( ?.split(
Contract.AffordanceTable Contract.LockScreenQuickAffordances.AffordanceTable
.ENABLEMENT_INSTRUCTIONS_DELIMITER .ENABLEMENT_INSTRUCTIONS_DELIMITER
), ),
enablementActionText = enablementActionText =
@@ -357,16 +376,17 @@ class KeyguardQuickAffordanceProviderClientImpl(
?: emptyList() ?: emptyList()
} }
override fun observeAffordances(): override fun observeAffordances(): Flow<List<CustomizationProviderClient.Affordance>> {
Flow<List<KeyguardQuickAffordanceProviderClient.Affordance>> { return observeUri(Contract.LockScreenQuickAffordances.AffordanceTable.URI).map {
return observeUri(Contract.AffordanceTable.URI).map { queryAffordances() } queryAffordances()
}
} }
override suspend fun querySelections(): List<KeyguardQuickAffordanceProviderClient.Selection> { override suspend fun querySelections(): List<CustomizationProviderClient.Selection> {
return withContext(backgroundDispatcher) { return withContext(backgroundDispatcher) {
context.contentResolver context.contentResolver
.query( .query(
Contract.SelectionTable.URI, Contract.LockScreenQuickAffordances.SelectionTable.URI,
null, null,
null, null,
null, null,
@@ -375,11 +395,19 @@ class KeyguardQuickAffordanceProviderClientImpl(
?.use { cursor -> ?.use { cursor ->
buildList { buildList {
val slotIdColumnIndex = val slotIdColumnIndex =
cursor.getColumnIndex(Contract.SelectionTable.Columns.SLOT_ID) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID
)
val affordanceIdColumnIndex = val affordanceIdColumnIndex =
cursor.getColumnIndex(Contract.SelectionTable.Columns.AFFORDANCE_ID) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SelectionTable.Columns
.AFFORDANCE_ID
)
val affordanceNameColumnIndex = val affordanceNameColumnIndex =
cursor.getColumnIndex(Contract.SelectionTable.Columns.AFFORDANCE_NAME) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SelectionTable.Columns
.AFFORDANCE_NAME
)
if ( if (
slotIdColumnIndex == -1 || slotIdColumnIndex == -1 ||
affordanceIdColumnIndex == -1 || affordanceIdColumnIndex == -1 ||
@@ -390,7 +418,7 @@ class KeyguardQuickAffordanceProviderClientImpl(
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
add( add(
KeyguardQuickAffordanceProviderClient.Selection( CustomizationProviderClient.Selection(
slotId = cursor.getString(slotIdColumnIndex), slotId = cursor.getString(slotIdColumnIndex),
affordanceId = cursor.getString(affordanceIdColumnIndex), affordanceId = cursor.getString(affordanceIdColumnIndex),
affordanceName = cursor.getString(affordanceNameColumnIndex), affordanceName = cursor.getString(affordanceNameColumnIndex),
@@ -403,8 +431,10 @@ class KeyguardQuickAffordanceProviderClientImpl(
?: emptyList() ?: emptyList()
} }
override fun observeSelections(): Flow<List<KeyguardQuickAffordanceProviderClient.Selection>> { override fun observeSelections(): Flow<List<CustomizationProviderClient.Selection>> {
return observeUri(Contract.SelectionTable.URI).map { querySelections() } return observeUri(Contract.LockScreenQuickAffordances.SelectionTable.URI).map {
querySelections()
}
} }
override suspend fun deleteSelection( override suspend fun deleteSelection(
@@ -413,9 +443,10 @@ class KeyguardQuickAffordanceProviderClientImpl(
) { ) {
withContext(backgroundDispatcher) { withContext(backgroundDispatcher) {
context.contentResolver.delete( context.contentResolver.delete(
Contract.SelectionTable.URI, Contract.LockScreenQuickAffordances.SelectionTable.URI,
"${Contract.SelectionTable.Columns.SLOT_ID} = ? AND" + "${Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID} = ? AND" +
" ${Contract.SelectionTable.Columns.AFFORDANCE_ID} = ?", " ${Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID}" +
" = ?",
arrayOf( arrayOf(
slotId, slotId,
affordanceId, affordanceId,
@@ -429,8 +460,8 @@ class KeyguardQuickAffordanceProviderClientImpl(
) { ) {
withContext(backgroundDispatcher) { withContext(backgroundDispatcher) {
context.contentResolver.delete( context.contentResolver.delete(
Contract.SelectionTable.URI, Contract.LockScreenQuickAffordances.SelectionTable.URI,
Contract.SelectionTable.Columns.SLOT_ID, Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID,
arrayOf( arrayOf(
slotId, slotId,
), ),

View File

@@ -0,0 +1,183 @@
/*
* Copyright (C) 2022 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.systemui.shared.customization.data.content
import android.content.ContentResolver
import android.net.Uri
/** Contract definitions for querying content about keyguard quick affordances. */
object CustomizationProviderContract {
const val AUTHORITY = "com.android.systemui.customization"
const val PERMISSION = "android.permission.CUSTOMIZE_SYSTEM_UI"
private val BASE_URI: Uri =
Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY).build()
/** Namespace for lock screen shortcut (quick affordance) tables. */
object LockScreenQuickAffordances {
const val NAMESPACE = "lockscreen_quickaffordance"
private val LOCK_SCREEN_QUICK_AFFORDANCE_BASE_URI: Uri =
BASE_URI.buildUpon().path(NAMESPACE).build()
fun qualifiedTablePath(tableName: String): String {
return "$NAMESPACE/$tableName"
}
/**
* Table for slots.
*
* Slots are positions where affordances can be placed on the lock screen. Affordances that
* are placed on slots are said to be "selected". The system supports the idea of multiple
* affordances per slot, though the implementation may limit the number of affordances on
* each slot.
*
* Supported operations:
* - Query - to know which slots are available, query the [SlotTable.URI] [Uri]. The result
* set will contain rows with the [SlotTable.Columns] columns.
*/
object SlotTable {
const val TABLE_NAME = "slots"
val URI: Uri =
LOCK_SCREEN_QUICK_AFFORDANCE_BASE_URI.buildUpon().appendPath(TABLE_NAME).build()
object Columns {
/** String. Unique ID for this slot. */
const val ID = "id"
/** Integer. The maximum number of affordances that can be placed in the slot. */
const val CAPACITY = "capacity"
}
}
/**
* Table for affordances.
*
* Affordances are actions/buttons that the user can execute. They are placed on slots on
* the lock screen.
*
* Supported operations:
* - Query - to know about all the affordances that are available on the device, regardless
* of which ones are currently selected, query the [AffordanceTable.URI] [Uri]. The result
* set will contain rows, each with the columns specified in [AffordanceTable.Columns].
*/
object AffordanceTable {
const val TABLE_NAME = "affordances"
val URI: Uri =
LOCK_SCREEN_QUICK_AFFORDANCE_BASE_URI.buildUpon().appendPath(TABLE_NAME).build()
const val ENABLEMENT_INSTRUCTIONS_DELIMITER = "]["
const val COMPONENT_NAME_SEPARATOR = "/"
object Columns {
/** String. Unique ID for this affordance. */
const val ID = "id"
/** String. User-visible name for this affordance. */
const val NAME = "name"
/**
* Integer. Resource ID for the drawable to load for this affordance. This is a
* resource ID from the system UI package.
*/
const val ICON = "icon"
/** Integer. `1` if the affordance is enabled or `0` if it disabled. */
const val IS_ENABLED = "is_enabled"
/**
* String. List of strings, delimited by [ENABLEMENT_INSTRUCTIONS_DELIMITER] to be
* shown to the user if the affordance is disabled and the user selects the
* affordance.
*/
const val ENABLEMENT_INSTRUCTIONS = "enablement_instructions"
/**
* String. Optional label for a button that, when clicked, opens a destination
* activity where the user can re-enable the disabled affordance.
*/
const val ENABLEMENT_ACTION_TEXT = "enablement_action_text"
/**
* String. Optional package name and activity action string, delimited by
* [COMPONENT_NAME_SEPARATOR] to use with an `Intent` to start an activity that
* opens a destination where the user can re-enable the disabled affordance.
*/
const val ENABLEMENT_COMPONENT_NAME = "enablement_action_intent"
}
}
/**
* Table for selections.
*
* Selections are pairs of slot and affordance IDs.
*
* Supported operations:
* - Insert - to insert an affordance and place it in a slot, insert values for the columns
* into the [SelectionTable.URI] [Uri]. The maximum capacity rule is enforced by the system.
* Selecting a new affordance for a slot that is already full will automatically remove the
* oldest affordance from the slot.
* - Query - to know which affordances are set on which slots, query the
* [SelectionTable.URI] [Uri]. The result set will contain rows, each of which with the
* columns from [SelectionTable.Columns].
* - Delete - to unselect an affordance, removing it from a slot, delete from the
* [SelectionTable.URI] [Uri], passing in values for each column.
*/
object SelectionTable {
const val TABLE_NAME = "selections"
val URI: Uri =
LOCK_SCREEN_QUICK_AFFORDANCE_BASE_URI.buildUpon().appendPath(TABLE_NAME).build()
object Columns {
/** String. Unique ID for the slot. */
const val SLOT_ID = "slot_id"
/** String. Unique ID for the selected affordance. */
const val AFFORDANCE_ID = "affordance_id"
/** String. Human-readable name for the affordance. */
const val AFFORDANCE_NAME = "affordance_name"
}
}
}
/**
* Table for flags.
*
* Flags are key-value pairs.
*
* Supported operations:
* - Query - to know the values of flags, query the [FlagsTable.URI] [Uri]. The result set will
* contain rows, each of which with the columns from [FlagsTable.Columns].
*/
object FlagsTable {
const val TABLE_NAME = "flags"
val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
/** Flag denoting whether the Wallpaper Picker should use the new, revamped UI. */
const val FLAG_NAME_REVAMPED_WALLPAPER_UI = "revamped_wallpaper_ui"
/**
* Flag denoting whether the customizable lock screen quick affordances feature is enabled.
*/
const val FLAG_NAME_CUSTOM_LOCK_SCREEN_QUICK_AFFORDANCES_ENABLED =
"is_custom_lock_screen_quick_affordances_feature_enabled"
/** Flag denoting whether the customizable clocks feature is enabled. */
const val FLAG_NAME_CUSTOM_CLOCKS_ENABLED = "is_custom_clocks_feature_enabled"
object Columns {
/** String. Unique ID for the flag. */
const val NAME = "name"
/** Int. Value of the flag. `1` means `true` and `0` means `false`. */
const val VALUE = "value"
}
}
}

View File

@@ -15,7 +15,7 @@
* *
*/ */
package com.android.systemui.shared.quickaffordance.data.content package com.android.systemui.shared.customization.data.content
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
@@ -25,46 +25,46 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
class FakeKeyguardQuickAffordanceProviderClient( class FakeCustomizationProviderClient(
slots: List<KeyguardQuickAffordanceProviderClient.Slot> = slots: List<CustomizationProviderClient.Slot> =
listOf( listOf(
KeyguardQuickAffordanceProviderClient.Slot( CustomizationProviderClient.Slot(
id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
capacity = 1, capacity = 1,
), ),
KeyguardQuickAffordanceProviderClient.Slot( CustomizationProviderClient.Slot(
id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
capacity = 1, capacity = 1,
), ),
), ),
affordances: List<KeyguardQuickAffordanceProviderClient.Affordance> = affordances: List<CustomizationProviderClient.Affordance> =
listOf( listOf(
KeyguardQuickAffordanceProviderClient.Affordance( CustomizationProviderClient.Affordance(
id = AFFORDANCE_1, id = AFFORDANCE_1,
name = AFFORDANCE_1, name = AFFORDANCE_1,
iconResourceId = 1, iconResourceId = 1,
), ),
KeyguardQuickAffordanceProviderClient.Affordance( CustomizationProviderClient.Affordance(
id = AFFORDANCE_2, id = AFFORDANCE_2,
name = AFFORDANCE_2, name = AFFORDANCE_2,
iconResourceId = 2, iconResourceId = 2,
), ),
KeyguardQuickAffordanceProviderClient.Affordance( CustomizationProviderClient.Affordance(
id = AFFORDANCE_3, id = AFFORDANCE_3,
name = AFFORDANCE_3, name = AFFORDANCE_3,
iconResourceId = 3, iconResourceId = 3,
), ),
), ),
flags: List<KeyguardQuickAffordanceProviderClient.Flag> = flags: List<CustomizationProviderClient.Flag> =
listOf( listOf(
KeyguardQuickAffordanceProviderClient.Flag( CustomizationProviderClient.Flag(
name = name =
KeyguardQuickAffordanceProviderContract.FlagsTable CustomizationProviderContract.FlagsTable
.FLAG_NAME_CUSTOM_LOCK_SCREEN_QUICK_AFFORDANCES_ENABLED, .FLAG_NAME_CUSTOM_LOCK_SCREEN_QUICK_AFFORDANCES_ENABLED,
value = true, value = true,
) )
), ),
) : KeyguardQuickAffordanceProviderClient { ) : CustomizationProviderClient {
private val slots = MutableStateFlow(slots) private val slots = MutableStateFlow(slots)
private val affordances = MutableStateFlow(affordances) private val affordances = MutableStateFlow(affordances)
@@ -85,37 +85,35 @@ class FakeKeyguardQuickAffordanceProviderClient(
selections.value = selections.value.toMutableMap().apply { this[slotId] = affordances } selections.value = selections.value.toMutableMap().apply { this[slotId] = affordances }
} }
override suspend fun querySlots(): List<KeyguardQuickAffordanceProviderClient.Slot> { override suspend fun querySlots(): List<CustomizationProviderClient.Slot> {
return slots.value return slots.value
} }
override suspend fun queryFlags(): List<KeyguardQuickAffordanceProviderClient.Flag> { override suspend fun queryFlags(): List<CustomizationProviderClient.Flag> {
return flags.value return flags.value
} }
override fun observeSlots(): Flow<List<KeyguardQuickAffordanceProviderClient.Slot>> { override fun observeSlots(): Flow<List<CustomizationProviderClient.Slot>> {
return slots.asStateFlow() return slots.asStateFlow()
} }
override fun observeFlags(): Flow<List<KeyguardQuickAffordanceProviderClient.Flag>> { override fun observeFlags(): Flow<List<CustomizationProviderClient.Flag>> {
return flags.asStateFlow() return flags.asStateFlow()
} }
override suspend fun queryAffordances(): override suspend fun queryAffordances(): List<CustomizationProviderClient.Affordance> {
List<KeyguardQuickAffordanceProviderClient.Affordance> {
return affordances.value return affordances.value
} }
override fun observeAffordances(): override fun observeAffordances(): Flow<List<CustomizationProviderClient.Affordance>> {
Flow<List<KeyguardQuickAffordanceProviderClient.Affordance>> {
return affordances.asStateFlow() return affordances.asStateFlow()
} }
override suspend fun querySelections(): List<KeyguardQuickAffordanceProviderClient.Selection> { override suspend fun querySelections(): List<CustomizationProviderClient.Selection> {
return toSelectionList(selections.value, affordances.value) return toSelectionList(selections.value, affordances.value)
} }
override fun observeSelections(): Flow<List<KeyguardQuickAffordanceProviderClient.Selection>> { override fun observeSelections(): Flow<List<CustomizationProviderClient.Selection>> {
return combine(selections, affordances) { selections, affordances -> return combine(selections, affordances) { selections, affordances ->
toSelectionList(selections, affordances) toSelectionList(selections, affordances)
} }
@@ -148,7 +146,7 @@ class FakeKeyguardQuickAffordanceProviderClient(
flags.value = flags.value =
flags.value.toMutableList().apply { flags.value.toMutableList().apply {
removeIf { it.name == name } removeIf { it.name == name }
add(KeyguardQuickAffordanceProviderClient.Flag(name = name, value = value)) add(CustomizationProviderClient.Flag(name = name, value = value))
} }
} }
@@ -157,29 +155,26 @@ class FakeKeyguardQuickAffordanceProviderClient(
slots.value.toMutableList().apply { slots.value.toMutableList().apply {
val index = indexOfFirst { it.id == slotId } val index = indexOfFirst { it.id == slotId }
check(index != -1) { "Slot with ID \"$slotId\" doesn't exist!" } check(index != -1) { "Slot with ID \"$slotId\" doesn't exist!" }
set( set(index, CustomizationProviderClient.Slot(id = slotId, capacity = capacity))
index,
KeyguardQuickAffordanceProviderClient.Slot(id = slotId, capacity = capacity)
)
} }
} }
fun addAffordance(affordance: KeyguardQuickAffordanceProviderClient.Affordance): Int { fun addAffordance(affordance: CustomizationProviderClient.Affordance): Int {
affordances.value = affordances.value + listOf(affordance) affordances.value = affordances.value + listOf(affordance)
return affordances.value.size - 1 return affordances.value.size - 1
} }
private fun toSelectionList( private fun toSelectionList(
selections: Map<String, List<String>>, selections: Map<String, List<String>>,
affordances: List<KeyguardQuickAffordanceProviderClient.Affordance>, affordances: List<CustomizationProviderClient.Affordance>,
): List<KeyguardQuickAffordanceProviderClient.Selection> { ): List<CustomizationProviderClient.Selection> {
return selections return selections
.map { (slotId, affordanceIds) -> .map { (slotId, affordanceIds) ->
affordanceIds.map { affordanceId -> affordanceIds.map { affordanceId ->
val affordanceName = val affordanceName =
affordances.find { it.id == affordanceId }?.name affordances.find { it.id == affordanceId }?.name
?: error("No affordance with ID of \"$affordanceId\"!") ?: error("No affordance with ID of \"$affordanceId\"!")
KeyguardQuickAffordanceProviderClient.Selection( CustomizationProviderClient.Selection(
slotId = slotId, slotId = slotId,
affordanceId = affordanceId, affordanceId = affordanceId,
affordanceName = affordanceName, affordanceName = affordanceName,

View File

@@ -1,166 +0,0 @@
/*
* Copyright (C) 2022 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.systemui.shared.quickaffordance.data.content
import android.content.ContentResolver
import android.net.Uri
/** Contract definitions for querying content about keyguard quick affordances. */
object KeyguardQuickAffordanceProviderContract {
const val AUTHORITY = "com.android.systemui.keyguard.quickaffordance"
const val PERMISSION = "android.permission.ACCESS_KEYGUARD_QUICK_AFFORDANCES"
private val BASE_URI: Uri =
Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY).build()
/**
* Table for slots.
*
* Slots are positions where affordances can be placed on the lock screen. Affordances that are
* placed on slots are said to be "selected". The system supports the idea of multiple
* affordances per slot, though the implementation may limit the number of affordances on each
* slot.
*
* Supported operations:
* - Query - to know which slots are available, query the [SlotTable.URI] [Uri]. The result set
* will contain rows with the [SlotTable.Columns] columns.
*/
object SlotTable {
const val TABLE_NAME = "slots"
val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
object Columns {
/** String. Unique ID for this slot. */
const val ID = "id"
/** Integer. The maximum number of affordances that can be placed in the slot. */
const val CAPACITY = "capacity"
}
}
/**
* Table for affordances.
*
* Affordances are actions/buttons that the user can execute. They are placed on slots on the
* lock screen.
*
* Supported operations:
* - Query - to know about all the affordances that are available on the device, regardless of
* which ones are currently selected, query the [AffordanceTable.URI] [Uri]. The result set will
* contain rows, each with the columns specified in [AffordanceTable.Columns].
*/
object AffordanceTable {
const val TABLE_NAME = "affordances"
val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
const val ENABLEMENT_INSTRUCTIONS_DELIMITER = "]["
const val COMPONENT_NAME_SEPARATOR = "/"
object Columns {
/** String. Unique ID for this affordance. */
const val ID = "id"
/** String. User-visible name for this affordance. */
const val NAME = "name"
/**
* Integer. Resource ID for the drawable to load for this affordance. This is a resource
* ID from the system UI package.
*/
const val ICON = "icon"
/** Integer. `1` if the affordance is enabled or `0` if it disabled. */
const val IS_ENABLED = "is_enabled"
/**
* String. List of strings, delimited by [ENABLEMENT_INSTRUCTIONS_DELIMITER] to be shown
* to the user if the affordance is disabled and the user selects the affordance.
*/
const val ENABLEMENT_INSTRUCTIONS = "enablement_instructions"
/**
* String. Optional label for a button that, when clicked, opens a destination activity
* where the user can re-enable the disabled affordance.
*/
const val ENABLEMENT_ACTION_TEXT = "enablement_action_text"
/**
* String. Optional package name and activity action string, delimited by
* [COMPONENT_NAME_SEPARATOR] to use with an `Intent` to start an activity that opens a
* destination where the user can re-enable the disabled affordance.
*/
const val ENABLEMENT_COMPONENT_NAME = "enablement_action_intent"
}
}
/**
* Table for selections.
*
* Selections are pairs of slot and affordance IDs.
*
* Supported operations:
* - Insert - to insert an affordance and place it in a slot, insert values for the columns into
* the [SelectionTable.URI] [Uri]. The maximum capacity rule is enforced by the system.
* Selecting a new affordance for a slot that is already full will automatically remove the
* oldest affordance from the slot.
* - Query - to know which affordances are set on which slots, query the [SelectionTable.URI]
* [Uri]. The result set will contain rows, each of which with the columns from
* [SelectionTable.Columns].
* - Delete - to unselect an affordance, removing it from a slot, delete from the
* [SelectionTable.URI] [Uri], passing in values for each column.
*/
object SelectionTable {
const val TABLE_NAME = "selections"
val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
object Columns {
/** String. Unique ID for the slot. */
const val SLOT_ID = "slot_id"
/** String. Unique ID for the selected affordance. */
const val AFFORDANCE_ID = "affordance_id"
/** String. Human-readable name for the affordance. */
const val AFFORDANCE_NAME = "affordance_name"
}
}
/**
* Table for flags.
*
* Flags are key-value pairs.
*
* Supported operations:
* - Query - to know the values of flags, query the [FlagsTable.URI] [Uri]. The result set will
* contain rows, each of which with the columns from [FlagsTable.Columns].
*/
object FlagsTable {
const val TABLE_NAME = "flags"
val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
/** Flag denoting whether the Wallpaper Picker should use the new, revamped UI. */
const val FLAG_NAME_REVAMPED_WALLPAPER_UI = "revamped_wallpaper_ui"
/**
* Flag denoting whether the customizable lock screen quick affordances feature is enabled.
*/
const val FLAG_NAME_CUSTOM_LOCK_SCREEN_QUICK_AFFORDANCES_ENABLED =
"is_custom_lock_screen_quick_affordances_feature_enabled"
/** Flag denoting whether the customizable clocks feature is enabled. */
const val FLAG_NAME_CUSTOM_CLOCKS_ENABLED = "is_custom_clocks_feature_enabled"
object Columns {
/** String. Unique ID for the flag. */
const val NAME = "name"
/** Int. Value of the flag. `1` means `true` and `0` means `false`. */
const val VALUE = "value"
}
}
}

View File

@@ -31,7 +31,7 @@ This section describes how to implement a potential picker, selector, or configu
### Accessing Quick Affordance Data ### Accessing Quick Affordance Data
Quick Affordances structured data are exposed to other applications through the `KeyguardQuickAffordanceProvider` content provider which is owned by the System UI process. Quick Affordances structured data are exposed to other applications through the `KeyguardQuickAffordanceProvider` content provider which is owned by the System UI process.
To access this content provider, applications must have the `android.permission.ACCESS_KEYGUARD_QUICK_AFFORDANCES` permission which is a signature and privileged permission, limiting access to system apps or apps signed by the same signature as System UI. The `KeyguardQuickAffordanceProviderContract` file defines the content provider schema for consumers. To access this content provider, applications must have the `android.permission.CUSTOMIZE_SYSTEM_UI` permission which is a signature and privileged permission, limiting access to system apps or apps signed by the same signature as System UI. The `KeyguardQuickAffordanceProviderContract` file defines the content provider schema for consumers.
Generally speaking, there are three important tables served by the content provider: `slots`, `affordances`, and `selections`. There is also a `flags` table, but that's not important and may be ignored. Generally speaking, there are three important tables served by the content provider: `slots`, `affordances`, and `selections`. There is also a `flags` table, but that's not important and may be ignored.

View File

@@ -16,7 +16,7 @@
package com.android.systemui.dagger; package com.android.systemui.dagger;
import com.android.systemui.keyguard.KeyguardQuickAffordanceProvider; import com.android.systemui.keyguard.CustomizationProvider;
import com.android.systemui.statusbar.NotificationInsetsModule; import com.android.systemui.statusbar.NotificationInsetsModule;
import com.android.systemui.statusbar.QsFrameTranslateModule; import com.android.systemui.statusbar.QsFrameTranslateModule;
@@ -49,5 +49,5 @@ public interface ReferenceSysUIComponent extends SysUIComponent {
/** /**
* Member injection into the supplied argument. * Member injection into the supplied argument.
*/ */
void inject(KeyguardQuickAffordanceProvider keyguardQuickAffordanceProvider); void inject(CustomizationProvider customizationProvider);
} }

View File

@@ -33,11 +33,11 @@ import com.android.systemui.SystemUIAppComponentFactoryBase
import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
class KeyguardQuickAffordanceProvider : class CustomizationProvider :
ContentProvider(), SystemUIAppComponentFactoryBase.ContextInitializer { ContentProvider(), SystemUIAppComponentFactoryBase.ContextInitializer {
@Inject lateinit var interactor: KeyguardQuickAffordanceInteractor @Inject lateinit var interactor: KeyguardQuickAffordanceInteractor
@@ -49,17 +49,23 @@ class KeyguardQuickAffordanceProvider :
UriMatcher(UriMatcher.NO_MATCH).apply { UriMatcher(UriMatcher.NO_MATCH).apply {
addURI( addURI(
Contract.AUTHORITY, Contract.AUTHORITY,
Contract.SlotTable.TABLE_NAME, Contract.LockScreenQuickAffordances.qualifiedTablePath(
Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME,
),
MATCH_CODE_ALL_SLOTS, MATCH_CODE_ALL_SLOTS,
) )
addURI( addURI(
Contract.AUTHORITY, Contract.AUTHORITY,
Contract.AffordanceTable.TABLE_NAME, Contract.LockScreenQuickAffordances.qualifiedTablePath(
Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME,
),
MATCH_CODE_ALL_AFFORDANCES, MATCH_CODE_ALL_AFFORDANCES,
) )
addURI( addURI(
Contract.AUTHORITY, Contract.AUTHORITY,
Contract.SelectionTable.TABLE_NAME, Contract.LockScreenQuickAffordances.qualifiedTablePath(
Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME,
),
MATCH_CODE_ALL_SELECTIONS, MATCH_CODE_ALL_SELECTIONS,
) )
addURI( addURI(
@@ -94,9 +100,18 @@ class KeyguardQuickAffordanceProvider :
val tableName = val tableName =
when (uriMatcher.match(uri)) { when (uriMatcher.match(uri)) {
MATCH_CODE_ALL_SLOTS -> Contract.SlotTable.TABLE_NAME MATCH_CODE_ALL_SLOTS ->
MATCH_CODE_ALL_AFFORDANCES -> Contract.AffordanceTable.TABLE_NAME Contract.LockScreenQuickAffordances.qualifiedTablePath(
MATCH_CODE_ALL_SELECTIONS -> Contract.SelectionTable.TABLE_NAME Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME,
)
MATCH_CODE_ALL_AFFORDANCES ->
Contract.LockScreenQuickAffordances.qualifiedTablePath(
Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME,
)
MATCH_CODE_ALL_SELECTIONS ->
Contract.LockScreenQuickAffordances.qualifiedTablePath(
Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME,
)
MATCH_CODE_ALL_FLAGS -> Contract.FlagsTable.TABLE_NAME MATCH_CODE_ALL_FLAGS -> Contract.FlagsTable.TABLE_NAME
else -> null else -> null
} }
@@ -174,22 +189,34 @@ class KeyguardQuickAffordanceProvider :
throw IllegalArgumentException("Cannot insert selection, no values passed in!") throw IllegalArgumentException("Cannot insert selection, no values passed in!")
} }
if (!values.containsKey(Contract.SelectionTable.Columns.SLOT_ID)) { if (
!values.containsKey(Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID)
) {
throw IllegalArgumentException( throw IllegalArgumentException(
"Cannot insert selection, " + "Cannot insert selection, " +
"\"${Contract.SelectionTable.Columns.SLOT_ID}\" not specified!" "\"${Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID}\"" +
" not specified!"
) )
} }
if (!values.containsKey(Contract.SelectionTable.Columns.AFFORDANCE_ID)) { if (
!values.containsKey(
Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID
)
) {
throw IllegalArgumentException( throw IllegalArgumentException(
"Cannot insert selection, " + "Cannot insert selection, " +
"\"${Contract.SelectionTable.Columns.AFFORDANCE_ID}\" not specified!" "\"${Contract.LockScreenQuickAffordances
.SelectionTable.Columns.AFFORDANCE_ID}\" not specified!"
) )
} }
val slotId = values.getAsString(Contract.SelectionTable.Columns.SLOT_ID) val slotId =
val affordanceId = values.getAsString(Contract.SelectionTable.Columns.AFFORDANCE_ID) values.getAsString(Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID)
val affordanceId =
values.getAsString(
Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID
)
if (slotId.isNullOrEmpty()) { if (slotId.isNullOrEmpty()) {
throw IllegalArgumentException("Cannot insert selection, slot ID was empty!") throw IllegalArgumentException("Cannot insert selection, slot ID was empty!")
@@ -207,8 +234,10 @@ class KeyguardQuickAffordanceProvider :
return if (success) { return if (success) {
Log.d(TAG, "Successfully selected $affordanceId for slot $slotId") Log.d(TAG, "Successfully selected $affordanceId for slot $slotId")
context?.contentResolver?.notifyChange(Contract.SelectionTable.URI, null) context
Contract.SelectionTable.URI ?.contentResolver
?.notifyChange(Contract.LockScreenQuickAffordances.SelectionTable.URI, null)
Contract.LockScreenQuickAffordances.SelectionTable.URI
} else { } else {
Log.d(TAG, "Failed to select $affordanceId for slot $slotId") Log.d(TAG, "Failed to select $affordanceId for slot $slotId")
null null
@@ -218,9 +247,9 @@ class KeyguardQuickAffordanceProvider :
private suspend fun querySelections(): Cursor { private suspend fun querySelections(): Cursor {
return MatrixCursor( return MatrixCursor(
arrayOf( arrayOf(
Contract.SelectionTable.Columns.SLOT_ID, Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID,
Contract.SelectionTable.Columns.AFFORDANCE_ID, Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID,
Contract.SelectionTable.Columns.AFFORDANCE_NAME, Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_NAME,
) )
) )
.apply { .apply {
@@ -243,13 +272,16 @@ class KeyguardQuickAffordanceProvider :
private suspend fun queryAffordances(): Cursor { private suspend fun queryAffordances(): Cursor {
return MatrixCursor( return MatrixCursor(
arrayOf( arrayOf(
Contract.AffordanceTable.Columns.ID, Contract.LockScreenQuickAffordances.AffordanceTable.Columns.ID,
Contract.AffordanceTable.Columns.NAME, Contract.LockScreenQuickAffordances.AffordanceTable.Columns.NAME,
Contract.AffordanceTable.Columns.ICON, Contract.LockScreenQuickAffordances.AffordanceTable.Columns.ICON,
Contract.AffordanceTable.Columns.IS_ENABLED, Contract.LockScreenQuickAffordances.AffordanceTable.Columns.IS_ENABLED,
Contract.AffordanceTable.Columns.ENABLEMENT_INSTRUCTIONS, Contract.LockScreenQuickAffordances.AffordanceTable.Columns
Contract.AffordanceTable.Columns.ENABLEMENT_ACTION_TEXT, .ENABLEMENT_INSTRUCTIONS,
Contract.AffordanceTable.Columns.ENABLEMENT_COMPONENT_NAME, Contract.LockScreenQuickAffordances.AffordanceTable.Columns
.ENABLEMENT_ACTION_TEXT,
Contract.LockScreenQuickAffordances.AffordanceTable.Columns
.ENABLEMENT_COMPONENT_NAME,
) )
) )
.apply { .apply {
@@ -261,7 +293,8 @@ class KeyguardQuickAffordanceProvider :
representation.iconResourceId, representation.iconResourceId,
if (representation.isEnabled) 1 else 0, if (representation.isEnabled) 1 else 0,
representation.instructions?.joinToString( representation.instructions?.joinToString(
Contract.AffordanceTable.ENABLEMENT_INSTRUCTIONS_DELIMITER Contract.LockScreenQuickAffordances.AffordanceTable
.ENABLEMENT_INSTRUCTIONS_DELIMITER
), ),
representation.actionText, representation.actionText,
representation.actionComponentName, representation.actionComponentName,
@@ -274,8 +307,8 @@ class KeyguardQuickAffordanceProvider :
private fun querySlots(): Cursor { private fun querySlots(): Cursor {
return MatrixCursor( return MatrixCursor(
arrayOf( arrayOf(
Contract.SlotTable.Columns.ID, Contract.LockScreenQuickAffordances.SlotTable.Columns.ID,
Contract.SlotTable.Columns.CAPACITY, Contract.LockScreenQuickAffordances.SlotTable.Columns.CAPACITY,
) )
) )
.apply { .apply {

View File

@@ -22,7 +22,7 @@ import android.content.Intent
import com.android.systemui.animation.Expandable import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.Icon
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/** Defines interface that can act as data source for a single quick affordance model. */ /** Defines interface that can act as data source for a single quick affordance model. */
@@ -90,8 +90,9 @@ interface KeyguardQuickAffordanceConfig {
* the user to be able to set up the quick affordance and make it enabled. * the user to be able to set up the quick affordance and make it enabled.
* *
* This is either just an action for the `Intent` or a package name and action, * This is either just an action for the `Intent` or a package name and action,
* separated by [Contract.AffordanceTable.COMPONENT_NAME_SEPARATOR] for convenience, you * separated by
* can use the [componentName] function. * [Contract.LockScreenQuickAffordances.AffordanceTable.COMPONENT_NAME_SEPARATOR] for
* convenience, you can use the [componentName] function.
*/ */
val actionComponentName: String? = null, val actionComponentName: String? = null,
) : PickerScreenState() { ) : PickerScreenState() {
@@ -145,8 +146,8 @@ interface KeyguardQuickAffordanceConfig {
/** /**
* Returning this as a result from the [onTriggered] method means that the implementation * Returning this as a result from the [onTriggered] method means that the implementation
* has _not_ taken care of the action and the system should show a Dialog using the * has _not_ taken care of the action and the system should show a Dialog using the given
* given [AlertDialog] and [Expandable]. * [AlertDialog] and [Expandable].
*/ */
data class ShowDialog( data class ShowDialog(
val dialog: AlertDialog, val dialog: AlertDialog,
@@ -162,7 +163,8 @@ interface KeyguardQuickAffordanceConfig {
return when { return when {
action.isNullOrEmpty() -> null action.isNullOrEmpty() -> null
!packageName.isNullOrEmpty() -> !packageName.isNullOrEmpty() ->
"$packageName${Contract.AffordanceTable.COMPONENT_NAME_SEPARATOR}$action" "$packageName${Contract.LockScreenQuickAffordances.AffordanceTable
.COMPONENT_NAME_SEPARATOR}$action"
else -> action else -> action
} }
} }

View File

@@ -19,13 +19,13 @@ package com.android.systemui.keyguard.data.quickaffordance
import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderClient import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderClientImpl import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
interface KeyguardQuickAffordanceProviderClientFactory { interface KeyguardQuickAffordanceProviderClientFactory {
fun create(): KeyguardQuickAffordanceProviderClient fun create(): CustomizationProviderClient
} }
class KeyguardQuickAffordanceProviderClientFactoryImpl class KeyguardQuickAffordanceProviderClientFactoryImpl
@@ -34,8 +34,8 @@ constructor(
private val userTracker: UserTracker, private val userTracker: UserTracker,
@Background private val backgroundDispatcher: CoroutineDispatcher, @Background private val backgroundDispatcher: CoroutineDispatcher,
) : KeyguardQuickAffordanceProviderClientFactory { ) : KeyguardQuickAffordanceProviderClientFactory {
override fun create(): KeyguardQuickAffordanceProviderClient { override fun create(): CustomizationProviderClient {
return KeyguardQuickAffordanceProviderClientImpl( return CustomizationProviderClientImpl(
context = userTracker.userContext, context = userTracker.userContext,
backgroundDispatcher = backgroundDispatcher, backgroundDispatcher = backgroundDispatcher,
) )

View File

@@ -24,7 +24,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderClient import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -69,7 +69,7 @@ constructor(
awaitClose { userTracker.removeCallback(callback) } awaitClose { userTracker.removeCallback(callback) }
} }
private val clientOrNull: StateFlow<KeyguardQuickAffordanceProviderClient?> = private val clientOrNull: StateFlow<CustomizationProviderClient?> =
userId userId
.distinctUntilChanged() .distinctUntilChanged()
.map { selectedUserId -> .map { selectedUserId ->

View File

@@ -36,7 +36,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentati
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy import dagger.Lazy

View File

@@ -146,7 +146,7 @@
tools:replace="android:authorities" tools:replace="android:authorities"
tools:node="remove" /> tools:node="remove" />
<provider android:name="com.android.systemui.keyguard.KeyguardQuickAffordanceProvider" <provider android:name="com.android.systemui.keyguard.CustomizationProvider"
android:authorities="com.android.systemui.test.keyguard.quickaffordance.disabled" android:authorities="com.android.systemui.test.keyguard.quickaffordance.disabled"
android:enabled="false" android:enabled="false"
tools:replace="android:authorities" tools:replace="android:authorities"

View File

@@ -49,8 +49,8 @@ import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
@@ -75,7 +75,7 @@ import org.mockito.MockitoAnnotations
@SmallTest @SmallTest
@RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true) @TestableLooper.RunWithLooper(setAsMainLooper = true)
class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { class CustomizationProviderTest : SysuiTestCase() {
@Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var lockPatternUtils: LockPatternUtils
@Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var keyguardStateController: KeyguardStateController
@@ -87,7 +87,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
@Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage @Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage
@Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var launchAnimator: DialogLaunchAnimator
private lateinit var underTest: KeyguardQuickAffordanceProvider private lateinit var underTest: CustomizationProvider
private lateinit var testScope: TestScope private lateinit var testScope: TestScope
@@ -98,7 +98,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
whenever(previewRendererFactory.create(any())).thenReturn(previewRenderer) whenever(previewRendererFactory.create(any())).thenReturn(previewRenderer)
whenever(backgroundHandler.looper).thenReturn(TestableLooper.get(this).looper) whenever(backgroundHandler.looper).thenReturn(TestableLooper.get(this).looper)
underTest = KeyguardQuickAffordanceProvider() underTest = CustomizationProvider()
val testDispatcher = StandardTestDispatcher() val testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher) testScope = TestScope(testDispatcher)
val localUserSelectionManager = val localUserSelectionManager =
@@ -205,19 +205,34 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
@Test @Test
fun getType() { fun getType() {
assertThat(underTest.getType(Contract.AffordanceTable.URI)) assertThat(underTest.getType(Contract.LockScreenQuickAffordances.AffordanceTable.URI))
.isEqualTo( .isEqualTo(
"vnd.android.cursor.dir/vnd." + "vnd.android.cursor.dir/vnd." +
"${Contract.AUTHORITY}.${Contract.AffordanceTable.TABLE_NAME}" "${Contract.AUTHORITY}." +
Contract.LockScreenQuickAffordances.qualifiedTablePath(
Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME
) )
assertThat(underTest.getType(Contract.SlotTable.URI)) )
assertThat(underTest.getType(Contract.LockScreenQuickAffordances.SlotTable.URI))
.isEqualTo( .isEqualTo(
"vnd.android.cursor.dir/vnd.${Contract.AUTHORITY}.${Contract.SlotTable.TABLE_NAME}" "vnd.android.cursor.dir/vnd.${Contract.AUTHORITY}." +
Contract.LockScreenQuickAffordances.qualifiedTablePath(
Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME
) )
assertThat(underTest.getType(Contract.SelectionTable.URI)) )
assertThat(underTest.getType(Contract.LockScreenQuickAffordances.SelectionTable.URI))
.isEqualTo( .isEqualTo(
"vnd.android.cursor.dir/vnd." + "vnd.android.cursor.dir/vnd." +
"${Contract.AUTHORITY}.${Contract.SelectionTable.TABLE_NAME}" "${Contract.AUTHORITY}." +
Contract.LockScreenQuickAffordances.qualifiedTablePath(
Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME
)
)
assertThat(underTest.getType(Contract.FlagsTable.URI))
.isEqualTo(
"vnd.android.cursor.dir/vnd." +
"${Contract.AUTHORITY}." +
Contract.FlagsTable.TABLE_NAME
) )
} }
@@ -296,9 +311,10 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
) )
context.contentResolver.delete( context.contentResolver.delete(
Contract.SelectionTable.URI, Contract.LockScreenQuickAffordances.SelectionTable.URI,
"${Contract.SelectionTable.Columns.SLOT_ID} = ? AND" + "${Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID} = ? AND" +
" ${Contract.SelectionTable.Columns.AFFORDANCE_ID} = ?", " ${Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID}" +
" = ?",
arrayOf( arrayOf(
KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
AFFORDANCE_2, AFFORDANCE_2,
@@ -330,8 +346,8 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
) )
context.contentResolver.delete( context.contentResolver.delete(
Contract.SelectionTable.URI, Contract.LockScreenQuickAffordances.SelectionTable.URI,
Contract.SelectionTable.Columns.SLOT_ID, Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID,
arrayOf( arrayOf(
KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
), ),
@@ -371,10 +387,13 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
affordanceId: String, affordanceId: String,
) { ) {
context.contentResolver.insert( context.contentResolver.insert(
Contract.SelectionTable.URI, Contract.LockScreenQuickAffordances.SelectionTable.URI,
ContentValues().apply { ContentValues().apply {
put(Contract.SelectionTable.Columns.SLOT_ID, slotId) put(Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID, slotId)
put(Contract.SelectionTable.Columns.AFFORDANCE_ID, affordanceId) put(
Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID,
affordanceId
)
} }
) )
} }
@@ -382,7 +401,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
private fun querySelections(): List<Selection> { private fun querySelections(): List<Selection> {
return context.contentResolver return context.contentResolver
.query( .query(
Contract.SelectionTable.URI, Contract.LockScreenQuickAffordances.SelectionTable.URI,
null, null,
null, null,
null, null,
@@ -391,11 +410,18 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
?.use { cursor -> ?.use { cursor ->
buildList { buildList {
val slotIdColumnIndex = val slotIdColumnIndex =
cursor.getColumnIndex(Contract.SelectionTable.Columns.SLOT_ID) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID
)
val affordanceIdColumnIndex = val affordanceIdColumnIndex =
cursor.getColumnIndex(Contract.SelectionTable.Columns.AFFORDANCE_ID) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID
)
val affordanceNameColumnIndex = val affordanceNameColumnIndex =
cursor.getColumnIndex(Contract.SelectionTable.Columns.AFFORDANCE_NAME) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SelectionTable.Columns
.AFFORDANCE_NAME
)
if ( if (
slotIdColumnIndex == -1 || slotIdColumnIndex == -1 ||
affordanceIdColumnIndex == -1 || affordanceIdColumnIndex == -1 ||
@@ -421,7 +447,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
private fun querySlots(): List<Slot> { private fun querySlots(): List<Slot> {
return context.contentResolver return context.contentResolver
.query( .query(
Contract.SlotTable.URI, Contract.LockScreenQuickAffordances.SlotTable.URI,
null, null,
null, null,
null, null,
@@ -429,9 +455,14 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
) )
?.use { cursor -> ?.use { cursor ->
buildList { buildList {
val idColumnIndex = cursor.getColumnIndex(Contract.SlotTable.Columns.ID) val idColumnIndex =
cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SlotTable.Columns.ID
)
val capacityColumnIndex = val capacityColumnIndex =
cursor.getColumnIndex(Contract.SlotTable.Columns.CAPACITY) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.SlotTable.Columns.CAPACITY
)
if (idColumnIndex == -1 || capacityColumnIndex == -1) { if (idColumnIndex == -1 || capacityColumnIndex == -1) {
return@buildList return@buildList
} }
@@ -452,7 +483,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
private fun queryAffordances(): List<Affordance> { private fun queryAffordances(): List<Affordance> {
return context.contentResolver return context.contentResolver
.query( .query(
Contract.AffordanceTable.URI, Contract.LockScreenQuickAffordances.AffordanceTable.URI,
null, null,
null, null,
null, null,
@@ -460,11 +491,18 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
) )
?.use { cursor -> ?.use { cursor ->
buildList { buildList {
val idColumnIndex = cursor.getColumnIndex(Contract.AffordanceTable.Columns.ID) val idColumnIndex =
cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns.ID
)
val nameColumnIndex = val nameColumnIndex =
cursor.getColumnIndex(Contract.AffordanceTable.Columns.NAME) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns.NAME
)
val iconColumnIndex = val iconColumnIndex =
cursor.getColumnIndex(Contract.AffordanceTable.Columns.ICON) cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns.ICON
)
if (idColumnIndex == -1 || nameColumnIndex == -1 || iconColumnIndex == -1) { if (idColumnIndex == -1 || nameColumnIndex == -1 || iconColumnIndex == -1) {
return@buildList return@buildList
} }

View File

@@ -22,8 +22,8 @@ import android.os.UserHandle
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.shared.customization.data.content.FakeCustomizationProviderClient
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.shared.quickaffordance.data.content.FakeKeyguardQuickAffordanceProviderClient
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -54,16 +54,16 @@ class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
private lateinit var testScope: TestScope private lateinit var testScope: TestScope
private lateinit var testDispatcher: TestDispatcher private lateinit var testDispatcher: TestDispatcher
private lateinit var userTracker: FakeUserTracker private lateinit var userTracker: FakeUserTracker
private lateinit var client1: FakeKeyguardQuickAffordanceProviderClient private lateinit var client1: FakeCustomizationProviderClient
private lateinit var client2: FakeKeyguardQuickAffordanceProviderClient private lateinit var client2: FakeCustomizationProviderClient
@Before @Before
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
whenever(userHandle.identifier).thenReturn(UserHandle.USER_SYSTEM) whenever(userHandle.identifier).thenReturn(UserHandle.USER_SYSTEM)
whenever(userHandle.isSystem).thenReturn(true) whenever(userHandle.isSystem).thenReturn(true)
client1 = FakeKeyguardQuickAffordanceProviderClient() client1 = FakeCustomizationProviderClient()
client2 = FakeKeyguardQuickAffordanceProviderClient() client2 = FakeCustomizationProviderClient()
userTracker = FakeUserTracker() userTracker = FakeUserTracker()
userTracker.set( userTracker.set(
@@ -122,11 +122,11 @@ class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
client1.insertSelection( client1.insertSelection(
slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
affordanceId = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1, affordanceId = FakeCustomizationProviderClient.AFFORDANCE_1,
) )
client2.insertSelection( client2.insertSelection(
slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
affordanceId = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2, affordanceId = FakeCustomizationProviderClient.AFFORDANCE_2,
) )
userTracker.set( userTracker.set(
@@ -139,7 +139,7 @@ class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
mapOf( mapOf(
KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
listOf( listOf(
FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1, FakeCustomizationProviderClient.AFFORDANCE_1,
), ),
) )
) )
@@ -154,7 +154,7 @@ class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
mapOf( mapOf(
KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to
listOf( listOf(
FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2, FakeCustomizationProviderClient.AFFORDANCE_2,
), ),
) )
) )
@@ -174,7 +174,7 @@ class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
client1.insertSelection( client1.insertSelection(
slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
affordanceId = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1, affordanceId = FakeCustomizationProviderClient.AFFORDANCE_1,
) )
userTracker.set( userTracker.set(
userInfos = userTracker.userProfiles, userInfos = userTracker.userProfiles,
@@ -197,7 +197,7 @@ class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
underTest.setSelections( underTest.setSelections(
slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
affordanceIds = listOf(FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1), affordanceIds = listOf(FakeCustomizationProviderClient.AFFORDANCE_1),
) )
runCurrent() runCurrent()
@@ -206,7 +206,7 @@ class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
mapOf( mapOf(
KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
listOf( listOf(
FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1, FakeCustomizationProviderClient.AFFORDANCE_1,
), ),
) )
) )

View File

@@ -32,8 +32,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerR
import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation
import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserFileManager
import com.android.systemui.shared.customization.data.content.FakeCustomizationProviderClient
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.shared.quickaffordance.data.content.FakeKeyguardQuickAffordanceProviderClient
import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
@@ -63,19 +63,13 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() {
private lateinit var config1: FakeKeyguardQuickAffordanceConfig private lateinit var config1: FakeKeyguardQuickAffordanceConfig
private lateinit var config2: FakeKeyguardQuickAffordanceConfig private lateinit var config2: FakeKeyguardQuickAffordanceConfig
private lateinit var userTracker: FakeUserTracker private lateinit var userTracker: FakeUserTracker
private lateinit var client1: FakeKeyguardQuickAffordanceProviderClient private lateinit var client1: FakeCustomizationProviderClient
private lateinit var client2: FakeKeyguardQuickAffordanceProviderClient private lateinit var client2: FakeCustomizationProviderClient
@Before @Before
fun setUp() { fun setUp() {
config1 = config1 = FakeKeyguardQuickAffordanceConfig(FakeCustomizationProviderClient.AFFORDANCE_1)
FakeKeyguardQuickAffordanceConfig( config2 = FakeKeyguardQuickAffordanceConfig(FakeCustomizationProviderClient.AFFORDANCE_2)
FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1
)
config2 =
FakeKeyguardQuickAffordanceConfig(
FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2
)
val scope = CoroutineScope(IMMEDIATE) val scope = CoroutineScope(IMMEDIATE)
userTracker = FakeUserTracker() userTracker = FakeUserTracker()
val localUserSelectionManager = val localUserSelectionManager =
@@ -95,8 +89,8 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() {
userTracker = userTracker, userTracker = userTracker,
broadcastDispatcher = fakeBroadcastDispatcher, broadcastDispatcher = fakeBroadcastDispatcher,
) )
client1 = FakeKeyguardQuickAffordanceProviderClient() client1 = FakeCustomizationProviderClient()
client2 = FakeKeyguardQuickAffordanceProviderClient() client2 = FakeCustomizationProviderClient()
val remoteUserSelectionManager = val remoteUserSelectionManager =
KeyguardQuickAffordanceRemoteUserSelectionManager( KeyguardQuickAffordanceRemoteUserSelectionManager(
scope = scope, scope = scope,
@@ -256,7 +250,7 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() {
) )
client2.insertSelection( client2.insertSelection(
slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
affordanceId = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2, affordanceId = FakeCustomizationProviderClient.AFFORDANCE_2,
) )
val observed = mutableListOf<Map<String, List<KeyguardQuickAffordanceConfig>>>() val observed = mutableListOf<Map<String, List<KeyguardQuickAffordanceConfig>>>()
val job = underTest.selections.onEach { observed.add(it) }.launchIn(this) val job = underTest.selections.onEach { observed.add(it) }.launchIn(this)

View File

@@ -18,17 +18,17 @@
package com.android.systemui.keyguard.data.quickaffordance package com.android.systemui.keyguard.data.quickaffordance
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.quickaffordance.data.content.FakeKeyguardQuickAffordanceProviderClient import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderClient import com.android.systemui.shared.customization.data.content.FakeCustomizationProviderClient
class FakeKeyguardQuickAffordanceProviderClientFactory( class FakeKeyguardQuickAffordanceProviderClientFactory(
private val userTracker: UserTracker, private val userTracker: UserTracker,
private val callback: (Int) -> KeyguardQuickAffordanceProviderClient = { private val callback: (Int) -> CustomizationProviderClient = {
FakeKeyguardQuickAffordanceProviderClient() FakeCustomizationProviderClient()
}, },
) : KeyguardQuickAffordanceProviderClientFactory { ) : KeyguardQuickAffordanceProviderClientFactory {
override fun create(): KeyguardQuickAffordanceProviderClient { override fun create(): CustomizationProviderClient {
return callback(userTracker.userId) return callback(userTracker.userId)
} }
} }