Merge "Use standard touch path for drawable state" into rvc-dev am: e7794e6991
Change-Id: Ife73a927cfc053cd7f75ff9c919e88e74f7b08f5
This commit is contained in:
@@ -16,7 +16,5 @@
|
||||
-->
|
||||
<com.android.systemui.media.IlluminationDrawable
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
systemui:rippleMinSize="30dp"
|
||||
systemui:rippleMaxSize="135dp"
|
||||
systemui:highlight="15"
|
||||
systemui:cornerRadius="?android:attr/dialogCornerRadius" />
|
||||
20
packages/SystemUI/res/drawable/qs_media_light_source.xml
Normal file
20
packages/SystemUI/res/drawable/qs_media_light_source.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<com.android.systemui.media.LightSourceDrawable
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
systemui:rippleMinSize="25dp"
|
||||
systemui:rippleMaxSize="135dp" />
|
||||
@@ -94,7 +94,8 @@
|
||||
android:id="@+id/media_seamless"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@*android:drawable/media_seamless_background"
|
||||
android:foreground="@*android:drawable/media_seamless_background"
|
||||
android:background="@drawable/qs_media_light_source"
|
||||
android:orientation="horizontal"
|
||||
android:forceHasOverlappingRendering="false"
|
||||
android:paddingLeft="12dp"
|
||||
|
||||
@@ -623,7 +623,7 @@
|
||||
</style>
|
||||
|
||||
<style name="MediaPlayer.Button" parent="@android:style/Widget.Material.Button.Borderless.Small">
|
||||
<item name="android:background">@null</item>
|
||||
<item name="android:background">@drawable/qs_media_light_source</item>
|
||||
<item name="android:tint">@android:color/white</item>
|
||||
<item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
/*
|
||||
* 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.media
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Resources
|
||||
@@ -10,16 +25,12 @@ import android.content.res.TypedArray
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.Outline
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.RadialGradient
|
||||
import android.graphics.Rect
|
||||
import android.graphics.Shader
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.util.MathUtils
|
||||
import android.util.MathUtils.lerp
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import androidx.annotation.Keep
|
||||
import com.android.internal.graphics.ColorUtils
|
||||
@@ -29,20 +40,6 @@ import com.android.systemui.R
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
|
||||
private const val BACKGROUND_ANIM_DURATION = 370L
|
||||
private const val RIPPLE_ANIM_DURATION = 800L
|
||||
private const val RIPPLE_DOWN_PROGRESS = 0.05f
|
||||
private const val RIPPLE_CANCEL_DURATION = 200L
|
||||
private val GRADIENT_STOPS = floatArrayOf(0.2f, 1f)
|
||||
|
||||
private data class RippleData(
|
||||
var x: Float,
|
||||
var y: Float,
|
||||
var alpha: Float,
|
||||
var progress: Float,
|
||||
var minSize: Float,
|
||||
var maxSize: Float,
|
||||
var highlight: Float
|
||||
)
|
||||
|
||||
/**
|
||||
* Drawable that can draw an animated gradient when tapped.
|
||||
@@ -53,9 +50,10 @@ class IlluminationDrawable : Drawable() {
|
||||
private var themeAttrs: IntArray? = null
|
||||
private var cornerRadius = 0f
|
||||
private var highlightColor = Color.TRANSPARENT
|
||||
private val rippleData = RippleData(0f, 0f, 0f, 0f, 0f, 0f, 0f)
|
||||
private var tmpHsl = floatArrayOf(0f, 0f, 0f)
|
||||
private var paint = Paint()
|
||||
private var highlight = 0f
|
||||
private val lightSources = arrayListOf<LightSourceDrawable>()
|
||||
|
||||
private var backgroundColor = Color.TRANSPARENT
|
||||
set(value) {
|
||||
@@ -66,70 +64,20 @@ class IlluminationDrawable : Drawable() {
|
||||
animateBackground()
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a small highlight under the finger before expanding (or cancelling) it.
|
||||
*/
|
||||
private var pressed: Boolean = false
|
||||
set(value) {
|
||||
if (value == field) {
|
||||
return
|
||||
}
|
||||
field = value
|
||||
|
||||
if (value) {
|
||||
rippleAnimation?.cancel()
|
||||
rippleData.alpha = 1f
|
||||
rippleData.progress = RIPPLE_DOWN_PROGRESS
|
||||
} else {
|
||||
rippleAnimation?.cancel()
|
||||
rippleAnimation = ValueAnimator.ofFloat(rippleData.alpha, 0f).apply {
|
||||
duration = RIPPLE_CANCEL_DURATION
|
||||
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
|
||||
addUpdateListener {
|
||||
rippleData.alpha = it.animatedValue as Float
|
||||
invalidateSelf()
|
||||
}
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
var cancelled = false
|
||||
override fun onAnimationCancel(animation: Animator?) {
|
||||
cancelled = true;
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
if (cancelled) {
|
||||
return
|
||||
}
|
||||
rippleData.progress = 0f
|
||||
rippleData.alpha = 0f
|
||||
rippleAnimation = null
|
||||
invalidateSelf()
|
||||
}
|
||||
})
|
||||
start()
|
||||
}
|
||||
}
|
||||
invalidateSelf()
|
||||
}
|
||||
|
||||
private var rippleAnimation: Animator? = null
|
||||
private var backgroundAnimation: ValueAnimator? = null
|
||||
|
||||
/**
|
||||
* Draw background and gradient.
|
||||
*/
|
||||
override fun draw(canvas: Canvas) {
|
||||
paint.shader = if (rippleData.progress > 0) {
|
||||
val radius = lerp(rippleData.minSize, rippleData.maxSize, rippleData.progress)
|
||||
val centerColor = blendARGB(paint.color, highlightColor, rippleData.alpha)
|
||||
RadialGradient(rippleData.x, rippleData.y, radius, intArrayOf(centerColor, paint.color),
|
||||
GRADIENT_STOPS, Shader.TileMode.CLAMP)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
canvas.drawRoundRect(0f, 0f, bounds.width().toFloat(), bounds.height().toFloat(),
|
||||
cornerRadius, cornerRadius, paint)
|
||||
}
|
||||
|
||||
override fun getOutline(outline: Outline) {
|
||||
outline.setRoundRect(bounds, cornerRadius)
|
||||
}
|
||||
|
||||
override fun getOpacity(): Int {
|
||||
return PixelFormat.TRANSPARENT
|
||||
}
|
||||
@@ -151,14 +99,8 @@ class IlluminationDrawable : Drawable() {
|
||||
cornerRadius = a.getDimension(R.styleable.IlluminationDrawable_cornerRadius,
|
||||
cornerRadius)
|
||||
}
|
||||
if (a.hasValue(R.styleable.IlluminationDrawable_rippleMinSize)) {
|
||||
rippleData.minSize = a.getDimension(R.styleable.IlluminationDrawable_rippleMinSize, 0f)
|
||||
}
|
||||
if (a.hasValue(R.styleable.IlluminationDrawable_rippleMaxSize)) {
|
||||
rippleData.maxSize = a.getDimension(R.styleable.IlluminationDrawable_rippleMaxSize, 0f)
|
||||
}
|
||||
if (a.hasValue(R.styleable.IlluminationDrawable_highlight)) {
|
||||
rippleData.highlight = a.getInteger(R.styleable.IlluminationDrawable_highlight, 0) /
|
||||
highlight = a.getInteger(R.styleable.IlluminationDrawable_highlight, 0) /
|
||||
100f
|
||||
}
|
||||
}
|
||||
@@ -192,10 +134,10 @@ class IlluminationDrawable : Drawable() {
|
||||
private fun animateBackground() {
|
||||
ColorUtils.colorToHSL(backgroundColor, tmpHsl)
|
||||
val L = tmpHsl[2]
|
||||
tmpHsl[2] = MathUtils.constrain(if (L < 1f - rippleData.highlight) {
|
||||
L + rippleData.highlight
|
||||
tmpHsl[2] = MathUtils.constrain(if (L < 1f - highlight) {
|
||||
L + highlight
|
||||
} else {
|
||||
L - rippleData.highlight
|
||||
L - highlight
|
||||
}, 0f, 1f)
|
||||
|
||||
val initialBackground = paint.color
|
||||
@@ -210,6 +152,7 @@ class IlluminationDrawable : Drawable() {
|
||||
val progress = it.animatedValue as Float
|
||||
paint.color = blendARGB(initialBackground, backgroundColor, progress)
|
||||
highlightColor = blendARGB(initialHighlight, finalHighlight, progress)
|
||||
lightSources.forEach { it.highlightColor = highlightColor }
|
||||
invalidateSelf()
|
||||
}
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
@@ -226,69 +169,11 @@ class IlluminationDrawable : Drawable() {
|
||||
backgroundColor = tint!!.defaultColor
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an animated ripple that expands fading away.
|
||||
*/
|
||||
private fun illuminate() {
|
||||
rippleData.alpha = 1f
|
||||
invalidateSelf()
|
||||
|
||||
rippleAnimation?.cancel()
|
||||
rippleAnimation = AnimatorSet().apply {
|
||||
playTogether(ValueAnimator.ofFloat(1f, 0f).apply {
|
||||
startDelay = 133
|
||||
duration = RIPPLE_ANIM_DURATION - startDelay
|
||||
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
|
||||
addUpdateListener {
|
||||
rippleData.alpha = it.animatedValue as Float
|
||||
invalidateSelf()
|
||||
}
|
||||
}, ValueAnimator.ofFloat(rippleData.progress, 1f).apply {
|
||||
duration = RIPPLE_ANIM_DURATION
|
||||
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
|
||||
addUpdateListener {
|
||||
rippleData.progress = it.animatedValue as Float
|
||||
invalidateSelf()
|
||||
}
|
||||
})
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
rippleData.progress = 0f
|
||||
rippleAnimation = null
|
||||
invalidateSelf()
|
||||
}
|
||||
})
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup touch events on a view such as tapping it would trigger effects on this drawable.
|
||||
* @param target View receiving touched.
|
||||
* @param container View that holds this drawable.
|
||||
*/
|
||||
fun setupTouch(target: View, container: View) {
|
||||
val containerRect = Rect()
|
||||
target.setOnTouchListener { view: View, event: MotionEvent ->
|
||||
container.getGlobalVisibleRect(containerRect)
|
||||
rippleData.x = event.rawX - containerRect.left
|
||||
rippleData.y = event.rawY - containerRect.top
|
||||
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
pressed = true
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
invalidateSelf()
|
||||
}
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
pressed = false
|
||||
if (event.action == MotionEvent.ACTION_UP) {
|
||||
illuminate()
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
fun registerLightSource(lightSource: View) {
|
||||
if (lightSource.background is LightSourceDrawable) {
|
||||
lightSources.add(lightSource.background as LightSourceDrawable)
|
||||
} else if (lightSource.foreground is LightSourceDrawable) {
|
||||
lightSources.add(lightSource.foreground as LightSourceDrawable)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* 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.media
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.res.Resources
|
||||
import android.content.res.TypedArray
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.Outline
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.RadialGradient
|
||||
import android.graphics.Rect
|
||||
import android.graphics.Shader
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.util.MathUtils.lerp
|
||||
import androidx.annotation.Keep
|
||||
import com.android.internal.graphics.ColorUtils
|
||||
import com.android.systemui.Interpolators
|
||||
import com.android.systemui.R
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
|
||||
private const val RIPPLE_ANIM_DURATION = 800L
|
||||
private const val RIPPLE_DOWN_PROGRESS = 0.05f
|
||||
private const val RIPPLE_CANCEL_DURATION = 200L
|
||||
private val GRADIENT_STOPS = floatArrayOf(0.2f, 1f)
|
||||
|
||||
private data class RippleData(
|
||||
var x: Float,
|
||||
var y: Float,
|
||||
var alpha: Float,
|
||||
var progress: Float,
|
||||
var minSize: Float,
|
||||
var maxSize: Float,
|
||||
var highlight: Float
|
||||
)
|
||||
|
||||
/**
|
||||
* Drawable that can draw an animated gradient when tapped.
|
||||
*/
|
||||
@Keep
|
||||
class LightSourceDrawable : Drawable() {
|
||||
|
||||
private var pressed = false
|
||||
private var themeAttrs: IntArray? = null
|
||||
private val rippleData = RippleData(0f, 0f, 0f, 0f, 0f, 0f, 0f)
|
||||
private var paint = Paint()
|
||||
|
||||
var highlightColor = Color.WHITE
|
||||
set(value) {
|
||||
if (field == value) {
|
||||
return
|
||||
}
|
||||
field = value
|
||||
invalidateSelf()
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a small highlight under the finger before expanding (or cancelling) it.
|
||||
*/
|
||||
private var active: Boolean = false
|
||||
set(value) {
|
||||
if (value == field) {
|
||||
return
|
||||
}
|
||||
field = value
|
||||
|
||||
if (value) {
|
||||
rippleAnimation?.cancel()
|
||||
rippleData.alpha = 1f
|
||||
rippleData.progress = RIPPLE_DOWN_PROGRESS
|
||||
} else {
|
||||
rippleAnimation?.cancel()
|
||||
rippleAnimation = ValueAnimator.ofFloat(rippleData.alpha, 0f).apply {
|
||||
duration = RIPPLE_CANCEL_DURATION
|
||||
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
|
||||
addUpdateListener {
|
||||
rippleData.alpha = it.animatedValue as Float
|
||||
invalidateSelf()
|
||||
}
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
var cancelled = false
|
||||
override fun onAnimationCancel(animation: Animator?) {
|
||||
cancelled = true
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
if (cancelled) {
|
||||
return
|
||||
}
|
||||
rippleData.progress = 0f
|
||||
rippleData.alpha = 0f
|
||||
rippleAnimation = null
|
||||
invalidateSelf()
|
||||
}
|
||||
})
|
||||
start()
|
||||
}
|
||||
}
|
||||
invalidateSelf()
|
||||
}
|
||||
|
||||
private var rippleAnimation: Animator? = null
|
||||
|
||||
/**
|
||||
* Draw background and gradient.
|
||||
*/
|
||||
override fun draw(canvas: Canvas) {
|
||||
val radius = lerp(rippleData.minSize, rippleData.maxSize, rippleData.progress)
|
||||
val centerColor =
|
||||
ColorUtils.setAlphaComponent(highlightColor, (rippleData.alpha * 255).toInt())
|
||||
paint.shader = RadialGradient(rippleData.x, rippleData.y, radius,
|
||||
intArrayOf(centerColor, Color.TRANSPARENT), GRADIENT_STOPS, Shader.TileMode.CLAMP)
|
||||
canvas.drawCircle(rippleData.x, rippleData.y, radius, paint)
|
||||
}
|
||||
|
||||
override fun getOutline(outline: Outline) {
|
||||
// No bounds, parent will clip it
|
||||
}
|
||||
|
||||
override fun getOpacity(): Int {
|
||||
return PixelFormat.TRANSPARENT
|
||||
}
|
||||
|
||||
override fun inflate(
|
||||
r: Resources,
|
||||
parser: XmlPullParser,
|
||||
attrs: AttributeSet,
|
||||
theme: Resources.Theme?
|
||||
) {
|
||||
val a = obtainAttributes(r, theme, attrs, R.styleable.IlluminationDrawable)
|
||||
themeAttrs = a.extractThemeAttrs()
|
||||
updateStateFromTypedArray(a)
|
||||
a.recycle()
|
||||
}
|
||||
|
||||
private fun updateStateFromTypedArray(a: TypedArray) {
|
||||
if (a.hasValue(R.styleable.IlluminationDrawable_rippleMinSize)) {
|
||||
rippleData.minSize = a.getDimension(R.styleable.IlluminationDrawable_rippleMinSize, 0f)
|
||||
}
|
||||
if (a.hasValue(R.styleable.IlluminationDrawable_rippleMaxSize)) {
|
||||
rippleData.maxSize = a.getDimension(R.styleable.IlluminationDrawable_rippleMaxSize, 0f)
|
||||
}
|
||||
if (a.hasValue(R.styleable.IlluminationDrawable_highlight)) {
|
||||
rippleData.highlight = a.getInteger(R.styleable.IlluminationDrawable_highlight, 0) /
|
||||
100f
|
||||
}
|
||||
}
|
||||
|
||||
override fun canApplyTheme(): Boolean {
|
||||
return themeAttrs != null && themeAttrs!!.size > 0 || super.canApplyTheme()
|
||||
}
|
||||
|
||||
override fun applyTheme(t: Resources.Theme) {
|
||||
super.applyTheme(t)
|
||||
themeAttrs?.let {
|
||||
val a = t.resolveAttributes(it, R.styleable.IlluminationDrawable)
|
||||
updateStateFromTypedArray(a)
|
||||
a.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setColorFilter(p0: ColorFilter?) {
|
||||
throw UnsupportedOperationException("Color filters are not supported")
|
||||
}
|
||||
|
||||
override fun setAlpha(value: Int) {
|
||||
throw UnsupportedOperationException("Alpha is not supported")
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an animated ripple that expands fading away.
|
||||
*/
|
||||
private fun illuminate() {
|
||||
rippleData.alpha = 1f
|
||||
invalidateSelf()
|
||||
|
||||
rippleAnimation?.cancel()
|
||||
rippleAnimation = AnimatorSet().apply {
|
||||
playTogether(ValueAnimator.ofFloat(1f, 0f).apply {
|
||||
startDelay = 133
|
||||
duration = RIPPLE_ANIM_DURATION - startDelay
|
||||
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
|
||||
addUpdateListener {
|
||||
rippleData.alpha = it.animatedValue as Float
|
||||
invalidateSelf()
|
||||
}
|
||||
}, ValueAnimator.ofFloat(rippleData.progress, 1f).apply {
|
||||
duration = RIPPLE_ANIM_DURATION
|
||||
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
|
||||
addUpdateListener {
|
||||
rippleData.progress = it.animatedValue as Float
|
||||
invalidateSelf()
|
||||
}
|
||||
})
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
rippleData.progress = 0f
|
||||
rippleAnimation = null
|
||||
invalidateSelf()
|
||||
}
|
||||
})
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setHotspot(x: Float, y: Float) {
|
||||
rippleData.x = x
|
||||
rippleData.y = y
|
||||
if (active) {
|
||||
invalidateSelf()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isStateful(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hasFocusStateSpecified(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isProjected(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getDirtyBounds(): Rect {
|
||||
val radius = lerp(rippleData.minSize, rippleData.maxSize, rippleData.progress)
|
||||
val bounds = Rect((rippleData.x - radius).toInt(), (rippleData.y - radius).toInt(),
|
||||
(rippleData.x + radius).toInt(), (rippleData.y + radius).toInt())
|
||||
bounds.union(super.getDirtyBounds())
|
||||
return bounds
|
||||
}
|
||||
|
||||
override fun onStateChange(stateSet: IntArray?): Boolean {
|
||||
val changed = super.onStateChange(stateSet)
|
||||
if (stateSet == null) {
|
||||
return changed
|
||||
}
|
||||
|
||||
val wasPressed = pressed
|
||||
var enabled = false
|
||||
pressed = false
|
||||
var focused = false
|
||||
var hovered = false
|
||||
|
||||
for (state in stateSet) {
|
||||
when (state) {
|
||||
com.android.internal.R.attr.state_enabled -> {
|
||||
enabled = true
|
||||
}
|
||||
com.android.internal.R.attr.state_focused -> {
|
||||
focused = true
|
||||
}
|
||||
com.android.internal.R.attr.state_pressed -> {
|
||||
pressed = true
|
||||
}
|
||||
com.android.internal.R.attr.state_hovered -> {
|
||||
hovered = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
active = enabled && (pressed || focused || hovered)
|
||||
if (wasPressed && !pressed) {
|
||||
illuminate()
|
||||
}
|
||||
|
||||
return changed
|
||||
}
|
||||
}
|
||||
@@ -304,7 +304,7 @@ public class MediaControlPanel {
|
||||
TextView deviceName = mViewHolder.getSeamlessText();
|
||||
|
||||
// Update the outline color
|
||||
RippleDrawable bkgDrawable = (RippleDrawable) mViewHolder.getSeamless().getBackground();
|
||||
RippleDrawable bkgDrawable = (RippleDrawable) mViewHolder.getSeamless().getForeground();
|
||||
GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
|
||||
rect.setStroke(2, deviceName.getCurrentTextColor());
|
||||
rect.setColor(Color.TRANSPARENT);
|
||||
|
||||
@@ -41,7 +41,7 @@ class PlayerViewHolder private constructor(itemView: View) {
|
||||
val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
|
||||
|
||||
// Output switcher
|
||||
val seamless = itemView.findViewById<ViewGroup>(R.id.media_seamless)
|
||||
val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless)
|
||||
val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image)
|
||||
val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text)
|
||||
|
||||
@@ -59,12 +59,12 @@ class PlayerViewHolder private constructor(itemView: View) {
|
||||
|
||||
init {
|
||||
(player.background as IlluminationDrawable).let {
|
||||
it.setupTouch(seamless, player)
|
||||
it.setupTouch(action0, player)
|
||||
it.setupTouch(action1, player)
|
||||
it.setupTouch(action2, player)
|
||||
it.setupTouch(action3, player)
|
||||
it.setupTouch(action4, player)
|
||||
it.registerLightSource(seamless)
|
||||
it.registerLightSource(action0)
|
||||
it.registerLightSource(action1)
|
||||
it.registerLightSource(action2)
|
||||
it.registerLightSource(action3)
|
||||
it.registerLightSource(action4)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
whenever(holder.artistText).thenReturn(artistText)
|
||||
seamless = FrameLayout(context)
|
||||
val seamlessBackground = mock(RippleDrawable::class.java)
|
||||
seamless.setBackground(seamlessBackground)
|
||||
seamless.foreground = seamlessBackground
|
||||
whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
|
||||
whenever(holder.seamless).thenReturn(seamless)
|
||||
seamlessIcon = ImageView(context)
|
||||
|
||||
Reference in New Issue
Block a user