Merge "[Media TTT] Polish the tablet ripple" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
6115f2ecc9
@@ -27,6 +27,14 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<com.android.systemui.media.taptotransfer.receiver.ReceiverChipRippleView
|
||||||
|
android:id="@+id/icon_glow_ripple"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Add a bottom margin to avoid the glow of the icon ripple from being cropped by screen
|
||||||
|
bounds while animating with the icon -->
|
||||||
<com.android.internal.widget.CachingIconView
|
<com.android.internal.widget.CachingIconView
|
||||||
android:id="@+id/app_icon"
|
android:id="@+id/app_icon"
|
||||||
android:background="@drawable/media_ttt_chip_background_receiver"
|
android:background="@drawable/media_ttt_chip_background_receiver"
|
||||||
@@ -34,6 +42,7 @@
|
|||||||
android:layout_height="@dimen/media_ttt_icon_size_receiver"
|
android:layout_height="@dimen/media_ttt_icon_size_receiver"
|
||||||
android:layout_gravity="center|bottom"
|
android:layout_gravity="center|bottom"
|
||||||
android:alpha="0.0"
|
android:alpha="0.0"
|
||||||
|
android:layout_marginBottom="@dimen/media_ttt_receiver_icon_bottom_margin"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|||||||
@@ -1087,6 +1087,7 @@
|
|||||||
(112 - 40) / 2 = 36dp -->
|
(112 - 40) / 2 = 36dp -->
|
||||||
<dimen name="media_ttt_generic_icon_padding">36dp</dimen>
|
<dimen name="media_ttt_generic_icon_padding">36dp</dimen>
|
||||||
<dimen name="media_ttt_receiver_vert_translation">40dp</dimen>
|
<dimen name="media_ttt_receiver_vert_translation">40dp</dimen>
|
||||||
|
<dimen name="media_ttt_receiver_icon_bottom_margin">10dp</dimen>
|
||||||
|
|
||||||
<!-- Window magnification -->
|
<!-- Window magnification -->
|
||||||
<dimen name="magnification_border_drag_size">35dp</dimen>
|
<dimen name="magnification_border_drag_size">35dp</dimen>
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import android.view.ViewGroup
|
|||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.view.accessibility.AccessibilityManager
|
import android.view.accessibility.AccessibilityManager
|
||||||
import com.android.internal.widget.CachingIconView
|
import com.android.internal.widget.CachingIconView
|
||||||
import com.android.settingslib.Utils
|
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.common.shared.model.ContentDescription
|
import com.android.systemui.common.shared.model.ContentDescription
|
||||||
import com.android.systemui.common.ui.binder.TintedIconViewBinder
|
import com.android.systemui.common.ui.binder.TintedIconViewBinder
|
||||||
@@ -78,6 +77,7 @@ open class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
private val viewUtil: ViewUtil,
|
private val viewUtil: ViewUtil,
|
||||||
wakeLockBuilder: WakeLock.Builder,
|
wakeLockBuilder: WakeLock.Builder,
|
||||||
systemClock: SystemClock,
|
systemClock: SystemClock,
|
||||||
|
private val rippleController: MediaTttReceiverRippleController,
|
||||||
) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger<ChipReceiverInfo>>(
|
) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger<ChipReceiverInfo>>(
|
||||||
context,
|
context,
|
||||||
logger,
|
logger,
|
||||||
@@ -114,9 +114,6 @@ open class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var maxRippleWidth: Float = 0f
|
|
||||||
private var maxRippleHeight: Float = 0f
|
|
||||||
|
|
||||||
private fun updateMediaTapToTransferReceiverDisplay(
|
private fun updateMediaTapToTransferReceiverDisplay(
|
||||||
@StatusBarManager.MediaTransferReceiverState displayState: Int,
|
@StatusBarManager.MediaTransferReceiverState displayState: Int,
|
||||||
routeInfo: MediaRoute2Info,
|
routeInfo: MediaRoute2Info,
|
||||||
@@ -206,36 +203,40 @@ open class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
|
|
||||||
override fun animateViewIn(view: ViewGroup) {
|
override fun animateViewIn(view: ViewGroup) {
|
||||||
val appIconView = view.getAppIconView()
|
val appIconView = view.getAppIconView()
|
||||||
appIconView.animate()
|
val iconRippleView: ReceiverChipRippleView = view.requireViewById(R.id.icon_glow_ripple)
|
||||||
.translationYBy(-1 * getTranslationAmount().toFloat())
|
val rippleView: ReceiverChipRippleView = view.requireViewById(R.id.ripple)
|
||||||
.setDuration(ICON_TRANSLATION_ANIM_DURATION)
|
animateViewTranslationAndFade(appIconView, -1 * getTranslationAmount(), 1f)
|
||||||
.start()
|
animateViewTranslationAndFade(iconRippleView, -1 * getTranslationAmount(), 1f)
|
||||||
appIconView.animate()
|
|
||||||
.alpha(1f)
|
|
||||||
.setDuration(ICON_ALPHA_ANIM_DURATION)
|
|
||||||
.start()
|
|
||||||
// Using withEndAction{} doesn't apply a11y focus when screen is unlocked.
|
// Using withEndAction{} doesn't apply a11y focus when screen is unlocked.
|
||||||
appIconView.postOnAnimation { view.requestAccessibilityFocus() }
|
appIconView.postOnAnimation { view.requestAccessibilityFocus() }
|
||||||
expandRipple(view.requireViewById(R.id.ripple))
|
rippleController.expandToInProgressState(rippleView, iconRippleView)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
|
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
|
||||||
val appIconView = view.getAppIconView()
|
val appIconView = view.getAppIconView()
|
||||||
appIconView.animate()
|
val iconRippleView: ReceiverChipRippleView = view.requireViewById(R.id.icon_glow_ripple)
|
||||||
.translationYBy(getTranslationAmount().toFloat())
|
|
||||||
.setDuration(ICON_TRANSLATION_ANIM_DURATION)
|
|
||||||
.start()
|
|
||||||
appIconView.animate()
|
|
||||||
.alpha(0f)
|
|
||||||
.setDuration(ICON_ALPHA_ANIM_DURATION)
|
|
||||||
.start()
|
|
||||||
|
|
||||||
val rippleView: ReceiverChipRippleView = view.requireViewById(R.id.ripple)
|
val rippleView: ReceiverChipRippleView = view.requireViewById(R.id.ripple)
|
||||||
if (removalReason == ChipStateReceiver.TRANSFER_TO_RECEIVER_SUCCEEDED.name &&
|
if (removalReason == ChipStateReceiver.TRANSFER_TO_RECEIVER_SUCCEEDED.name &&
|
||||||
mediaTttFlags.isMediaTttReceiverSuccessRippleEnabled()) {
|
mediaTttFlags.isMediaTttReceiverSuccessRippleEnabled()) {
|
||||||
expandRippleToFull(rippleView, onAnimationEnd)
|
rippleController.expandToSuccessState(rippleView, onAnimationEnd)
|
||||||
|
animateViewTranslationAndFade(
|
||||||
|
iconRippleView,
|
||||||
|
-1 * getTranslationAmount(),
|
||||||
|
0f,
|
||||||
|
translationDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
|
||||||
|
alphaDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
|
||||||
|
)
|
||||||
|
animateViewTranslationAndFade(
|
||||||
|
appIconView,
|
||||||
|
-1 * getTranslationAmount(),
|
||||||
|
0f,
|
||||||
|
translationDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
|
||||||
|
alphaDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
rippleView.collapseRipple(onAnimationEnd)
|
rippleController.collapseRipple(rippleView, onAnimationEnd)
|
||||||
|
animateViewTranslationAndFade(iconRippleView, getTranslationAmount(), 0f)
|
||||||
|
animateViewTranslationAndFade(appIconView, getTranslationAmount(), 0f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,74 +246,41 @@ open class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
viewUtil.setRectToViewWindowLocation(view.getAppIconView(), outRect)
|
viewUtil.setRectToViewWindowLocation(view.getAppIconView(), outRect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Animation of view translation and fading. */
|
||||||
|
private fun animateViewTranslationAndFade(
|
||||||
|
view: View,
|
||||||
|
translationYBy: Float,
|
||||||
|
alphaEndValue: Float,
|
||||||
|
translationDuration: Long = ICON_TRANSLATION_ANIM_DURATION,
|
||||||
|
alphaDuration: Long = ICON_ALPHA_ANIM_DURATION,
|
||||||
|
) {
|
||||||
|
view.animate()
|
||||||
|
.translationYBy(translationYBy)
|
||||||
|
.setDuration(translationDuration)
|
||||||
|
.start()
|
||||||
|
view.animate()
|
||||||
|
.alpha(alphaEndValue)
|
||||||
|
.setDuration(alphaDuration)
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the amount that the chip will be translated by in its intro animation. */
|
/** Returns the amount that the chip will be translated by in its intro animation. */
|
||||||
private fun getTranslationAmount(): Int {
|
private fun getTranslationAmount(): Float {
|
||||||
return context.resources.getDimensionPixelSize(R.dimen.media_ttt_receiver_vert_translation)
|
return rippleController.getRippleSize() * 0.5f -
|
||||||
}
|
rippleController.getReceiverIconSize()
|
||||||
|
|
||||||
private fun expandRipple(rippleView: ReceiverChipRippleView) {
|
|
||||||
if (rippleView.rippleInProgress()) {
|
|
||||||
// Skip if ripple is still playing
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// In case the device orientation changes, we need to reset the layout.
|
|
||||||
rippleView.addOnLayoutChangeListener (
|
|
||||||
View.OnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
|
||||||
if (v == null) return@OnLayoutChangeListener
|
|
||||||
|
|
||||||
val layoutChangedRippleView = v as ReceiverChipRippleView
|
|
||||||
layoutRipple(layoutChangedRippleView)
|
|
||||||
layoutChangedRippleView.invalidate()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
rippleView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
|
||||||
override fun onViewDetachedFromWindow(view: View?) {}
|
|
||||||
|
|
||||||
override fun onViewAttachedToWindow(view: View?) {
|
|
||||||
if (view == null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val attachedRippleView = view as ReceiverChipRippleView
|
|
||||||
layoutRipple(attachedRippleView)
|
|
||||||
attachedRippleView.expandRipple()
|
|
||||||
attachedRippleView.removeOnAttachStateChangeListener(this)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun layoutRipple(rippleView: ReceiverChipRippleView, isFullScreen: Boolean = false) {
|
|
||||||
val windowBounds = windowManager.currentWindowMetrics.bounds
|
|
||||||
val height = windowBounds.height().toFloat()
|
|
||||||
val width = windowBounds.width().toFloat()
|
|
||||||
|
|
||||||
if (isFullScreen) {
|
|
||||||
maxRippleHeight = height * 2f
|
|
||||||
maxRippleWidth = width * 2f
|
|
||||||
} else {
|
|
||||||
maxRippleHeight = height / 2f
|
|
||||||
maxRippleWidth = width / 2f
|
|
||||||
}
|
|
||||||
rippleView.setMaxSize(maxRippleWidth, maxRippleHeight)
|
|
||||||
// Center the ripple on the bottom of the screen in the middle.
|
|
||||||
rippleView.setCenter(width * 0.5f, height)
|
|
||||||
val color = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent)
|
|
||||||
rippleView.setColor(color, 70)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun View.getAppIconView(): CachingIconView {
|
private fun View.getAppIconView(): CachingIconView {
|
||||||
return this.requireViewById(R.id.app_icon)
|
return this.requireViewById(R.id.app_icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun expandRippleToFull(rippleView: ReceiverChipRippleView, onAnimationEnd: Runnable?) {
|
companion object {
|
||||||
layoutRipple(rippleView, true)
|
private const val ICON_TRANSLATION_ANIM_DURATION = 500L
|
||||||
rippleView.expandToFull(maxRippleHeight, onAnimationEnd)
|
private const val ICON_TRANSLATION_SUCCEEDED_DURATION = 167L
|
||||||
|
private val ICON_ALPHA_ANIM_DURATION = 5.frames
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ICON_TRANSLATION_ANIM_DURATION = 30.frames
|
|
||||||
val ICON_ALPHA_ANIM_DURATION = 5.frames
|
|
||||||
|
|
||||||
data class ChipReceiverInfo(
|
data class ChipReceiverInfo(
|
||||||
val routeInfo: MediaRoute2Info,
|
val routeInfo: MediaRoute2Info,
|
||||||
val appIconDrawableOverride: Drawable?,
|
val appIconDrawableOverride: Drawable?,
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.taptotransfer.receiver
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.view.View
|
||||||
|
import android.view.WindowManager
|
||||||
|
import com.android.settingslib.Utils
|
||||||
|
import com.android.systemui.R
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A controller responsible for the animation of the ripples shown in media tap-to-transfer on the
|
||||||
|
* receiving device.
|
||||||
|
*/
|
||||||
|
class MediaTttReceiverRippleController
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val context: Context,
|
||||||
|
private val windowManager: WindowManager,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private var maxRippleWidth: Float = 0f
|
||||||
|
private var maxRippleHeight: Float = 0f
|
||||||
|
|
||||||
|
/** Expands the icon and main ripple to in-progress state */
|
||||||
|
fun expandToInProgressState(
|
||||||
|
mainRippleView: ReceiverChipRippleView,
|
||||||
|
iconRippleView: ReceiverChipRippleView,
|
||||||
|
) {
|
||||||
|
expandRipple(mainRippleView, isIconRipple = false)
|
||||||
|
expandRipple(iconRippleView, isIconRipple = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun expandRipple(rippleView: ReceiverChipRippleView, isIconRipple: Boolean) {
|
||||||
|
if (rippleView.rippleInProgress()) {
|
||||||
|
// Skip if ripple is still playing
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case the device orientation changes, we need to reset the layout.
|
||||||
|
rippleView.addOnLayoutChangeListener(
|
||||||
|
View.OnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
if (v == null) return@OnLayoutChangeListener
|
||||||
|
|
||||||
|
val layoutChangedRippleView = v as ReceiverChipRippleView
|
||||||
|
if (isIconRipple) {
|
||||||
|
layoutIconRipple(layoutChangedRippleView)
|
||||||
|
} else {
|
||||||
|
layoutRipple(layoutChangedRippleView)
|
||||||
|
}
|
||||||
|
layoutChangedRippleView.invalidate()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
rippleView.addOnAttachStateChangeListener(
|
||||||
|
object : View.OnAttachStateChangeListener {
|
||||||
|
override fun onViewDetachedFromWindow(view: View?) {}
|
||||||
|
|
||||||
|
override fun onViewAttachedToWindow(view: View?) {
|
||||||
|
if (view == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val attachedRippleView = view as ReceiverChipRippleView
|
||||||
|
if (isIconRipple) {
|
||||||
|
layoutIconRipple(attachedRippleView)
|
||||||
|
} else {
|
||||||
|
layoutRipple(attachedRippleView)
|
||||||
|
}
|
||||||
|
attachedRippleView.expandRipple()
|
||||||
|
attachedRippleView.removeOnAttachStateChangeListener(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Expands the ripple to cover the screen. */
|
||||||
|
fun expandToSuccessState(rippleView: ReceiverChipRippleView, onAnimationEnd: Runnable?) {
|
||||||
|
layoutRipple(rippleView, isFullScreen = true)
|
||||||
|
rippleView.expandToFull(maxRippleHeight, onAnimationEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Collapses the ripple. */
|
||||||
|
fun collapseRipple(rippleView: ReceiverChipRippleView, onAnimationEnd: Runnable? = null) {
|
||||||
|
rippleView.collapseRipple(onAnimationEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun layoutRipple(rippleView: ReceiverChipRippleView, isFullScreen: Boolean = false) {
|
||||||
|
val windowBounds = windowManager.currentWindowMetrics.bounds
|
||||||
|
val height = windowBounds.height().toFloat()
|
||||||
|
val width = windowBounds.width().toFloat()
|
||||||
|
|
||||||
|
if (isFullScreen) {
|
||||||
|
maxRippleHeight = height * 2f
|
||||||
|
maxRippleWidth = width * 2f
|
||||||
|
} else {
|
||||||
|
maxRippleHeight = getRippleSize()
|
||||||
|
maxRippleWidth = getRippleSize()
|
||||||
|
}
|
||||||
|
rippleView.setMaxSize(maxRippleWidth, maxRippleHeight)
|
||||||
|
// Center the ripple on the bottom of the screen in the middle.
|
||||||
|
rippleView.setCenter(width * 0.5f, height)
|
||||||
|
rippleView.setColor(getRippleColor(), RIPPLE_OPACITY)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun layoutIconRipple(iconRippleView: ReceiverChipRippleView) {
|
||||||
|
val windowBounds = windowManager.currentWindowMetrics.bounds
|
||||||
|
val height = windowBounds.height().toFloat()
|
||||||
|
val width = windowBounds.width().toFloat()
|
||||||
|
val radius = getReceiverIconSize().toFloat()
|
||||||
|
|
||||||
|
iconRippleView.setMaxSize(radius * 0.8f, radius * 0.8f)
|
||||||
|
iconRippleView.setCenter(
|
||||||
|
width * 0.5f,
|
||||||
|
height - getReceiverIconSize() * 0.5f - getReceiverIconBottomMargin()
|
||||||
|
)
|
||||||
|
iconRippleView.setColor(getRippleColor(), RIPPLE_OPACITY)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRippleColor(): Int {
|
||||||
|
var colorStateList =
|
||||||
|
ColorStateList.valueOf(
|
||||||
|
Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent)
|
||||||
|
)
|
||||||
|
return colorStateList.withLStar(TONE_PERCENT).defaultColor
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the size of the ripple. */
|
||||||
|
internal fun getRippleSize(): Float {
|
||||||
|
return getReceiverIconSize() * 4f
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the size of the icon of the receiver. */
|
||||||
|
internal fun getReceiverIconSize(): Int {
|
||||||
|
return context.resources.getDimensionPixelSize(R.dimen.media_ttt_icon_size_receiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the bottom margin of the icon of the receiver. */
|
||||||
|
internal fun getReceiverIconBottomMargin(): Int {
|
||||||
|
// Adding a margin to make sure ripple behind the icon is not cut by the screen bounds.
|
||||||
|
return context.resources.getDimensionPixelSize(
|
||||||
|
R.dimen.media_ttt_receiver_icon_bottom_margin
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val RIPPLE_OPACITY = 70
|
||||||
|
const val TONE_PERCENT = 95f
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,14 +33,14 @@ class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleVi
|
|||||||
private var isStarted: Boolean
|
private var isStarted: Boolean
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setupShader(RippleShader.RippleShape.ELLIPSE)
|
setupShader(RippleShader.RippleShape.CIRCLE)
|
||||||
setRippleFill(true)
|
setRippleFill(true)
|
||||||
setSparkleStrength(0f)
|
setSparkleStrength(0f)
|
||||||
duration = 3000L
|
|
||||||
isStarted = false
|
isStarted = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun expandRipple(onAnimationEnd: Runnable? = null) {
|
fun expandRipple(onAnimationEnd: Runnable? = null) {
|
||||||
|
duration = DEFAULT_DURATION
|
||||||
isStarted = true
|
isStarted = true
|
||||||
super.startRipple(onAnimationEnd)
|
super.startRipple(onAnimationEnd)
|
||||||
}
|
}
|
||||||
@@ -50,6 +50,7 @@ class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleVi
|
|||||||
if (!isStarted) {
|
if (!isStarted) {
|
||||||
return // Ignore if ripple is not started yet.
|
return // Ignore if ripple is not started yet.
|
||||||
}
|
}
|
||||||
|
duration = DEFAULT_DURATION
|
||||||
// Reset all listeners to animator.
|
// Reset all listeners to animator.
|
||||||
animator.removeAllListeners()
|
animator.removeAllListeners()
|
||||||
animator.addListener(object : AnimatorListenerAdapter() {
|
animator.addListener(object : AnimatorListenerAdapter() {
|
||||||
@@ -74,6 +75,7 @@ class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleVi
|
|||||||
setRippleFill(false)
|
setRippleFill(false)
|
||||||
|
|
||||||
val startingPercentage = calculateStartingPercentage(newHeight)
|
val startingPercentage = calculateStartingPercentage(newHeight)
|
||||||
|
animator.duration = EXPAND_TO_FULL_DURATION
|
||||||
animator.addUpdateListener { updateListener ->
|
animator.addUpdateListener { updateListener ->
|
||||||
val now = updateListener.currentPlayTime
|
val now = updateListener.currentPlayTime
|
||||||
val progress = updateListener.animatedValue as Float
|
val progress = updateListener.animatedValue as Float
|
||||||
@@ -100,4 +102,9 @@ class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleVi
|
|||||||
val remainingPercentage = (1 - ratio).toDouble().pow(1 / 3.toDouble()).toFloat()
|
val remainingPercentage = (1 - ratio).toDouble().pow(1 / 3.toDouble()).toFloat()
|
||||||
return 1 - remainingPercentage
|
return 1 - remainingPercentage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DEFAULT_DURATION = 333L
|
||||||
|
const val EXPAND_TO_FULL_DURATION = 1000L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class FakeMediaTttChipControllerReceiver(
|
|||||||
viewUtil: ViewUtil,
|
viewUtil: ViewUtil,
|
||||||
wakeLockBuilder: WakeLock.Builder,
|
wakeLockBuilder: WakeLock.Builder,
|
||||||
systemClock: SystemClock,
|
systemClock: SystemClock,
|
||||||
|
rippleController: MediaTttReceiverRippleController,
|
||||||
) :
|
) :
|
||||||
MediaTttChipControllerReceiver(
|
MediaTttChipControllerReceiver(
|
||||||
commandQueue,
|
commandQueue,
|
||||||
@@ -65,6 +66,7 @@ class FakeMediaTttChipControllerReceiver(
|
|||||||
viewUtil,
|
viewUtil,
|
||||||
wakeLockBuilder,
|
wakeLockBuilder,
|
||||||
systemClock,
|
systemClock,
|
||||||
|
rippleController,
|
||||||
) {
|
) {
|
||||||
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
|
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
|
||||||
// Just bypass the animation in tests
|
// Just bypass the animation in tests
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
private lateinit var windowManager: WindowManager
|
private lateinit var windowManager: WindowManager
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var commandQueue: CommandQueue
|
private lateinit var commandQueue: CommandQueue
|
||||||
|
@Mock
|
||||||
|
private lateinit var rippleController: MediaTttReceiverRippleController
|
||||||
private lateinit var commandQueueCallback: CommandQueue.Callbacks
|
private lateinit var commandQueueCallback: CommandQueue.Callbacks
|
||||||
private lateinit var fakeAppIconDrawable: Drawable
|
private lateinit var fakeAppIconDrawable: Drawable
|
||||||
private lateinit var uiEventLoggerFake: UiEventLoggerFake
|
private lateinit var uiEventLoggerFake: UiEventLoggerFake
|
||||||
@@ -134,6 +136,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
viewUtil,
|
viewUtil,
|
||||||
fakeWakeLockBuilder,
|
fakeWakeLockBuilder,
|
||||||
fakeClock,
|
fakeClock,
|
||||||
|
rippleController,
|
||||||
)
|
)
|
||||||
controllerReceiver.start()
|
controllerReceiver.start()
|
||||||
|
|
||||||
@@ -163,6 +166,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
viewUtil,
|
viewUtil,
|
||||||
fakeWakeLockBuilder,
|
fakeWakeLockBuilder,
|
||||||
fakeClock,
|
fakeClock,
|
||||||
|
rippleController,
|
||||||
)
|
)
|
||||||
controllerReceiver.start()
|
controllerReceiver.start()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user