Merge "Controls UI - Stateless controls" into rvc-dev am: dbc90fad28 am: 02ac81a897
Change-Id: I4260a01e0082987fc6da0e8f8afd8fda96ba0e0f
This commit is contained in:
@@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
package com.android.systemui.controls
|
package com.android.systemui.controls
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
import android.service.controls.Control
|
import android.service.controls.Control
|
||||||
|
|
||||||
data class ControlStatus(
|
data class ControlStatus(
|
||||||
val control: Control,
|
val control: Control,
|
||||||
|
val component: ComponentName,
|
||||||
var favorite: Boolean,
|
var favorite: Boolean,
|
||||||
val removed: Boolean = false
|
val removed: Boolean = false
|
||||||
)
|
)
|
||||||
@@ -238,7 +238,11 @@ class ControlsControllerImpl @Inject constructor (
|
|||||||
}
|
}
|
||||||
val removed = findRemoved(favoritesForComponentKeys.toSet(), controls)
|
val removed = findRemoved(favoritesForComponentKeys.toSet(), controls)
|
||||||
val controlsWithFavorite = controls.map {
|
val controlsWithFavorite = controls.map {
|
||||||
ControlStatus(it, it.controlId in favoritesForComponentKeys)
|
ControlStatus(
|
||||||
|
it,
|
||||||
|
componentName,
|
||||||
|
it.controlId in favoritesForComponentKeys
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val loadData = createLoadDataObject(
|
val loadData = createLoadDataObject(
|
||||||
Favorites.getControlsForComponent(componentName)
|
Favorites.getControlsForComponent(componentName)
|
||||||
@@ -290,7 +294,7 @@ class ControlsControllerImpl @Inject constructor (
|
|||||||
.setTitle(controlInfo.controlTitle)
|
.setTitle(controlInfo.controlTitle)
|
||||||
.setDeviceType(controlInfo.deviceType)
|
.setDeviceType(controlInfo.deviceType)
|
||||||
.build()
|
.build()
|
||||||
return ControlStatus(control, true, setRemoved)
|
return ControlStatus(control, componentName, true, setRemoved)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findRemoved(favoriteKeys: Set<String>, list: List<Control>): Set<String> {
|
private fun findRemoved(favoriteKeys: Set<String>, list: List<Control>): Set<String> {
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
package com.android.systemui.controls.management
|
package com.android.systemui.controls.management
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.graphics.drawable.Icon
|
|
||||||
import android.service.controls.DeviceTypes
|
import android.service.controls.DeviceTypes
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -147,7 +147,7 @@ private class ControlHolder(view: View, val favoriteCallback: ModelFavoriteChang
|
|||||||
override fun bindData(wrapper: ElementWrapper) {
|
override fun bindData(wrapper: ElementWrapper) {
|
||||||
wrapper as ControlWrapper
|
wrapper as ControlWrapper
|
||||||
val data = wrapper.controlStatus
|
val data = wrapper.controlStatus
|
||||||
val renderInfo = getRenderInfo(data.control.deviceType)
|
val renderInfo = getRenderInfo(data.component, data.control.deviceType)
|
||||||
title.text = data.control.title
|
title.text = data.control.title
|
||||||
subtitle.text = data.control.subtitle
|
subtitle.text = data.control.subtitle
|
||||||
favorite.isChecked = data.favorite
|
favorite.isChecked = data.favorite
|
||||||
@@ -160,16 +160,17 @@ private class ControlHolder(view: View, val favoriteCallback: ModelFavoriteChang
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getRenderInfo(
|
private fun getRenderInfo(
|
||||||
|
component: ComponentName,
|
||||||
@DeviceTypes.DeviceType deviceType: Int
|
@DeviceTypes.DeviceType deviceType: Int
|
||||||
): RenderInfo {
|
): RenderInfo {
|
||||||
return RenderInfo.lookup(deviceType, true)
|
return RenderInfo.lookup(itemView.context, component, deviceType, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applyRenderInfo(ri: RenderInfo) {
|
private fun applyRenderInfo(ri: RenderInfo) {
|
||||||
val context = itemView.context
|
val context = itemView.context
|
||||||
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
|
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
|
||||||
|
|
||||||
icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
|
icon.setImageDrawable(ri.icon)
|
||||||
icon.setImageTintList(fg)
|
icon.setImageTintList(fg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import android.app.Dialog
|
|||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.drawable.Icon
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.UserHandle
|
import android.os.UserHandle
|
||||||
import android.service.controls.Control
|
import android.service.controls.Control
|
||||||
@@ -137,11 +136,10 @@ class ControlsRequestDialog @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createDialog(label: CharSequence): Dialog {
|
fun createDialog(label: CharSequence): Dialog {
|
||||||
|
val renderInfo = RenderInfo.lookup(this, component, control.deviceType, true)
|
||||||
val renderInfo = RenderInfo.lookup(control.deviceType, true)
|
|
||||||
val frame = LayoutInflater.from(this).inflate(R.layout.controls_dialog, null).apply {
|
val frame = LayoutInflater.from(this).inflate(R.layout.controls_dialog, null).apply {
|
||||||
requireViewById<ImageView>(R.id.icon).apply {
|
requireViewById<ImageView>(R.id.icon).apply {
|
||||||
setImageIcon(Icon.createWithResource(context, renderInfo.iconResourceId))
|
setImageDrawable(renderInfo.icon)
|
||||||
setImageTintList(
|
setImageTintList(
|
||||||
context.resources.getColorStateList(renderInfo.foreground, context.theme))
|
context.resources.getColorStateList(renderInfo.foreground, context.theme))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import android.app.PendingIntent
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.service.controls.actions.BooleanAction
|
import android.service.controls.actions.BooleanAction
|
||||||
|
import android.service.controls.actions.CommandAction
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.HapticFeedbackConstants
|
import android.view.HapticFeedbackConstants
|
||||||
|
|
||||||
@@ -36,6 +37,10 @@ object ControlActionCoordinator {
|
|||||||
cvh.clipLayer.setLevel(nextLevel)
|
cvh.clipLayer.setLevel(nextLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun touch(cvh: ControlViewHolder, templateId: String) {
|
||||||
|
cvh.action(CommandAction(templateId))
|
||||||
|
}
|
||||||
|
|
||||||
fun longPress(cvh: ControlViewHolder) {
|
fun longPress(cvh: ControlViewHolder) {
|
||||||
// Long press snould only be called when there is valid control state, otherwise ignore
|
// Long press snould only be called when there is valid control state, otherwise ignore
|
||||||
cvh.cws.control?.let {
|
cvh.cws.control?.let {
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ package com.android.systemui.controls.ui
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.BlendMode
|
import android.graphics.BlendMode
|
||||||
import android.graphics.drawable.ClipDrawable
|
import android.graphics.drawable.ClipDrawable
|
||||||
import android.graphics.drawable.Icon
|
|
||||||
import android.graphics.drawable.LayerDrawable
|
import android.graphics.drawable.LayerDrawable
|
||||||
import android.service.controls.Control
|
import android.service.controls.Control
|
||||||
import android.service.controls.actions.ControlAction
|
import android.service.controls.actions.ControlAction
|
||||||
import android.service.controls.templates.ControlTemplate
|
import android.service.controls.templates.ControlTemplate
|
||||||
|
import android.service.controls.templates.StatelessTemplate
|
||||||
import android.service.controls.templates.TemperatureControlTemplate
|
import android.service.controls.templates.TemperatureControlTemplate
|
||||||
import android.service.controls.templates.ToggleRangeTemplate
|
import android.service.controls.templates.ToggleRangeTemplate
|
||||||
import android.service.controls.templates.ToggleTemplate
|
import android.service.controls.templates.ToggleTemplate
|
||||||
@@ -122,19 +122,25 @@ class ControlViewHolder(
|
|||||||
return when {
|
return when {
|
||||||
status == Control.STATUS_UNKNOWN -> UnknownBehavior::class
|
status == Control.STATUS_UNKNOWN -> UnknownBehavior::class
|
||||||
template is ToggleTemplate -> ToggleBehavior::class
|
template is ToggleTemplate -> ToggleBehavior::class
|
||||||
|
template is StatelessTemplate -> TouchBehavior::class
|
||||||
template is ToggleRangeTemplate -> ToggleRangeBehavior::class
|
template is ToggleRangeTemplate -> ToggleRangeBehavior::class
|
||||||
template is TemperatureControlTemplate -> TemperatureControlBehavior::class
|
template is TemperatureControlTemplate -> TemperatureControlBehavior::class
|
||||||
else -> DefaultBehavior::class
|
else -> DefaultBehavior::class
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun applyRenderInfo(ri: RenderInfo) {
|
internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0) {
|
||||||
|
setEnabled(enabled)
|
||||||
|
|
||||||
|
val deviceType = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
|
||||||
|
val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset)
|
||||||
|
|
||||||
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
|
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
|
||||||
val bg = context.getResources().getColorStateList(ri.background, context.getTheme())
|
val bg = context.getResources().getColorStateList(ri.background, context.getTheme())
|
||||||
status.setTextColor(fg)
|
status.setTextColor(fg)
|
||||||
statusExtra.setTextColor(fg)
|
statusExtra.setTextColor(fg)
|
||||||
|
|
||||||
icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
|
icon.setImageDrawable(ri.icon)
|
||||||
icon.setImageTintList(fg)
|
icon.setImageTintList(fg)
|
||||||
|
|
||||||
clipLayer.getDrawable().apply {
|
clipLayer.getDrawable().apply {
|
||||||
@@ -143,7 +149,7 @@ class ControlViewHolder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setEnabled(enabled: Boolean) {
|
private fun setEnabled(enabled: Boolean) {
|
||||||
status.setEnabled(enabled)
|
status.setEnabled(enabled)
|
||||||
icon.setEnabled(enabled)
|
icon.setEnabled(enabled)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,36 +188,23 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
parent.removeAllViews()
|
parent.removeAllViews()
|
||||||
controlViewsById.clear()
|
controlViewsById.clear()
|
||||||
|
|
||||||
val inflater = LayoutInflater.from(context)
|
createListView()
|
||||||
inflater.inflate(R.layout.controls_with_favorites, parent, true)
|
createDropDown(items)
|
||||||
|
|
||||||
val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
|
|
||||||
var lastRow: ViewGroup = createRow(inflater, listView)
|
|
||||||
selectedStructure.controls.forEach {
|
|
||||||
if (lastRow.getChildCount() == 2) {
|
|
||||||
lastRow = createRow(inflater, listView)
|
|
||||||
}
|
|
||||||
val item = inflater.inflate(
|
|
||||||
R.layout.controls_base_item, lastRow, false) as ViewGroup
|
|
||||||
lastRow.addView(item)
|
|
||||||
val cvh = ControlViewHolder(item, controlsController.get(), uiExecutor, bgExecutor)
|
|
||||||
val key = ControlKey(selectedStructure.componentName, it.controlId)
|
|
||||||
cvh.bindData(controlsById.getValue(key))
|
|
||||||
controlViewsById.put(key, cvh)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add spacer if necessary to keep control size consistent
|
private fun createDropDown(items: List<SelectionItem>) {
|
||||||
if ((selectedStructure.controls.size % 2) == 1) {
|
items.forEach {
|
||||||
lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
|
RenderInfo.registerComponentIcon(it.componentName, it.icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
val itemsByComponent = items.associateBy { it.componentName }
|
val itemsByComponent = items.associateBy { it.componentName }
|
||||||
var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
|
val itemsWithStructure = allStructures.mapNotNull {
|
||||||
val listItems = allStructures.mapNotNull {
|
|
||||||
itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
|
itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
|
||||||
}
|
}
|
||||||
|
val selectionItem = findSelectionItem(selectedStructure, itemsWithStructure) ?: items[0]
|
||||||
|
|
||||||
addAll(listItems + addControlsItem)
|
var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
|
||||||
|
addAll(itemsWithStructure + addControlsItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -225,16 +212,15 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
* for this dialog. Use a textView with the ListPopupWindow to achieve
|
* for this dialog. Use a textView with the ListPopupWindow to achieve
|
||||||
* a similar effect
|
* a similar effect
|
||||||
*/
|
*/
|
||||||
val item = adapter.findSelectionItem(selectedStructure) ?: adapter.getItem(0)
|
|
||||||
parent.requireViewById<TextView>(R.id.app_or_structure_spinner).apply {
|
parent.requireViewById<TextView>(R.id.app_or_structure_spinner).apply {
|
||||||
setText(item.getTitle())
|
setText(selectionItem.getTitle())
|
||||||
// override the default color on the dropdown drawable
|
// override the default color on the dropdown drawable
|
||||||
(getBackground() as LayerDrawable).getDrawable(1)
|
(getBackground() as LayerDrawable).getDrawable(1)
|
||||||
.setTint(context.resources.getColor(R.color.control_spinner_dropdown, null))
|
.setTint(context.resources.getColor(R.color.control_spinner_dropdown, null))
|
||||||
}
|
}
|
||||||
parent.requireViewById<ImageView>(R.id.app_icon).apply {
|
parent.requireViewById<ImageView>(R.id.app_icon).apply {
|
||||||
setContentDescription(item.getTitle())
|
setContentDescription(selectionItem.getTitle())
|
||||||
setImageDrawable(item.icon)
|
setImageDrawable(selectionItem.icon)
|
||||||
}
|
}
|
||||||
val anchor = parent.requireViewById<ViewGroup>(R.id.controls_header)
|
val anchor = parent.requireViewById<ViewGroup>(R.id.controls_header)
|
||||||
anchor.setOnClickListener(object : View.OnClickListener {
|
anchor.setOnClickListener(object : View.OnClickListener {
|
||||||
@@ -272,6 +258,36 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createListView() {
|
||||||
|
val inflater = LayoutInflater.from(context)
|
||||||
|
inflater.inflate(R.layout.controls_with_favorites, parent, true)
|
||||||
|
|
||||||
|
val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
|
||||||
|
var lastRow: ViewGroup = createRow(inflater, listView)
|
||||||
|
selectedStructure.controls.forEach {
|
||||||
|
if (lastRow.getChildCount() == 2) {
|
||||||
|
lastRow = createRow(inflater, listView)
|
||||||
|
}
|
||||||
|
val baseLayout = inflater.inflate(
|
||||||
|
R.layout.controls_base_item, lastRow, false) as ViewGroup
|
||||||
|
lastRow.addView(baseLayout)
|
||||||
|
val cvh = ControlViewHolder(
|
||||||
|
baseLayout,
|
||||||
|
controlsController.get(),
|
||||||
|
uiExecutor,
|
||||||
|
bgExecutor
|
||||||
|
)
|
||||||
|
val key = ControlKey(selectedStructure.componentName, it.controlId)
|
||||||
|
cvh.bindData(controlsById.getValue(key))
|
||||||
|
controlViewsById.put(key, cvh)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add spacer if necessary to keep control size consistent
|
||||||
|
if ((selectedStructure.controls.size % 2) == 1) {
|
||||||
|
lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadPreference(structures: List<StructureInfo>): StructureInfo {
|
private fun loadPreference(structures: List<StructureInfo>): StructureInfo {
|
||||||
if (structures.isEmpty()) return EMPTY_STRUCTURE
|
if (structures.isEmpty()) return EMPTY_STRUCTURE
|
||||||
|
|
||||||
@@ -320,6 +336,8 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
controlsById.clear()
|
controlsById.clear()
|
||||||
controlViewsById.clear()
|
controlViewsById.clear()
|
||||||
controlsListingController.get().removeCallback(listingCallback)
|
controlsListingController.get().removeCallback(listingCallback)
|
||||||
|
|
||||||
|
RenderInfo.clearCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRefreshState(componentName: ComponentName, controls: List<Control>) {
|
override fun onRefreshState(componentName: ComponentName, controls: List<Control>) {
|
||||||
@@ -358,6 +376,11 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
listView.addView(row)
|
listView.addView(row)
|
||||||
return row
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findSelectionItem(si: StructureInfo, items: List<SelectionItem>): SelectionItem? =
|
||||||
|
items.firstOrNull {
|
||||||
|
it.componentName == si.componentName && it.structure == si.structure
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class SelectionItem(
|
private data class SelectionItem(
|
||||||
@@ -388,17 +411,4 @@ private class ItemAdapter(
|
|||||||
}
|
}
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findSelectionItem(si: StructureInfo): SelectionItem? {
|
|
||||||
var i = 0
|
|
||||||
while (i < getCount()) {
|
|
||||||
val item = getItem(i)
|
|
||||||
if (item.componentName == si.componentName &&
|
|
||||||
item.structure == si.structure) {
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ class DefaultBehavior : Behavior {
|
|||||||
|
|
||||||
override fun bind(cws: ControlWithState) {
|
override fun bind(cws: ControlWithState) {
|
||||||
cvh.status.setText(cws.control?.getStatusText() ?: "")
|
cvh.status.setText(cws.control?.getStatusText() ?: "")
|
||||||
cvh.setEnabled(false)
|
cvh.applyRenderInfo(false)
|
||||||
cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,14 @@
|
|||||||
|
|
||||||
package com.android.systemui.controls.ui
|
package com.android.systemui.controls.ui
|
||||||
|
|
||||||
|
import android.annotation.MainThread
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.service.controls.DeviceTypes
|
import android.service.controls.DeviceTypes
|
||||||
import android.service.controls.templates.TemperatureControlTemplate
|
import android.service.controls.templates.TemperatureControlTemplate
|
||||||
|
import android.util.ArrayMap
|
||||||
|
import android.util.SparseArray
|
||||||
|
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
|
|
||||||
@@ -31,18 +37,54 @@ data class IconState(val disabledResourceId: Int, val enabledResourceId: Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class RenderInfo(val iconResourceId: Int, val foreground: Int, val background: Int) {
|
data class RenderInfo(val icon: Drawable, val foreground: Int, val background: Int) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun lookup(deviceType: Int, enabled: Boolean): RenderInfo {
|
const val APP_ICON_ID = -1
|
||||||
val iconState = deviceIconMap.getValue(deviceType)
|
private val iconMap = SparseArray<Drawable>()
|
||||||
|
private val appIconMap = ArrayMap<ComponentName, Drawable>()
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
fun lookup(
|
||||||
|
context: Context,
|
||||||
|
componentName: ComponentName,
|
||||||
|
deviceType: Int,
|
||||||
|
enabled: Boolean,
|
||||||
|
offset: Int = 0
|
||||||
|
): RenderInfo {
|
||||||
val (fg, bg) = deviceColorMap.getValue(deviceType)
|
val (fg, bg) = deviceColorMap.getValue(deviceType)
|
||||||
return RenderInfo(iconState[enabled], fg, bg)
|
|
||||||
|
val iconKey = if (offset > 0) {
|
||||||
|
deviceType * BUCKET_SIZE + offset
|
||||||
|
} else deviceType
|
||||||
|
|
||||||
|
val iconState = deviceIconMap.getValue(iconKey)
|
||||||
|
val resourceId = iconState[enabled]
|
||||||
|
var icon: Drawable? = null
|
||||||
|
if (resourceId == APP_ICON_ID) {
|
||||||
|
icon = appIconMap.get(componentName)
|
||||||
|
if (icon == null) {
|
||||||
|
icon = context.resources
|
||||||
|
.getDrawable(R.drawable.ic_device_unknown_gm2_24px, null)
|
||||||
|
appIconMap.put(componentName, icon)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
icon = iconMap.get(resourceId)
|
||||||
|
if (icon == null) {
|
||||||
|
icon = context.resources.getDrawable(resourceId, null)
|
||||||
|
iconMap.put(resourceId, icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RenderInfo(icon!!, fg, bg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun lookup(deviceType: Int, offset: Int, enabled: Boolean): RenderInfo {
|
fun registerComponentIcon(componentName: ComponentName, icon: Drawable) {
|
||||||
val key = deviceType * BUCKET_SIZE + offset
|
appIconMap.put(componentName, icon)
|
||||||
return lookup(key, enabled)
|
}
|
||||||
|
|
||||||
|
fun clearCache() {
|
||||||
|
iconMap.clear()
|
||||||
|
appIconMap.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,6 +158,10 @@ private val deviceIconMap = mapOf<Int, IconState>(
|
|||||||
DeviceTypes.TYPE_MOP to IconState(
|
DeviceTypes.TYPE_MOP to IconState(
|
||||||
R.drawable.ic_vacuum_gm2_24px,
|
R.drawable.ic_vacuum_gm2_24px,
|
||||||
R.drawable.ic_vacuum_gm2_24px
|
R.drawable.ic_vacuum_gm2_24px
|
||||||
|
),
|
||||||
|
DeviceTypes.TYPE_ROUTINE to IconState(
|
||||||
|
RenderInfo.APP_ICON_ID,
|
||||||
|
RenderInfo.APP_ICON_ID
|
||||||
)
|
)
|
||||||
).withDefault {
|
).withDefault {
|
||||||
IconState(
|
IconState(
|
||||||
|
|||||||
@@ -47,10 +47,7 @@ class TemperatureControlBehavior : Behavior {
|
|||||||
|
|
||||||
val activeMode = template.getCurrentActiveMode()
|
val activeMode = template.getCurrentActiveMode()
|
||||||
val enabled = activeMode != 0 && activeMode != TemperatureControlTemplate.MODE_OFF
|
val enabled = activeMode != 0 && activeMode != TemperatureControlTemplate.MODE_OFF
|
||||||
val deviceType = control.getDeviceType()
|
|
||||||
|
|
||||||
clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
|
clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
|
||||||
cvh.setEnabled(enabled)
|
cvh.applyRenderInfo(enabled, activeMode)
|
||||||
cvh.applyRenderInfo(RenderInfo.lookup(deviceType, activeMode, enabled))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ToggleBehavior : Behavior {
|
|||||||
|
|
||||||
override fun initialize(cvh: ControlViewHolder) {
|
override fun initialize(cvh: ControlViewHolder) {
|
||||||
this.cvh = cvh
|
this.cvh = cvh
|
||||||
cvh.setEnabled(false)
|
cvh.applyRenderInfo(false)
|
||||||
|
|
||||||
cvh.layout.setOnClickListener(View.OnClickListener() {
|
cvh.layout.setOnClickListener(View.OnClickListener() {
|
||||||
ControlActionCoordinator.toggle(cvh, template.getTemplateId(), template.isChecked())
|
ControlActionCoordinator.toggle(cvh, template.getTemplateId(), template.isChecked())
|
||||||
@@ -51,10 +51,7 @@ class ToggleBehavior : Behavior {
|
|||||||
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
|
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
|
||||||
|
|
||||||
val checked = template.isChecked()
|
val checked = template.isChecked()
|
||||||
val deviceType = control.getDeviceType()
|
|
||||||
|
|
||||||
clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL)
|
clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL)
|
||||||
cvh.setEnabled(checked)
|
cvh.applyRenderInfo(checked)
|
||||||
cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class ToggleRangeBehavior : Behavior {
|
|||||||
status = cvh.status
|
status = cvh.status
|
||||||
context = status.getContext()
|
context = status.getContext()
|
||||||
|
|
||||||
cvh.setEnabled(false)
|
cvh.applyRenderInfo(false)
|
||||||
|
|
||||||
val gestureListener = ToggleRangeGestureListener(cvh.layout)
|
val gestureListener = ToggleRangeGestureListener(cvh.layout)
|
||||||
val gestureDetector = GestureDetector(context, gestureListener)
|
val gestureDetector = GestureDetector(context, gestureListener)
|
||||||
@@ -89,14 +89,11 @@ class ToggleRangeBehavior : Behavior {
|
|||||||
rangeTemplate = template.getRange()
|
rangeTemplate = template.getRange()
|
||||||
|
|
||||||
val checked = template.isChecked()
|
val checked = template.isChecked()
|
||||||
val deviceType = control.getDeviceType()
|
|
||||||
|
|
||||||
val currentRatio = rangeTemplate.getCurrentValue() /
|
val currentRatio = rangeTemplate.getCurrentValue() /
|
||||||
(rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
|
(rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
|
||||||
updateRange(currentRatio, checked)
|
updateRange(currentRatio, checked)
|
||||||
|
|
||||||
cvh.setEnabled(checked)
|
cvh.applyRenderInfo(checked)
|
||||||
cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun beginUpdateRange() {
|
fun beginUpdateRange() {
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.controls.ui
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.graphics.drawable.LayerDrawable
|
||||||
|
import android.view.View
|
||||||
|
import android.service.controls.Control
|
||||||
|
import android.service.controls.templates.StatelessTemplate
|
||||||
|
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supports touch events, but has no notion of state as the {@link ToggleBehavior} does. Must be
|
||||||
|
* used with {@link StatelessTemplate}.
|
||||||
|
*/
|
||||||
|
class TouchBehavior : Behavior {
|
||||||
|
lateinit var clipLayer: Drawable
|
||||||
|
lateinit var template: StatelessTemplate
|
||||||
|
lateinit var control: Control
|
||||||
|
lateinit var cvh: ControlViewHolder
|
||||||
|
|
||||||
|
override fun initialize(cvh: ControlViewHolder) {
|
||||||
|
this.cvh = cvh
|
||||||
|
cvh.applyRenderInfo(false)
|
||||||
|
|
||||||
|
cvh.layout.setOnClickListener(View.OnClickListener() {
|
||||||
|
ControlActionCoordinator.touch(cvh, template.getTemplateId())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bind(cws: ControlWithState) {
|
||||||
|
this.control = cws.control!!
|
||||||
|
cvh.status.setText(control.getStatusText())
|
||||||
|
template = control.getControlTemplate() as StatelessTemplate
|
||||||
|
|
||||||
|
val ld = cvh.layout.getBackground() as LayerDrawable
|
||||||
|
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
|
||||||
|
clipLayer.setLevel(MIN_LEVEL)
|
||||||
|
|
||||||
|
cvh.applyRenderInfo(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ class UnknownBehavior : Behavior {
|
|||||||
|
|
||||||
override fun bind(cws: ControlWithState) {
|
override fun bind(cws: ControlWithState) {
|
||||||
cvh.status.setText(cvh.context.getString(com.android.internal.R.string.loading))
|
cvh.status.setText(cvh.context.getString(com.android.internal.R.string.loading))
|
||||||
cvh.setEnabled(false)
|
cvh.applyRenderInfo(false)
|
||||||
cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
|||||||
loaded = true
|
loaded = true
|
||||||
assertEquals(1, controls.size)
|
assertEquals(1, controls.size)
|
||||||
val controlStatus = controls[0]
|
val controlStatus = controls[0]
|
||||||
assertEquals(ControlStatus(control, false), controlStatus)
|
assertEquals(ControlStatus(control, TEST_COMPONENT, false), controlStatus)
|
||||||
|
|
||||||
assertTrue(favorites.isEmpty())
|
assertTrue(favorites.isEmpty())
|
||||||
assertFalse(data.errorOnLoad)
|
assertFalse(data.errorOnLoad)
|
||||||
@@ -265,10 +265,10 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
|||||||
loaded = true
|
loaded = true
|
||||||
assertEquals(2, controls.size)
|
assertEquals(2, controls.size)
|
||||||
val controlStatus = controls.first { it.control.controlId == TEST_CONTROL_ID }
|
val controlStatus = controls.first { it.control.controlId == TEST_CONTROL_ID }
|
||||||
assertEquals(ControlStatus(control, true), controlStatus)
|
assertEquals(ControlStatus(control, TEST_COMPONENT, true), controlStatus)
|
||||||
|
|
||||||
val controlStatus2 = controls.first { it.control.controlId == TEST_CONTROL_ID_2 }
|
val controlStatus2 = controls.first { it.control.controlId == TEST_CONTROL_ID_2 }
|
||||||
assertEquals(ControlStatus(control2, false), controlStatus2)
|
assertEquals(ControlStatus(control2, TEST_COMPONENT, false), controlStatus2)
|
||||||
|
|
||||||
assertEquals(1, favorites.size)
|
assertEquals(1, favorites.size)
|
||||||
assertEquals(TEST_CONTROL_ID, favorites[0])
|
assertEquals(TEST_CONTROL_ID, favorites[0])
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.systemui.controls.management
|
package com.android.systemui.controls.management
|
||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
|
import android.content.ComponentName
|
||||||
import android.service.controls.Control
|
import android.service.controls.Control
|
||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
@@ -78,6 +79,7 @@ class AllModelTest : SysuiTestCase() {
|
|||||||
Control.StatelessBuilder("$idPrefix$it", pendingIntent)
|
Control.StatelessBuilder("$idPrefix$it", pendingIntent)
|
||||||
.setZone(zoneMap(it))
|
.setZone(zoneMap(it))
|
||||||
.build(),
|
.build(),
|
||||||
|
ComponentName("", ""),
|
||||||
it in favoritesIndices
|
it in favoritesIndices
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.systemui.controls.management
|
package com.android.systemui.controls.management
|
||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
|
import android.content.ComponentName
|
||||||
import android.service.controls.Control
|
import android.service.controls.Control
|
||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
@@ -70,6 +71,7 @@ open class FavoriteModelTest : SysuiTestCase() {
|
|||||||
Control.StatelessBuilder("$idPrefix$it", pendingIntent)
|
Control.StatelessBuilder("$idPrefix$it", pendingIntent)
|
||||||
.setZone((it % 3).toString())
|
.setZone((it % 3).toString())
|
||||||
.build(),
|
.build(),
|
||||||
|
ComponentName("", ""),
|
||||||
it in favoritesIndices
|
it in favoritesIndices
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user