Merge "Controls UI - Part 1 - Thumbnail support"
This commit is contained in:
committed by
Android (Google) Code Review
commit
71293a7ccb
23
packages/SystemUI/res/color/camera_foreground.xml
Normal file
23
packages/SystemUI/res/color/camera_foreground.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright 2010, 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.
|
||||
*/
|
||||
-->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false"
|
||||
android:color="@color/control_default_foreground" />
|
||||
<item android:color="@color/GM2_grey_100" />
|
||||
</selector>
|
||||
@@ -257,6 +257,8 @@
|
||||
<color name="control_enabled_heat_foreground">#FF8B66</color>
|
||||
<color name="control_enabled_default_foreground">@color/GM2_blue_300</color>
|
||||
<color name="control_enabled_cool_foreground">@color/GM2_blue_300</color>
|
||||
<color name="control_thumbnail_tint">#33000000</color>
|
||||
<color name="control_thumbnail_shadow_color">@*android:color/black</color>
|
||||
|
||||
<!-- Docked misalignment message -->
|
||||
<color name="misalignment_text_color">#F28B82</color>
|
||||
|
||||
@@ -1269,6 +1269,10 @@
|
||||
<dimen name="controls_app_divider_height">2dp</dimen>
|
||||
<dimen name="controls_app_divider_side_margin">32dp</dimen>
|
||||
|
||||
<item name="controls_thumbnail_shadow_x" type="dimen" format="float">2.0</item>
|
||||
<item name="controls_thumbnail_shadow_y" type="dimen" format="float">2.0</item>
|
||||
<item name="controls_thumbnail_shadow_radius" type="dimen" format="float">2.0</item>
|
||||
|
||||
<dimen name="controls_card_margin">@dimen/control_base_item_margin</dimen>
|
||||
<item name="control_card_elevation" type="dimen" format="float">15</item>
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import android.service.controls.templates.ControlTemplate
|
||||
import android.service.controls.templates.RangeTemplate
|
||||
import android.service.controls.templates.StatelessTemplate
|
||||
import android.service.controls.templates.TemperatureControlTemplate
|
||||
import android.service.controls.templates.ThumbnailTemplate
|
||||
import android.service.controls.templates.ToggleRangeTemplate
|
||||
import android.service.controls.templates.ToggleTemplate
|
||||
import android.util.MathUtils
|
||||
@@ -87,8 +88,11 @@ class ControlViewHolder(
|
||||
): KClass<out Behavior> {
|
||||
return when {
|
||||
status != Control.STATUS_OK -> StatusBehavior::class
|
||||
deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class
|
||||
template == ControlTemplate.NO_TEMPLATE -> TouchBehavior::class
|
||||
template is ThumbnailTemplate -> ThumbnailBehavior::class
|
||||
|
||||
// Required for legacy support, or where cameras do not use the new template
|
||||
deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class
|
||||
template is ToggleTemplate -> ToggleBehavior::class
|
||||
template is StatelessTemplate -> TouchBehavior::class
|
||||
template is ToggleRangeTemplate -> ToggleRangeBehavior::class
|
||||
@@ -105,7 +109,7 @@ class ControlViewHolder(
|
||||
private var statusAnimator: Animator? = null
|
||||
private val baseLayer: GradientDrawable
|
||||
val icon: ImageView = layout.requireViewById(R.id.icon)
|
||||
private val status: TextView = layout.requireViewById(R.id.status)
|
||||
val status: TextView = layout.requireViewById(R.id.status)
|
||||
private var nextStatusText: CharSequence = ""
|
||||
val title: TextView = layout.requireViewById(R.id.title)
|
||||
val subtitle: TextView = layout.requireViewById(R.id.subtitle)
|
||||
@@ -132,7 +136,6 @@ class ControlViewHolder(
|
||||
val ld = layout.getBackground() as LayerDrawable
|
||||
ld.mutate()
|
||||
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
|
||||
clipLayer.alpha = ALPHA_DISABLED
|
||||
baseLayer = ld.findDrawableByLayerId(R.id.background) as GradientDrawable
|
||||
// needed for marquee to start
|
||||
status.setSelected(true)
|
||||
@@ -315,7 +318,9 @@ class ControlViewHolder(
|
||||
)
|
||||
}
|
||||
|
||||
(clipLayer.getDrawable() as GradientDrawable).apply {
|
||||
clipLayer.getDrawable().apply {
|
||||
clipLayer.alpha = ALPHA_DISABLED
|
||||
|
||||
val newBaseColor = if (behavior is ToggleRangeBehavior) {
|
||||
ColorUtils.blendARGB(bg, newClipColor, toggleBackgroundIntensity)
|
||||
} else {
|
||||
@@ -323,15 +328,25 @@ class ControlViewHolder(
|
||||
}
|
||||
stateAnimator?.cancel()
|
||||
if (animated) {
|
||||
val oldColor = color?.defaultColor ?: newClipColor
|
||||
val oldColor = if (this is GradientDrawable) {
|
||||
this.color?.defaultColor ?: newClipColor
|
||||
} else {
|
||||
newClipColor
|
||||
}
|
||||
val oldBaseColor = baseLayer.color?.defaultColor ?: newBaseColor
|
||||
val oldAlpha = layout.alpha
|
||||
|
||||
// Animate both alpha and background colors. Only animate colors for
|
||||
// GradientDrawables and not static images as used for the ThumbnailTemplate.
|
||||
stateAnimator = ValueAnimator.ofInt(clipLayer.alpha, newAlpha).apply {
|
||||
addUpdateListener {
|
||||
alpha = it.animatedValue as Int
|
||||
setColor(ColorUtils.blendARGB(oldColor, newClipColor, it.animatedFraction))
|
||||
baseLayer.setColor(ColorUtils.blendARGB(oldBaseColor,
|
||||
newBaseColor, it.animatedFraction))
|
||||
if (this is GradientDrawable) {
|
||||
this.setColor(ColorUtils.blendARGB(oldColor, newClipColor,
|
||||
it.animatedFraction))
|
||||
}
|
||||
baseLayer.setColor(ColorUtils.blendARGB(oldBaseColor, newBaseColor,
|
||||
it.animatedFraction))
|
||||
layout.alpha = MathUtils.lerp(oldAlpha, 1f, it.animatedFraction)
|
||||
}
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
@@ -345,7 +360,9 @@ class ControlViewHolder(
|
||||
}
|
||||
} else {
|
||||
alpha = newAlpha
|
||||
setColor(newClipColor)
|
||||
if (this is GradientDrawable) {
|
||||
this.setColor(newClipColor)
|
||||
}
|
||||
baseLayer.setColor(newBaseColor)
|
||||
layout.alpha = 1f
|
||||
}
|
||||
|
||||
@@ -92,7 +92,9 @@ private val deviceColorMap = mapOf<Int, Pair<Int, Int>>(
|
||||
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_COOL) to
|
||||
Pair(R.color.thermo_cool_foreground, R.color.control_enabled_thermo_cool_background),
|
||||
DeviceTypes.TYPE_LIGHT
|
||||
to Pair(R.color.light_foreground, R.color.control_enabled_light_background)
|
||||
to Pair(R.color.light_foreground, R.color.control_enabled_light_background),
|
||||
DeviceTypes.TYPE_CAMERA
|
||||
to Pair(R.color.camera_foreground, R.color.control_enabled_default_background)
|
||||
).withDefault {
|
||||
Pair(R.color.control_foreground, R.color.control_enabled_default_background)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.BlendMode
|
||||
import android.graphics.BlendModeColorFilter
|
||||
import android.graphics.drawable.ClipDrawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.view.View
|
||||
import android.service.controls.Control
|
||||
import android.service.controls.templates.ThumbnailTemplate
|
||||
import android.util.TypedValue
|
||||
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
|
||||
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL
|
||||
|
||||
/**
|
||||
* Supports display of static images on the background of the tile. When marked active, the title
|
||||
* and subtitle will not be visible. To be used with {@link Thumbnailtemplate} only.
|
||||
*/
|
||||
class ThumbnailBehavior : Behavior {
|
||||
lateinit var template: ThumbnailTemplate
|
||||
lateinit var control: Control
|
||||
lateinit var cvh: ControlViewHolder
|
||||
private var shadowOffsetX: Float = 0f
|
||||
private var shadowOffsetY: Float = 0f
|
||||
private var shadowRadius: Float = 0f
|
||||
private var shadowColor: Int = 0
|
||||
|
||||
private val enabled: Boolean
|
||||
get() = template.isActive()
|
||||
|
||||
override fun initialize(cvh: ControlViewHolder) {
|
||||
this.cvh = cvh
|
||||
|
||||
val outValue = TypedValue()
|
||||
cvh.context.resources.getValue(R.dimen.controls_thumbnail_shadow_x, outValue, true)
|
||||
shadowOffsetX = outValue.getFloat()
|
||||
|
||||
cvh.context.resources.getValue(R.dimen.controls_thumbnail_shadow_y, outValue, true)
|
||||
shadowOffsetY = outValue.getFloat()
|
||||
|
||||
cvh.context.resources.getValue(R.dimen.controls_thumbnail_shadow_radius, outValue, true)
|
||||
shadowRadius = outValue.getFloat()
|
||||
|
||||
shadowColor = cvh.context.resources.getColor(R.color.control_thumbnail_shadow_color)
|
||||
cvh.layout.setOnClickListener(View.OnClickListener() {
|
||||
cvh.controlActionCoordinator.touch(cvh, template.getTemplateId(), control)
|
||||
})
|
||||
}
|
||||
|
||||
override fun bind(cws: ControlWithState, colorOffset: Int) {
|
||||
this.control = cws.control!!
|
||||
cvh.setStatusText(control.getStatusText())
|
||||
template = control.getControlTemplate() as ThumbnailTemplate
|
||||
|
||||
val ld = cvh.layout.getBackground() as LayerDrawable
|
||||
val clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
|
||||
|
||||
clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
|
||||
|
||||
if (template.isActive()) {
|
||||
cvh.title.visibility = View.INVISIBLE
|
||||
cvh.subtitle.visibility = View.INVISIBLE
|
||||
cvh.status.setShadowLayer(shadowOffsetX, shadowOffsetY, shadowRadius, shadowColor)
|
||||
|
||||
cvh.bgExecutor.execute {
|
||||
val drawable = template.getThumbnail().loadDrawable(cvh.context)
|
||||
cvh.uiExecutor.execute {
|
||||
val radius = cvh.context.getResources()
|
||||
.getDimensionPixelSize(R.dimen.control_corner_radius).toFloat()
|
||||
clipLayer.setDrawable(CornerDrawable(drawable, radius))
|
||||
clipLayer.setColorFilter(BlendModeColorFilter(cvh.context.resources
|
||||
.getColor(R.color.control_thumbnail_tint), BlendMode.LUMINOSITY))
|
||||
cvh.applyRenderInfo(enabled, colorOffset)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cvh.title.visibility = View.VISIBLE
|
||||
cvh.subtitle.visibility = View.VISIBLE
|
||||
cvh.status.setShadowLayer(0f, 0f, 0f, shadowColor)
|
||||
}
|
||||
|
||||
cvh.applyRenderInfo(enabled, colorOffset)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user