Merge "Illumination hover state" into rvc-dev

This commit is contained in:
Lucas Dupin
2020-05-06 18:49:51 +00:00
committed by Android (Google) Code Review
7 changed files with 111 additions and 31 deletions

View File

@@ -124,7 +124,7 @@
android:layout_gravity="center" android:layout_gravity="center"
> >
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:gravity="center" android:gravity="center"
@@ -132,7 +132,7 @@
android:id="@+id/action0" android:id="@+id/action0"
/> />
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:gravity="center" android:gravity="center"
@@ -140,7 +140,7 @@
android:id="@+id/action1" android:id="@+id/action1"
/> />
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:gravity="center" android:gravity="center"

View File

@@ -63,7 +63,7 @@
android:gravity="center" android:gravity="center"
> >
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:gravity="center" android:gravity="center"
@@ -71,7 +71,7 @@
android:id="@+id/action0" android:id="@+id/action0"
/> />
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:gravity="center" android:gravity="center"
@@ -79,7 +79,7 @@
android:id="@+id/action1" android:id="@+id/action1"
/> />
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:gravity="center" android:gravity="center"

View File

@@ -197,7 +197,7 @@
android:gravity="center" android:gravity="center"
> >
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
@@ -207,7 +207,7 @@
android:id="@+id/action0" android:id="@+id/action0"
/> />
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
@@ -217,7 +217,7 @@
android:id="@+id/action1" android:id="@+id/action1"
/> />
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="52dp" android:layout_width="52dp"
android:layout_height="52dp" android:layout_height="52dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
@@ -227,7 +227,7 @@
android:id="@+id/action2" android:id="@+id/action2"
/> />
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
@@ -237,7 +237,7 @@
android:id="@+id/action3" android:id="@+id/action3"
/> />
<ImageButton <ImageButton
style="@android:style/Widget.Material.Button.Borderless.Small" style="@style/MediaPlayer.Button"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"

View File

@@ -620,6 +620,10 @@
<item name="rotateButtonScaleX">-1</item> <item name="rotateButtonScaleX">-1</item>
</style> </style>
<style name="MediaPlayer.Button" parent="@android:style/Widget.Material.Button.Borderless.Small">
<item name="android:background">@null</item>
</style>
<!-- Used to style charging animation AVD animation --> <!-- Used to style charging animation AVD animation -->
<style name="ChargingAnim" /> <style name="ChargingAnim" />

View File

@@ -12,11 +12,14 @@ import android.graphics.ColorFilter
import android.graphics.Paint import android.graphics.Paint
import android.graphics.PixelFormat import android.graphics.PixelFormat
import android.graphics.RadialGradient import android.graphics.RadialGradient
import android.graphics.Rect
import android.graphics.Shader import android.graphics.Shader
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.util.AttributeSet import android.util.AttributeSet
import android.util.MathUtils import android.util.MathUtils
import android.util.MathUtils.lerp import android.util.MathUtils.lerp
import android.view.MotionEvent
import android.view.View
import androidx.annotation.Keep import androidx.annotation.Keep
import com.android.internal.graphics.ColorUtils import com.android.internal.graphics.ColorUtils
import com.android.internal.graphics.ColorUtils.blendARGB import com.android.internal.graphics.ColorUtils.blendARGB
@@ -26,6 +29,8 @@ import org.xmlpull.v1.XmlPullParser
private const val BACKGROUND_ANIM_DURATION = 370L private const val BACKGROUND_ANIM_DURATION = 370L
private const val RIPPLE_ANIM_DURATION = 800L 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 val GRADIENT_STOPS = floatArrayOf(0.2f, 1f)
private data class RippleData( private data class RippleData(
@@ -50,7 +55,7 @@ class IlluminationDrawable : Drawable() {
private var tmpHsl = floatArrayOf(0f, 0f, 0f) private var tmpHsl = floatArrayOf(0f, 0f, 0f)
private var paint = Paint() private var paint = Paint()
var backgroundColor = Color.TRANSPARENT private var backgroundColor = Color.TRANSPARENT
set(value) { set(value) {
if (value == field) { if (value == field) {
return return
@@ -59,7 +64,52 @@ class IlluminationDrawable : Drawable() {
animateBackground() animateBackground()
} }
private var rippleAnimation: AnimatorSet? = null /**
* 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 private var backgroundAnimation: ValueAnimator? = null
/** /**
@@ -147,16 +197,10 @@ class IlluminationDrawable : Drawable() {
} }
/** /**
* Draws an animated ripple that expands from {@param x} and {@param y} fading away. * Draws an animated ripple that expands fading away.
*
* @param x X position of gradient centroid.
* @param y Y position of gradient centroid.
*/ */
fun illuminate(x: Int, y: Int) { private fun illuminate() {
rippleData.x = x.toFloat()
rippleData.y = y.toFloat()
rippleData.alpha = 1f rippleData.alpha = 1f
rippleData.progress = 0f
invalidateSelf() invalidateSelf()
rippleAnimation?.cancel() rippleAnimation?.cancel()
@@ -169,7 +213,7 @@ class IlluminationDrawable : Drawable() {
rippleData.alpha = it.animatedValue as Float rippleData.alpha = it.animatedValue as Float
invalidateSelf() invalidateSelf()
} }
}, ValueAnimator.ofFloat(0f, 1f).apply { }, ValueAnimator.ofFloat(rippleData.progress, 1f).apply {
duration = RIPPLE_ANIM_DURATION duration = RIPPLE_ANIM_DURATION
interpolator = Interpolators.LINEAR_OUT_SLOW_IN interpolator = Interpolators.LINEAR_OUT_SLOW_IN
addUpdateListener { addUpdateListener {
@@ -187,4 +231,34 @@ class IlluminationDrawable : Drawable() {
start() 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
}
}
} }

View File

@@ -183,21 +183,17 @@ public class QSMediaPlayer extends MediaControlPanel {
continue; continue;
} }
if (mMediaNotifView.getBackground() instanceof IlluminationDrawable) {
((IlluminationDrawable) mMediaNotifView.getBackground())
.setupTouch(thisBtn, mMediaNotifView);
}
Drawable thatIcon = thatBtn.getDrawable(); Drawable thatIcon = thatBtn.getDrawable();
thisBtn.setImageDrawable(thatIcon.mutate()); thisBtn.setImageDrawable(thatIcon.mutate());
thisBtn.setVisibility(View.VISIBLE); thisBtn.setVisibility(View.VISIBLE);
thisBtn.setOnClickListener(v -> { thisBtn.setOnClickListener(v -> {
Log.d(TAG, "clicking on other button"); Log.d(TAG, "clicking on other button");
thatBtn.performClick(); thatBtn.performClick();
if (mMediaNotifView.getBackground() instanceof IlluminationDrawable) {
Rect mediaRect = new Rect();
Rect buttonRect = new Rect();
mMediaNotifView.getGlobalVisibleRect(mediaRect);
thisBtn.getGlobalVisibleRect(buttonRect);
((IlluminationDrawable) mMediaNotifView.getBackground()).illuminate(
buttonRect.centerX() - mediaRect.left,
buttonRect.centerY() - mediaRect.top);
}
}); });
} }

View File

@@ -28,6 +28,7 @@ import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.media.IlluminationDrawable;
import com.android.systemui.media.MediaControlPanel; import com.android.systemui.media.MediaControlPanel;
import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter;
@@ -104,6 +105,11 @@ public class QuickQSMediaPlayer extends MediaControlPanel {
continue; continue;
} }
if (mMediaNotifView.getBackground() instanceof IlluminationDrawable) {
((IlluminationDrawable) mMediaNotifView.getBackground())
.setupTouch(thisBtn, mMediaNotifView);
}
Drawable thatIcon = thatBtn.getDrawable(); Drawable thatIcon = thatBtn.getDrawable();
thisBtn.setImageDrawable(thatIcon.mutate()); thisBtn.setImageDrawable(thatIcon.mutate());
thisBtn.setVisibility(View.VISIBLE); thisBtn.setVisibility(View.VISIBLE);