Merge "Add support for rounded notification in groups" into tm-qpr-dev am: 46b33d3f81
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20064744 Change-Id: I1c3a4c808d788ab17baede6457c240bc095f99a6 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -63,7 +63,8 @@ object Flags {
|
|||||||
@JvmField val NOTIFICATION_DISMISSAL_FADE = UnreleasedFlag(113, teamfood = true)
|
@JvmField val NOTIFICATION_DISMISSAL_FADE = UnreleasedFlag(113, teamfood = true)
|
||||||
val STABILITY_INDEX_FIX = UnreleasedFlag(114, teamfood = true)
|
val STABILITY_INDEX_FIX = UnreleasedFlag(114, teamfood = true)
|
||||||
val SEMI_STABLE_SORT = UnreleasedFlag(115, teamfood = true)
|
val SEMI_STABLE_SORT = UnreleasedFlag(115, teamfood = true)
|
||||||
// next id: 116
|
@JvmField val NOTIFICATION_GROUP_CORNER = UnreleasedFlag(116, true)
|
||||||
|
// next id: 117
|
||||||
|
|
||||||
// 200 - keyguard/lockscreen
|
// 200 - keyguard/lockscreen
|
||||||
// ** Flag retired **
|
// ** Flag retired **
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import com.android.systemui.animation.Interpolators;
|
|||||||
import com.android.systemui.animation.ShadeInterpolation;
|
import com.android.systemui.animation.ShadeInterpolation;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
|
||||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||||
|
import com.android.systemui.statusbar.notification.SourceType;
|
||||||
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
|
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
||||||
@@ -110,8 +111,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
|||||||
setClipChildren(false);
|
setClipChildren(false);
|
||||||
setClipToPadding(false);
|
setClipToPadding(false);
|
||||||
mShelfIcons.setIsStaticLayout(false);
|
mShelfIcons.setIsStaticLayout(false);
|
||||||
setBottomRoundness(1.0f, false /* animate */);
|
requestBottomRoundness(1.0f, /* animate = */ false, SourceType.DefaultValue);
|
||||||
setTopRoundness(1f, false /* animate */);
|
requestTopRoundness(1f, false, SourceType.DefaultValue);
|
||||||
|
|
||||||
// Setting this to first in section to get the clipping to the top roundness correct. This
|
// Setting this to first in section to get the clipping to the top roundness correct. This
|
||||||
// value determines the way we are clipping to the top roundness of the overall shade
|
// value determines the way we are clipping to the top roundness of the overall shade
|
||||||
@@ -413,7 +414,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
|||||||
if (iconState != null && iconState.clampedAppearAmount == 1.0f) {
|
if (iconState != null && iconState.clampedAppearAmount == 1.0f) {
|
||||||
// only if the first icon is fully in the shelf we want to clip to it!
|
// only if the first icon is fully in the shelf we want to clip to it!
|
||||||
backgroundTop = (int) (child.getTranslationY() - getTranslationY());
|
backgroundTop = (int) (child.getTranslationY() - getTranslationY());
|
||||||
firstElementRoundness = expandableRow.getCurrentTopRoundness();
|
firstElementRoundness = expandableRow.getTopRoundness();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,28 +508,36 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
|||||||
// Round bottom corners within animation bounds
|
// Round bottom corners within animation bounds
|
||||||
final float changeFraction = MathUtils.saturate(
|
final float changeFraction = MathUtils.saturate(
|
||||||
(viewEnd - cornerAnimationTop) / cornerAnimationDistance);
|
(viewEnd - cornerAnimationTop) / cornerAnimationDistance);
|
||||||
anv.setBottomRoundness(anv.isLastInSection() ? 1f : changeFraction,
|
anv.requestBottomRoundness(
|
||||||
false /* animate */);
|
anv.isLastInSection() ? 1f : changeFraction,
|
||||||
|
/* animate = */ false,
|
||||||
|
SourceType.OnScroll);
|
||||||
|
|
||||||
} else if (viewEnd < cornerAnimationTop) {
|
} else if (viewEnd < cornerAnimationTop) {
|
||||||
// Fast scroll skips frames and leaves corners with unfinished rounding.
|
// Fast scroll skips frames and leaves corners with unfinished rounding.
|
||||||
// Reset top and bottom corners outside of animation bounds.
|
// Reset top and bottom corners outside of animation bounds.
|
||||||
anv.setBottomRoundness(anv.isLastInSection() ? 1f : smallCornerRadius,
|
anv.requestBottomRoundness(
|
||||||
false /* animate */);
|
anv.isLastInSection() ? 1f : smallCornerRadius,
|
||||||
|
/* animate = */ false,
|
||||||
|
SourceType.OnScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewStart >= cornerAnimationTop) {
|
if (viewStart >= cornerAnimationTop) {
|
||||||
// Round top corners within animation bounds
|
// Round top corners within animation bounds
|
||||||
final float changeFraction = MathUtils.saturate(
|
final float changeFraction = MathUtils.saturate(
|
||||||
(viewStart - cornerAnimationTop) / cornerAnimationDistance);
|
(viewStart - cornerAnimationTop) / cornerAnimationDistance);
|
||||||
anv.setTopRoundness(anv.isFirstInSection() ? 1f : changeFraction,
|
anv.requestTopRoundness(
|
||||||
false /* animate */);
|
anv.isFirstInSection() ? 1f : changeFraction,
|
||||||
|
false,
|
||||||
|
SourceType.OnScroll);
|
||||||
|
|
||||||
} else if (viewStart < cornerAnimationTop) {
|
} else if (viewStart < cornerAnimationTop) {
|
||||||
// Fast scroll skips frames and leaves corners with unfinished rounding.
|
// Fast scroll skips frames and leaves corners with unfinished rounding.
|
||||||
// Reset top and bottom corners outside of animation bounds.
|
// Reset top and bottom corners outside of animation bounds.
|
||||||
anv.setTopRoundness(anv.isFirstInSection() ? 1f : smallCornerRadius,
|
anv.requestTopRoundness(
|
||||||
false /* animate */);
|
anv.isFirstInSection() ? 1f : smallCornerRadius,
|
||||||
|
false,
|
||||||
|
SourceType.OnScroll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ class NotificationLaunchAnimatorController(
|
|||||||
val height = max(0, notification.actualHeight - notification.clipBottomAmount)
|
val height = max(0, notification.actualHeight - notification.clipBottomAmount)
|
||||||
val location = notification.locationOnScreen
|
val location = notification.locationOnScreen
|
||||||
|
|
||||||
val clipStartLocation = notificationListContainer.getTopClippingStartLocation()
|
val clipStartLocation = notificationListContainer.topClippingStartLocation
|
||||||
val roundedTopClipping = Math.max(clipStartLocation - location[1], 0)
|
val roundedTopClipping = (clipStartLocation - location[1]).coerceAtLeast(0)
|
||||||
val windowTop = location[1] + roundedTopClipping
|
val windowTop = location[1] + roundedTopClipping
|
||||||
val topCornerRadius = if (roundedTopClipping > 0) {
|
val topCornerRadius = if (roundedTopClipping > 0) {
|
||||||
// Because the rounded Rect clipping is complex, we start the top rounding at
|
// Because the rounded Rect clipping is complex, we start the top rounding at
|
||||||
@@ -80,7 +80,7 @@ class NotificationLaunchAnimatorController(
|
|||||||
// if we'd like to have this perfect, but this is close enough.
|
// if we'd like to have this perfect, but this is close enough.
|
||||||
0f
|
0f
|
||||||
} else {
|
} else {
|
||||||
notification.currentBackgroundRadiusTop
|
notification.topCornerRadius
|
||||||
}
|
}
|
||||||
val params = LaunchAnimationParameters(
|
val params = LaunchAnimationParameters(
|
||||||
top = windowTop,
|
top = windowTop,
|
||||||
@@ -88,7 +88,7 @@ class NotificationLaunchAnimatorController(
|
|||||||
left = location[0],
|
left = location[0],
|
||||||
right = location[0] + notification.width,
|
right = location[0] + notification.width,
|
||||||
topCornerRadius = topCornerRadius,
|
topCornerRadius = topCornerRadius,
|
||||||
bottomCornerRadius = notification.currentBackgroundRadiusBottom
|
bottomCornerRadius = notification.bottomCornerRadius
|
||||||
)
|
)
|
||||||
|
|
||||||
params.startTranslationZ = notification.translationZ
|
params.startTranslationZ = notification.translationZ
|
||||||
@@ -97,8 +97,8 @@ class NotificationLaunchAnimatorController(
|
|||||||
params.startClipTopAmount = notification.clipTopAmount
|
params.startClipTopAmount = notification.clipTopAmount
|
||||||
if (notification.isChildInGroup) {
|
if (notification.isChildInGroup) {
|
||||||
params.startNotificationTop += notification.notificationParent.translationY
|
params.startNotificationTop += notification.notificationParent.translationY
|
||||||
val parentRoundedClip = Math.max(
|
val locationOnScreen = notification.notificationParent.locationOnScreen[1]
|
||||||
clipStartLocation - notification.notificationParent.locationOnScreen[1], 0)
|
val parentRoundedClip = (clipStartLocation - locationOnScreen).coerceAtLeast(0)
|
||||||
params.parentStartRoundedTopClipping = parentRoundedClip
|
params.parentStartRoundedTopClipping = parentRoundedClip
|
||||||
|
|
||||||
val parentClip = notification.notificationParent.clipTopAmount
|
val parentClip = notification.notificationParent.clipTopAmount
|
||||||
|
|||||||
@@ -0,0 +1,284 @@
|
|||||||
|
package com.android.systemui.statusbar.notification
|
||||||
|
|
||||||
|
import android.util.FloatProperty
|
||||||
|
import android.view.View
|
||||||
|
import androidx.annotation.FloatRange
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.statusbar.notification.stack.AnimationProperties
|
||||||
|
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface that allows to request/retrieve top and bottom roundness (a value between 0f and 1f).
|
||||||
|
*
|
||||||
|
* To request a roundness value, an [SourceType] must be specified. In case more origins require
|
||||||
|
* different roundness, for the same property, the maximum value will always be chosen.
|
||||||
|
*
|
||||||
|
* It also returns the current radius for all corners ([updatedRadii]).
|
||||||
|
*/
|
||||||
|
interface Roundable {
|
||||||
|
/** Properties required for a Roundable */
|
||||||
|
val roundableState: RoundableState
|
||||||
|
|
||||||
|
/** Current top roundness */
|
||||||
|
@get:FloatRange(from = 0.0, to = 1.0)
|
||||||
|
@JvmDefault
|
||||||
|
val topRoundness: Float
|
||||||
|
get() = roundableState.topRoundness
|
||||||
|
|
||||||
|
/** Current bottom roundness */
|
||||||
|
@get:FloatRange(from = 0.0, to = 1.0)
|
||||||
|
@JvmDefault
|
||||||
|
val bottomRoundness: Float
|
||||||
|
get() = roundableState.bottomRoundness
|
||||||
|
|
||||||
|
/** Max radius in pixel */
|
||||||
|
@JvmDefault
|
||||||
|
val maxRadius: Float
|
||||||
|
get() = roundableState.maxRadius
|
||||||
|
|
||||||
|
/** Current top corner in pixel, based on [topRoundness] and [maxRadius] */
|
||||||
|
@JvmDefault
|
||||||
|
val topCornerRadius: Float
|
||||||
|
get() = topRoundness * maxRadius
|
||||||
|
|
||||||
|
/** Current bottom corner in pixel, based on [bottomRoundness] and [maxRadius] */
|
||||||
|
@JvmDefault
|
||||||
|
val bottomCornerRadius: Float
|
||||||
|
get() = bottomRoundness * maxRadius
|
||||||
|
|
||||||
|
/** Get and update the current radii */
|
||||||
|
@JvmDefault
|
||||||
|
val updatedRadii: FloatArray
|
||||||
|
get() =
|
||||||
|
roundableState.radiiBuffer.also { radii ->
|
||||||
|
updateRadii(
|
||||||
|
topCornerRadius = topCornerRadius,
|
||||||
|
bottomCornerRadius = bottomCornerRadius,
|
||||||
|
radii = radii,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the top roundness [value] for a specific [sourceType].
|
||||||
|
*
|
||||||
|
* The top roundness of a [Roundable] can be defined by different [sourceType]. In case more
|
||||||
|
* origins require different roundness, for the same property, the maximum value will always be
|
||||||
|
* chosen.
|
||||||
|
*
|
||||||
|
* @param value a value between 0f and 1f.
|
||||||
|
* @param animate true if it should animate to that value.
|
||||||
|
* @param sourceType the source from which the request for roundness comes.
|
||||||
|
* @return Whether the roundness was changed.
|
||||||
|
*/
|
||||||
|
@JvmDefault
|
||||||
|
fun requestTopRoundness(
|
||||||
|
@FloatRange(from = 0.0, to = 1.0) value: Float,
|
||||||
|
animate: Boolean,
|
||||||
|
sourceType: SourceType,
|
||||||
|
): Boolean {
|
||||||
|
val roundnessMap = roundableState.topRoundnessMap
|
||||||
|
val lastValue = roundnessMap.values.maxOrNull() ?: 0f
|
||||||
|
if (value == 0f) {
|
||||||
|
// we should only take the largest value, and since the smallest value is 0f, we can
|
||||||
|
// remove this value from the list. In the worst case, the list is empty and the
|
||||||
|
// default value is 0f.
|
||||||
|
roundnessMap.remove(sourceType)
|
||||||
|
} else {
|
||||||
|
roundnessMap[sourceType] = value
|
||||||
|
}
|
||||||
|
val newValue = roundnessMap.values.maxOrNull() ?: 0f
|
||||||
|
|
||||||
|
if (lastValue != newValue) {
|
||||||
|
val wasAnimating = roundableState.isTopAnimating()
|
||||||
|
|
||||||
|
// Fail safe:
|
||||||
|
// when we've been animating previously and we're now getting an update in the
|
||||||
|
// other direction, make sure to animate it too, otherwise, the localized updating
|
||||||
|
// may make the start larger than 1.0.
|
||||||
|
val shouldAnimate = wasAnimating && abs(newValue - lastValue) > 0.5f
|
||||||
|
|
||||||
|
roundableState.setTopRoundness(value = newValue, animated = shouldAnimate || animate)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the bottom roundness [value] for a specific [sourceType].
|
||||||
|
*
|
||||||
|
* The bottom roundness of a [Roundable] can be defined by different [sourceType]. In case more
|
||||||
|
* origins require different roundness, for the same property, the maximum value will always be
|
||||||
|
* chosen.
|
||||||
|
*
|
||||||
|
* @param value value between 0f and 1f.
|
||||||
|
* @param animate true if it should animate to that value.
|
||||||
|
* @param sourceType the source from which the request for roundness comes.
|
||||||
|
* @return Whether the roundness was changed.
|
||||||
|
*/
|
||||||
|
@JvmDefault
|
||||||
|
fun requestBottomRoundness(
|
||||||
|
@FloatRange(from = 0.0, to = 1.0) value: Float,
|
||||||
|
animate: Boolean,
|
||||||
|
sourceType: SourceType,
|
||||||
|
): Boolean {
|
||||||
|
val roundnessMap = roundableState.bottomRoundnessMap
|
||||||
|
val lastValue = roundnessMap.values.maxOrNull() ?: 0f
|
||||||
|
if (value == 0f) {
|
||||||
|
// we should only take the largest value, and since the smallest value is 0f, we can
|
||||||
|
// remove this value from the list. In the worst case, the list is empty and the
|
||||||
|
// default value is 0f.
|
||||||
|
roundnessMap.remove(sourceType)
|
||||||
|
} else {
|
||||||
|
roundnessMap[sourceType] = value
|
||||||
|
}
|
||||||
|
val newValue = roundnessMap.values.maxOrNull() ?: 0f
|
||||||
|
|
||||||
|
if (lastValue != newValue) {
|
||||||
|
val wasAnimating = roundableState.isBottomAnimating()
|
||||||
|
|
||||||
|
// Fail safe:
|
||||||
|
// when we've been animating previously and we're now getting an update in the
|
||||||
|
// other direction, make sure to animate it too, otherwise, the localized updating
|
||||||
|
// may make the start larger than 1.0.
|
||||||
|
val shouldAnimate = wasAnimating && abs(newValue - lastValue) > 0.5f
|
||||||
|
|
||||||
|
roundableState.setBottomRoundness(value = newValue, animated = shouldAnimate || animate)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Apply the roundness changes, usually means invalidate the [RoundableState.targetView]. */
|
||||||
|
@JvmDefault
|
||||||
|
fun applyRoundness() {
|
||||||
|
roundableState.targetView.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return true if top or bottom roundness is not zero. */
|
||||||
|
@JvmDefault
|
||||||
|
fun hasRoundedCorner(): Boolean {
|
||||||
|
return topRoundness != 0f || bottomRoundness != 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an Array of 8 values, 4 pairs of [X,Y] radii. As expected by param radii of
|
||||||
|
* [android.graphics.Path.addRoundRect].
|
||||||
|
*
|
||||||
|
* This method reuses the previous [radii] for performance reasons.
|
||||||
|
*/
|
||||||
|
@JvmDefault
|
||||||
|
fun updateRadii(
|
||||||
|
topCornerRadius: Float,
|
||||||
|
bottomCornerRadius: Float,
|
||||||
|
radii: FloatArray,
|
||||||
|
) {
|
||||||
|
if (radii.size != 8) error("Unexpected radiiBuffer size ${radii.size}")
|
||||||
|
|
||||||
|
if (radii[0] != topCornerRadius || radii[4] != bottomCornerRadius) {
|
||||||
|
(0..3).forEach { radii[it] = topCornerRadius }
|
||||||
|
(4..7).forEach { radii[it] = bottomCornerRadius }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State object for a `Roundable` class.
|
||||||
|
* @param targetView Will handle the [AnimatableProperty]
|
||||||
|
* @param roundable Target of the radius animation
|
||||||
|
* @param maxRadius Max corner radius in pixels
|
||||||
|
*/
|
||||||
|
class RoundableState(
|
||||||
|
internal val targetView: View,
|
||||||
|
roundable: Roundable,
|
||||||
|
internal val maxRadius: Float,
|
||||||
|
) {
|
||||||
|
/** Animatable for top roundness */
|
||||||
|
private val topAnimatable = topAnimatable(roundable)
|
||||||
|
|
||||||
|
/** Animatable for bottom roundness */
|
||||||
|
private val bottomAnimatable = bottomAnimatable(roundable)
|
||||||
|
|
||||||
|
/** Current top roundness. Use [setTopRoundness] to update this value */
|
||||||
|
@set:FloatRange(from = 0.0, to = 1.0)
|
||||||
|
internal var topRoundness = 0f
|
||||||
|
private set
|
||||||
|
|
||||||
|
/** Current bottom roundness. Use [setBottomRoundness] to update this value */
|
||||||
|
@set:FloatRange(from = 0.0, to = 1.0)
|
||||||
|
internal var bottomRoundness = 0f
|
||||||
|
private set
|
||||||
|
|
||||||
|
/** Last requested top roundness associated by [SourceType] */
|
||||||
|
internal val topRoundnessMap = mutableMapOf<SourceType, Float>()
|
||||||
|
|
||||||
|
/** Last requested bottom roundness associated by [SourceType] */
|
||||||
|
internal val bottomRoundnessMap = mutableMapOf<SourceType, Float>()
|
||||||
|
|
||||||
|
/** Last cached radii */
|
||||||
|
internal val radiiBuffer = FloatArray(8)
|
||||||
|
|
||||||
|
/** Is top roundness animation in progress? */
|
||||||
|
internal fun isTopAnimating() = PropertyAnimator.isAnimating(targetView, topAnimatable)
|
||||||
|
|
||||||
|
/** Is bottom roundness animation in progress? */
|
||||||
|
internal fun isBottomAnimating() = PropertyAnimator.isAnimating(targetView, bottomAnimatable)
|
||||||
|
|
||||||
|
/** Set the current top roundness */
|
||||||
|
internal fun setTopRoundness(
|
||||||
|
value: Float,
|
||||||
|
animated: Boolean = targetView.isShown,
|
||||||
|
) {
|
||||||
|
PropertyAnimator.setProperty(targetView, topAnimatable, value, DURATION, animated)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the current bottom roundness */
|
||||||
|
internal fun setBottomRoundness(
|
||||||
|
value: Float,
|
||||||
|
animated: Boolean = targetView.isShown,
|
||||||
|
) {
|
||||||
|
PropertyAnimator.setProperty(targetView, bottomAnimatable, value, DURATION, animated)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val DURATION: AnimationProperties =
|
||||||
|
AnimationProperties()
|
||||||
|
.setDuration(StackStateAnimator.ANIMATION_DURATION_CORNER_RADIUS.toLong())
|
||||||
|
|
||||||
|
private fun topAnimatable(roundable: Roundable): AnimatableProperty =
|
||||||
|
AnimatableProperty.from(
|
||||||
|
object : FloatProperty<View>("topRoundness") {
|
||||||
|
override fun get(view: View): Float = roundable.topRoundness
|
||||||
|
|
||||||
|
override fun setValue(view: View, value: Float) {
|
||||||
|
roundable.roundableState.topRoundness = value
|
||||||
|
roundable.applyRoundness()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
R.id.top_roundess_animator_tag,
|
||||||
|
R.id.top_roundess_animator_end_tag,
|
||||||
|
R.id.top_roundess_animator_start_tag,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun bottomAnimatable(roundable: Roundable): AnimatableProperty =
|
||||||
|
AnimatableProperty.from(
|
||||||
|
object : FloatProperty<View>("bottomRoundness") {
|
||||||
|
override fun get(view: View): Float = roundable.bottomRoundness
|
||||||
|
|
||||||
|
override fun setValue(view: View, value: Float) {
|
||||||
|
roundable.roundableState.bottomRoundness = value
|
||||||
|
roundable.applyRoundness()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
R.id.bottom_roundess_animator_tag,
|
||||||
|
R.id.bottom_roundess_animator_end_tag,
|
||||||
|
R.id.bottom_roundess_animator_start_tag,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class SourceType {
|
||||||
|
DefaultValue,
|
||||||
|
OnDismissAnimation,
|
||||||
|
OnScroll,
|
||||||
|
}
|
||||||
@@ -613,22 +613,21 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
|
|||||||
protected void resetAllContentAlphas() {}
|
protected void resetAllContentAlphas() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyRoundness() {
|
public void applyRoundness() {
|
||||||
super.applyRoundness();
|
super.applyRoundness();
|
||||||
applyBackgroundRoundness(getCurrentBackgroundRadiusTop(),
|
applyBackgroundRoundness(getTopCornerRadius(), getBottomCornerRadius());
|
||||||
getCurrentBackgroundRadiusBottom());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getCurrentBackgroundRadiusTop() {
|
public float getTopCornerRadius() {
|
||||||
float fraction = getInterpolatedAppearAnimationFraction();
|
float fraction = getInterpolatedAppearAnimationFraction();
|
||||||
return MathUtils.lerp(0, super.getCurrentBackgroundRadiusTop(), fraction);
|
return MathUtils.lerp(0, super.getTopCornerRadius(), fraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getCurrentBackgroundRadiusBottom() {
|
public float getBottomCornerRadius() {
|
||||||
float fraction = getInterpolatedAppearAnimationFraction();
|
float fraction = getInterpolatedAppearAnimationFraction();
|
||||||
return MathUtils.lerp(0, super.getCurrentBackgroundRadiusBottom(), fraction);
|
return MathUtils.lerp(0, super.getBottomCornerRadius(), fraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyBackgroundRoundness(float topRadius, float bottomRadius) {
|
private void applyBackgroundRoundness(float topRadius, float bottomRadius) {
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
|
|||||||
import com.android.systemui.statusbar.notification.NotificationFadeAware;
|
import com.android.systemui.statusbar.notification.NotificationFadeAware;
|
||||||
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
|
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
|
||||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||||
|
import com.android.systemui.statusbar.notification.SourceType;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
|
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
|
||||||
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
|
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
|
||||||
@@ -154,7 +155,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
void onLayout();
|
void onLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Listens for changes to the expansion state of this row. */
|
/**
|
||||||
|
* Listens for changes to the expansion state of this row.
|
||||||
|
*/
|
||||||
public interface OnExpansionChangedListener {
|
public interface OnExpansionChangedListener {
|
||||||
void onExpansionChanged(boolean isExpanded);
|
void onExpansionChanged(boolean isExpanded);
|
||||||
}
|
}
|
||||||
@@ -183,22 +186,34 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
private int mNotificationLaunchHeight;
|
private int mNotificationLaunchHeight;
|
||||||
private boolean mMustStayOnScreen;
|
private boolean mMustStayOnScreen;
|
||||||
|
|
||||||
/** Does this row contain layouts that can adapt to row expansion */
|
/**
|
||||||
|
* Does this row contain layouts that can adapt to row expansion
|
||||||
|
*/
|
||||||
private boolean mExpandable;
|
private boolean mExpandable;
|
||||||
/** Has the user actively changed the expansion state of this row */
|
/**
|
||||||
|
* Has the user actively changed the expansion state of this row
|
||||||
|
*/
|
||||||
private boolean mHasUserChangedExpansion;
|
private boolean mHasUserChangedExpansion;
|
||||||
/** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
|
/**
|
||||||
|
* If {@link #mHasUserChangedExpansion}, has the user expanded this row
|
||||||
|
*/
|
||||||
private boolean mUserExpanded;
|
private boolean mUserExpanded;
|
||||||
/** Whether the blocking helper is showing on this notification (even if dismissed) */
|
/**
|
||||||
|
* Whether the blocking helper is showing on this notification (even if dismissed)
|
||||||
|
*/
|
||||||
private boolean mIsBlockingHelperShowing;
|
private boolean mIsBlockingHelperShowing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Has this notification been expanded while it was pinned
|
* Has this notification been expanded while it was pinned
|
||||||
*/
|
*/
|
||||||
private boolean mExpandedWhenPinned;
|
private boolean mExpandedWhenPinned;
|
||||||
/** Is the user touching this row */
|
/**
|
||||||
|
* Is the user touching this row
|
||||||
|
*/
|
||||||
private boolean mUserLocked;
|
private boolean mUserLocked;
|
||||||
/** Are we showing the "public" version */
|
/**
|
||||||
|
* Are we showing the "public" version
|
||||||
|
*/
|
||||||
private boolean mShowingPublic;
|
private boolean mShowingPublic;
|
||||||
private boolean mSensitive;
|
private boolean mSensitive;
|
||||||
private boolean mSensitiveHiddenInGeneral;
|
private boolean mSensitiveHiddenInGeneral;
|
||||||
@@ -351,11 +366,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
private boolean mWasChildInGroupWhenRemoved;
|
private boolean mWasChildInGroupWhenRemoved;
|
||||||
private NotificationInlineImageResolver mImageResolver;
|
private NotificationInlineImageResolver mImageResolver;
|
||||||
private NotificationMediaManager mMediaManager;
|
private NotificationMediaManager mMediaManager;
|
||||||
@Nullable private OnExpansionChangedListener mExpansionChangedListener;
|
@Nullable
|
||||||
@Nullable private Runnable mOnIntrinsicHeightReachedRunnable;
|
private OnExpansionChangedListener mExpansionChangedListener;
|
||||||
|
@Nullable
|
||||||
|
private Runnable mOnIntrinsicHeightReachedRunnable;
|
||||||
|
|
||||||
private float mTopRoundnessDuringLaunchAnimation;
|
private float mTopRoundnessDuringLaunchAnimation;
|
||||||
private float mBottomRoundnessDuringLaunchAnimation;
|
private float mBottomRoundnessDuringLaunchAnimation;
|
||||||
|
private boolean mIsNotificationGroupCornerEnabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the given {@code statusBarNotification} is a system notification.
|
* Returns whether the given {@code statusBarNotification} is a system notification.
|
||||||
@@ -574,14 +592,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when the notification's ranking was changed (but nothing else changed). */
|
/**
|
||||||
|
* Called when the notification's ranking was changed (but nothing else changed).
|
||||||
|
*/
|
||||||
public void onNotificationRankingUpdated() {
|
public void onNotificationRankingUpdated() {
|
||||||
if (mMenuRow != null) {
|
if (mMenuRow != null) {
|
||||||
mMenuRow.onNotificationUpdated(mEntry.getSbn());
|
mMenuRow.onNotificationUpdated(mEntry.getSbn());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Call when bubble state has changed and the button on the notification should be updated. */
|
/**
|
||||||
|
* Call when bubble state has changed and the button on the notification should be updated.
|
||||||
|
*/
|
||||||
public void updateBubbleButton() {
|
public void updateBubbleButton() {
|
||||||
for (NotificationContentView l : mLayouts) {
|
for (NotificationContentView l : mLayouts) {
|
||||||
l.updateBubbleButton(mEntry);
|
l.updateBubbleButton(mEntry);
|
||||||
@@ -620,6 +642,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a supplier that can determine whether the keyguard is secure or not.
|
* Sets a supplier that can determine whether the keyguard is secure or not.
|
||||||
|
*
|
||||||
* @param secureStateProvider A function that returns true if keyguard is secure.
|
* @param secureStateProvider A function that returns true if keyguard is secure.
|
||||||
*/
|
*/
|
||||||
public void setSecureStateProvider(BooleanSupplier secureStateProvider) {
|
public void setSecureStateProvider(BooleanSupplier secureStateProvider) {
|
||||||
@@ -781,7 +804,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
mChildrenContainer.setUntruncatedChildCount(childCount);
|
mChildrenContainer.setUntruncatedChildCount(childCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called after children have been attached to set the expansion states */
|
/**
|
||||||
|
* Called after children have been attached to set the expansion states
|
||||||
|
*/
|
||||||
public void resetChildSystemExpandedStates() {
|
public void resetChildSystemExpandedStates() {
|
||||||
if (isSummaryWithChildren()) {
|
if (isSummaryWithChildren()) {
|
||||||
mChildrenContainer.updateExpansionStates();
|
mChildrenContainer.updateExpansionStates();
|
||||||
@@ -809,10 +834,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
}
|
}
|
||||||
onAttachedChildrenCountChanged();
|
onAttachedChildrenCountChanged();
|
||||||
row.setIsChildInGroup(false, null);
|
row.setIsChildInGroup(false, null);
|
||||||
row.setBottomRoundness(0.0f, false /* animate */);
|
row.requestBottomRoundness(0.0f, /* animate = */ false, SourceType.DefaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the child notification at [index], or null if no such child. */
|
/**
|
||||||
|
* Returns the child notification at [index], or null if no such child.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public ExpandableNotificationRow getChildNotificationAt(int index) {
|
public ExpandableNotificationRow getChildNotificationAt(int index) {
|
||||||
if (mChildrenContainer == null
|
if (mChildrenContainer == null
|
||||||
@@ -898,7 +925,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
return mChildrenContainer == null ? null : mChildrenContainer.getAttachedChildren();
|
return mChildrenContainer == null ? null : mChildrenContainer.getAttachedChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Updates states of all children. */
|
/**
|
||||||
|
* Updates states of all children.
|
||||||
|
*/
|
||||||
public void updateChildrenStates(AmbientState ambientState) {
|
public void updateChildrenStates(AmbientState ambientState) {
|
||||||
if (mIsSummaryWithChildren) {
|
if (mIsSummaryWithChildren) {
|
||||||
ExpandableViewState parentState = getViewState();
|
ExpandableViewState parentState = getViewState();
|
||||||
@@ -906,21 +935,27 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Applies children states. */
|
/**
|
||||||
|
* Applies children states.
|
||||||
|
*/
|
||||||
public void applyChildrenState() {
|
public void applyChildrenState() {
|
||||||
if (mIsSummaryWithChildren) {
|
if (mIsSummaryWithChildren) {
|
||||||
mChildrenContainer.applyState();
|
mChildrenContainer.applyState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Prepares expansion changed. */
|
/**
|
||||||
|
* Prepares expansion changed.
|
||||||
|
*/
|
||||||
public void prepareExpansionChanged() {
|
public void prepareExpansionChanged() {
|
||||||
if (mIsSummaryWithChildren) {
|
if (mIsSummaryWithChildren) {
|
||||||
mChildrenContainer.prepareExpansionChanged();
|
mChildrenContainer.prepareExpansionChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Starts child animations. */
|
/**
|
||||||
|
* Starts child animations.
|
||||||
|
*/
|
||||||
public void startChildAnimation(AnimationProperties properties) {
|
public void startChildAnimation(AnimationProperties properties) {
|
||||||
if (mIsSummaryWithChildren) {
|
if (mIsSummaryWithChildren) {
|
||||||
mChildrenContainer.startAnimationToState(properties);
|
mChildrenContainer.startAnimationToState(properties);
|
||||||
@@ -984,7 +1019,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
if (mIsSummaryWithChildren) {
|
if (mIsSummaryWithChildren) {
|
||||||
return mChildrenContainer.getIntrinsicHeight();
|
return mChildrenContainer.getIntrinsicHeight();
|
||||||
}
|
}
|
||||||
if(mExpandedWhenPinned) {
|
if (mExpandedWhenPinned) {
|
||||||
return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
|
return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
|
||||||
} else if (atLeastMinHeight) {
|
} else if (atLeastMinHeight) {
|
||||||
return Math.max(getCollapsedHeight(), getHeadsUpHeight());
|
return Math.max(getCollapsedHeight(), getHeadsUpHeight());
|
||||||
@@ -1079,7 +1114,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
updateClickAndFocus();
|
updateClickAndFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The click listener for the bubble button. */
|
/**
|
||||||
|
* The click listener for the bubble button.
|
||||||
|
*/
|
||||||
public View.OnClickListener getBubbleClickListener() {
|
public View.OnClickListener getBubbleClickListener() {
|
||||||
return v -> {
|
return v -> {
|
||||||
if (mBubblesManagerOptional.isPresent()) {
|
if (mBubblesManagerOptional.isPresent()) {
|
||||||
@@ -1090,7 +1127,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The click listener for the snooze button. */
|
/**
|
||||||
|
* The click listener for the snooze button.
|
||||||
|
*/
|
||||||
public View.OnClickListener getSnoozeClickListener(MenuItem item) {
|
public View.OnClickListener getSnoozeClickListener(MenuItem item) {
|
||||||
return v -> {
|
return v -> {
|
||||||
// Dismiss a snoozed notification if one is still left behind
|
// Dismiss a snoozed notification if one is still left behind
|
||||||
@@ -1637,7 +1676,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
setTargetPoint(null);
|
setTargetPoint(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Shows the given feedback icon, or hides the icon if null. */
|
/**
|
||||||
|
* Shows the given feedback icon, or hides the icon if null.
|
||||||
|
*/
|
||||||
public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
|
public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
|
||||||
if (mIsSummaryWithChildren) {
|
if (mIsSummaryWithChildren) {
|
||||||
mChildrenContainer.setFeedbackIcon(icon);
|
mChildrenContainer.setFeedbackIcon(icon);
|
||||||
@@ -1646,7 +1687,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
mPublicLayout.setFeedbackIcon(icon);
|
mPublicLayout.setFeedbackIcon(icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the last time the notification being displayed audibly alerted the user. */
|
/**
|
||||||
|
* Sets the last time the notification being displayed audibly alerted the user.
|
||||||
|
*/
|
||||||
public void setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) {
|
public void setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) {
|
||||||
long timeSinceAlertedAudibly = System.currentTimeMillis() - lastAudiblyAlertedMs;
|
long timeSinceAlertedAudibly = System.currentTimeMillis() - lastAudiblyAlertedMs;
|
||||||
boolean alertedRecently = timeSinceAlertedAudibly < RECENTLY_ALERTED_THRESHOLD_MS;
|
boolean alertedRecently = timeSinceAlertedAudibly < RECENTLY_ALERTED_THRESHOLD_MS;
|
||||||
@@ -1700,7 +1743,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
Trace.endSection();
|
Trace.endSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Generates and appends "(MessagingStyle)" type tag to passed string for tracing. */
|
/**
|
||||||
|
* Generates and appends "(MessagingStyle)" type tag to passed string for tracing.
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private String appendTraceStyleTag(@NonNull String traceTag) {
|
private String appendTraceStyleTag(@NonNull String traceTag) {
|
||||||
if (!Trace.isEnabled()) {
|
if (!Trace.isEnabled()) {
|
||||||
@@ -1721,7 +1766,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
mPublicLayout = findViewById(R.id.expandedPublic);
|
mPublicLayout = findViewById(R.id.expandedPublic);
|
||||||
mPrivateLayout = findViewById(R.id.expanded);
|
mPrivateLayout = findViewById(R.id.expanded);
|
||||||
mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
|
mLayouts = new NotificationContentView[]{mPrivateLayout, mPublicLayout};
|
||||||
|
|
||||||
for (NotificationContentView l : mLayouts) {
|
for (NotificationContentView l : mLayouts) {
|
||||||
l.setExpandClickListener(mExpandClickListener);
|
l.setExpandClickListener(mExpandClickListener);
|
||||||
@@ -1740,6 +1785,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
mChildrenContainer.setIsLowPriority(mIsLowPriority);
|
mChildrenContainer.setIsLowPriority(mIsLowPriority);
|
||||||
mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
|
mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
|
||||||
mChildrenContainer.onNotificationUpdated();
|
mChildrenContainer.onNotificationUpdated();
|
||||||
|
mChildrenContainer.enableNotificationGroupCorner(mIsNotificationGroupCornerEnabled);
|
||||||
|
|
||||||
mTranslateableViews.add(mChildrenContainer);
|
mTranslateableViews.add(mChildrenContainer);
|
||||||
});
|
});
|
||||||
@@ -1796,6 +1842,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
/**
|
/**
|
||||||
* Perform a smart action which triggers a longpress (expose guts).
|
* Perform a smart action which triggers a longpress (expose guts).
|
||||||
* Based on the semanticAction passed, may update the state of the guts view.
|
* Based on the semanticAction passed, may update the state of the guts view.
|
||||||
|
*
|
||||||
* @param semanticAction associated with this smart action click
|
* @param semanticAction associated with this smart action click
|
||||||
*/
|
*/
|
||||||
public void doSmartActionClick(int x, int y, int semanticAction) {
|
public void doSmartActionClick(int x, int y, int semanticAction) {
|
||||||
@@ -1939,6 +1986,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the dismiss behavior of the view.
|
* Set the dismiss behavior of the view.
|
||||||
|
*
|
||||||
* @param usingRowTranslationX {@code true} if the view should translate using regular
|
* @param usingRowTranslationX {@code true} if the view should translate using regular
|
||||||
* translationX, otherwise the contents will be
|
* translationX, otherwise the contents will be
|
||||||
* translated.
|
* translated.
|
||||||
@@ -1955,6 +2003,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
if (previousTranslation != 0) {
|
if (previousTranslation != 0) {
|
||||||
setTranslation(previousTranslation);
|
setTranslation(previousTranslation);
|
||||||
}
|
}
|
||||||
|
if (mChildrenContainer != null) {
|
||||||
|
List<ExpandableNotificationRow> notificationChildren =
|
||||||
|
mChildrenContainer.getAttachedChildren();
|
||||||
|
for (int i = 0; i < notificationChildren.size(); i++) {
|
||||||
|
ExpandableNotificationRow child = notificationChildren.get(i);
|
||||||
|
child.setDismissUsingRowTranslationX(usingRowTranslationX);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2151,29 +2207,30 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
}
|
}
|
||||||
setTranslationY(top);
|
setTranslationY(top);
|
||||||
|
|
||||||
mTopRoundnessDuringLaunchAnimation = params.getTopCornerRadius() / mOutlineRadius;
|
final float maxRadius = getMaxRadius();
|
||||||
mBottomRoundnessDuringLaunchAnimation = params.getBottomCornerRadius() / mOutlineRadius;
|
mTopRoundnessDuringLaunchAnimation = params.getTopCornerRadius() / maxRadius;
|
||||||
|
mBottomRoundnessDuringLaunchAnimation = params.getBottomCornerRadius() / maxRadius;
|
||||||
invalidateOutline();
|
invalidateOutline();
|
||||||
|
|
||||||
mBackgroundNormal.setExpandAnimationSize(params.getWidth(), actualHeight);
|
mBackgroundNormal.setExpandAnimationSize(params.getWidth(), actualHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getCurrentTopRoundness() {
|
public float getTopRoundness() {
|
||||||
if (mExpandAnimationRunning) {
|
if (mExpandAnimationRunning) {
|
||||||
return mTopRoundnessDuringLaunchAnimation;
|
return mTopRoundnessDuringLaunchAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getCurrentTopRoundness();
|
return super.getTopRoundness();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getCurrentBottomRoundness() {
|
public float getBottomRoundness() {
|
||||||
if (mExpandAnimationRunning) {
|
if (mExpandAnimationRunning) {
|
||||||
return mBottomRoundnessDuringLaunchAnimation;
|
return mBottomRoundnessDuringLaunchAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getCurrentBottomRoundness();
|
return super.getBottomRoundness();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExpandAnimationRunning(boolean expandAnimationRunning) {
|
public void setExpandAnimationRunning(boolean expandAnimationRunning) {
|
||||||
@@ -2658,9 +2715,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
|
|
||||||
private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
|
private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
|
||||||
View[] privateViews = mIsSummaryWithChildren
|
View[] privateViews = mIsSummaryWithChildren
|
||||||
? new View[] {mChildrenContainer}
|
? new View[]{mChildrenContainer}
|
||||||
: new View[] {mPrivateLayout};
|
: new View[]{mPrivateLayout};
|
||||||
View[] publicViews = new View[] {mPublicLayout};
|
View[] publicViews = new View[]{mPublicLayout};
|
||||||
View[] hiddenChildren = showingPublic ? privateViews : publicViews;
|
View[] hiddenChildren = showingPublic ? privateViews : publicViews;
|
||||||
View[] shownChildren = showingPublic ? publicViews : privateViews;
|
View[] shownChildren = showingPublic ? publicViews : privateViews;
|
||||||
for (final View hiddenView : hiddenChildren) {
|
for (final View hiddenView : hiddenChildren) {
|
||||||
@@ -2777,8 +2834,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long performRemoveAnimation(long duration, long delay, float translationDirection,
|
public long performRemoveAnimation(
|
||||||
boolean isHeadsUpAnimation, float endLocation, Runnable onFinishedRunnable,
|
long duration,
|
||||||
|
long delay,
|
||||||
|
float translationDirection,
|
||||||
|
boolean isHeadsUpAnimation,
|
||||||
|
float endLocation,
|
||||||
|
Runnable onFinishedRunnable,
|
||||||
AnimatorListenerAdapter animationListener) {
|
AnimatorListenerAdapter animationListener) {
|
||||||
if (mMenuRow != null && mMenuRow.isMenuVisible()) {
|
if (mMenuRow != null && mMenuRow.isMenuVisible()) {
|
||||||
Animator anim = getTranslateViewAnimator(0f, null /* listener */);
|
Animator anim = getTranslateViewAnimator(0f, null /* listener */);
|
||||||
@@ -2828,7 +2890,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the last value set with {@link #setNotificationFaded(boolean)} */
|
/**
|
||||||
|
* Gets the last value set with {@link #setNotificationFaded(boolean)}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isNotificationFaded() {
|
public boolean isNotificationFaded() {
|
||||||
return mIsFaded;
|
return mIsFaded;
|
||||||
@@ -2843,7 +2907,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
* notifications return false from {@link #hasOverlappingRendering()} and delegate the
|
* notifications return false from {@link #hasOverlappingRendering()} and delegate the
|
||||||
* layerType to child views which really need it in order to render correctly, such as icon
|
* layerType to child views which really need it in order to render correctly, such as icon
|
||||||
* views or the conversation face pile.
|
* views or the conversation face pile.
|
||||||
*
|
* <p>
|
||||||
* Another compounding factor for notifications is that we change clipping on each frame of the
|
* Another compounding factor for notifications is that we change clipping on each frame of the
|
||||||
* animation, so the hardware layer isn't able to do any caching at the top level, but the
|
* animation, so the hardware layer isn't able to do any caching at the top level, but the
|
||||||
* individual elements we render with hardware layers (e.g. icons) cache wonderfully because we
|
* individual elements we render with hardware layers (e.g. icons) cache wonderfully because we
|
||||||
@@ -2869,7 +2933,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Private helper for iterating over the layouts and children containers to set faded state */
|
/**
|
||||||
|
* Private helper for iterating over the layouts and children containers to set faded state
|
||||||
|
*/
|
||||||
private void setNotificationFadedOnChildren(boolean faded) {
|
private void setNotificationFadedOnChildren(boolean faded) {
|
||||||
delegateNotificationFaded(mChildrenContainer, faded);
|
delegateNotificationFaded(mChildrenContainer, faded);
|
||||||
for (NotificationContentView layout : mLayouts) {
|
for (NotificationContentView layout : mLayouts) {
|
||||||
@@ -2897,7 +2963,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
* Because RemoteInputView is designed to be an opaque view that overlaps the Actions row, the
|
* Because RemoteInputView is designed to be an opaque view that overlaps the Actions row, the
|
||||||
* row should require overlapping rendering to ensure that the overlapped view doesn't bleed
|
* row should require overlapping rendering to ensure that the overlapped view doesn't bleed
|
||||||
* through when alpha fading.
|
* through when alpha fading.
|
||||||
*
|
* <p>
|
||||||
* Note that this currently works for top-level notifications which squish their height down
|
* Note that this currently works for top-level notifications which squish their height down
|
||||||
* while collapsing the shade, but does not work for children inside groups, because the
|
* while collapsing the shade, but does not work for children inside groups, because the
|
||||||
* accordion affect does not apply to those views, so super.hasOverlappingRendering() will
|
* accordion affect does not apply to those views, so super.hasOverlappingRendering() will
|
||||||
@@ -3280,17 +3346,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
NotificationContentView contentView = (NotificationContentView) child;
|
NotificationContentView contentView = (NotificationContentView) child;
|
||||||
if (isClippingNeeded()) {
|
if (isClippingNeeded()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (!hasNoRounding()
|
} else if (hasRoundedCorner()
|
||||||
&& contentView.shouldClipToRounding(getCurrentTopRoundness() != 0.0f,
|
&& contentView.shouldClipToRounding(getTopRoundness() != 0.0f,
|
||||||
getCurrentBottomRoundness() != 0.0f)) {
|
getBottomRoundness() != 0.0f)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (child == mChildrenContainer) {
|
} else if (child == mChildrenContainer) {
|
||||||
if (isClippingNeeded() || !hasNoRounding()) {
|
if (isClippingNeeded() || hasRoundedCorner()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (child instanceof NotificationGuts) {
|
} else if (child instanceof NotificationGuts) {
|
||||||
return !hasNoRounding();
|
return hasRoundedCorner();
|
||||||
}
|
}
|
||||||
return super.childNeedsClipping(child);
|
return super.childNeedsClipping(child);
|
||||||
}
|
}
|
||||||
@@ -3316,14 +3382,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyRoundness() {
|
public void applyRoundness() {
|
||||||
super.applyRoundness();
|
super.applyRoundness();
|
||||||
applyChildrenRoundness();
|
applyChildrenRoundness();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyChildrenRoundness() {
|
private void applyChildrenRoundness() {
|
||||||
if (mIsSummaryWithChildren) {
|
if (mIsSummaryWithChildren) {
|
||||||
mChildrenContainer.setCurrentBottomRoundness(getCurrentBottomRoundness());
|
mChildrenContainer.requestBottomRoundness(
|
||||||
|
getBottomRoundness(),
|
||||||
|
/* animate = */ false,
|
||||||
|
SourceType.DefaultValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3335,10 +3404,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
return super.getCustomClipPath(child);
|
return super.getCustomClipPath(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasNoRounding() {
|
|
||||||
return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMediaRow() {
|
public boolean isMediaRow() {
|
||||||
return mEntry.getSbn().getNotification().isMediaNotification();
|
return mEntry.getSbn().getNotification().isMediaNotification();
|
||||||
}
|
}
|
||||||
@@ -3434,6 +3499,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
public interface LongPressListener {
|
public interface LongPressListener {
|
||||||
/**
|
/**
|
||||||
* Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
|
* Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
|
||||||
|
*
|
||||||
* @return whether the longpress was handled
|
* @return whether the longpress was handled
|
||||||
*/
|
*/
|
||||||
boolean onLongPress(View v, int x, int y, MenuItem item);
|
boolean onLongPress(View v, int x, int y, MenuItem item);
|
||||||
@@ -3455,6 +3521,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
public interface CoordinateOnClickListener {
|
public interface CoordinateOnClickListener {
|
||||||
/**
|
/**
|
||||||
* Equivalent to {@link View.OnClickListener#onClick(View)} with coordinates
|
* Equivalent to {@link View.OnClickListener#onClick(View)} with coordinates
|
||||||
|
*
|
||||||
* @return whether the click was handled
|
* @return whether the click was handled
|
||||||
*/
|
*/
|
||||||
boolean onClick(View v, int x, int y, MenuItem item);
|
boolean onClick(View v, int x, int y, MenuItem item);
|
||||||
@@ -3511,7 +3578,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
private void setTargetPoint(Point p) {
|
private void setTargetPoint(Point p) {
|
||||||
mTargetPoint = p;
|
mTargetPoint = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point getTargetPoint() {
|
public Point getTargetPoint() {
|
||||||
return mTargetPoint;
|
return mTargetPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the support for rounded corner in notification group
|
||||||
|
* @param enabled true if is supported
|
||||||
|
*/
|
||||||
|
public void enableNotificationGroupCorner(boolean enabled) {
|
||||||
|
mIsNotificationGroupCornerEnabled = enabled;
|
||||||
|
if (mChildrenContainer != null) {
|
||||||
|
mChildrenContainer.enableNotificationGroupCorner(mIsNotificationGroupCornerEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,6 +231,8 @@ public class ExpandableNotificationRowController implements NotifViewController
|
|||||||
mStatusBarStateController.removeCallback(mStatusBarStateListener);
|
mStatusBarStateController.removeCallback(mStatusBarStateListener);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
mView.enableNotificationGroupCorner(
|
||||||
|
mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_CORNER));
|
||||||
}
|
}
|
||||||
|
|
||||||
private final StatusBarStateController.StateListener mStatusBarStateListener =
|
private final StatusBarStateController.StateListener mStatusBarStateListener =
|
||||||
|
|||||||
@@ -28,46 +28,21 @@ import android.view.View;
|
|||||||
import android.view.ViewOutlineProvider;
|
import android.view.ViewOutlineProvider;
|
||||||
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.statusbar.notification.AnimatableProperty;
|
import com.android.systemui.statusbar.notification.RoundableState;
|
||||||
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
|
||||||
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
|
|
||||||
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like {@link ExpandableView}, but setting an outline for the height and clipping.
|
* Like {@link ExpandableView}, but setting an outline for the height and clipping.
|
||||||
*/
|
*/
|
||||||
public abstract class ExpandableOutlineView extends ExpandableView {
|
public abstract class ExpandableOutlineView extends ExpandableView {
|
||||||
|
|
||||||
private static final AnimatableProperty TOP_ROUNDNESS = AnimatableProperty.from(
|
private RoundableState mRoundableState;
|
||||||
"topRoundness",
|
|
||||||
ExpandableOutlineView::setTopRoundnessInternal,
|
|
||||||
ExpandableOutlineView::getCurrentTopRoundness,
|
|
||||||
R.id.top_roundess_animator_tag,
|
|
||||||
R.id.top_roundess_animator_end_tag,
|
|
||||||
R.id.top_roundess_animator_start_tag);
|
|
||||||
private static final AnimatableProperty BOTTOM_ROUNDNESS = AnimatableProperty.from(
|
|
||||||
"bottomRoundness",
|
|
||||||
ExpandableOutlineView::setBottomRoundnessInternal,
|
|
||||||
ExpandableOutlineView::getCurrentBottomRoundness,
|
|
||||||
R.id.bottom_roundess_animator_tag,
|
|
||||||
R.id.bottom_roundess_animator_end_tag,
|
|
||||||
R.id.bottom_roundess_animator_start_tag);
|
|
||||||
private static final AnimationProperties ROUNDNESS_PROPERTIES =
|
|
||||||
new AnimationProperties().setDuration(
|
|
||||||
StackStateAnimator.ANIMATION_DURATION_CORNER_RADIUS);
|
|
||||||
private static final Path EMPTY_PATH = new Path();
|
private static final Path EMPTY_PATH = new Path();
|
||||||
|
|
||||||
private final Rect mOutlineRect = new Rect();
|
private final Rect mOutlineRect = new Rect();
|
||||||
private final Path mClipPath = new Path();
|
|
||||||
private boolean mCustomOutline;
|
private boolean mCustomOutline;
|
||||||
private float mOutlineAlpha = -1f;
|
private float mOutlineAlpha = -1f;
|
||||||
protected float mOutlineRadius;
|
|
||||||
private boolean mAlwaysRoundBothCorners;
|
private boolean mAlwaysRoundBothCorners;
|
||||||
private Path mTmpPath = new Path();
|
private Path mTmpPath = new Path();
|
||||||
private float mCurrentBottomRoundness;
|
|
||||||
private float mCurrentTopRoundness;
|
|
||||||
private float mBottomRoundness;
|
|
||||||
private float mTopRoundness;
|
|
||||||
private int mBackgroundTop;
|
private int mBackgroundTop;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,8 +55,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
|||||||
private final ViewOutlineProvider mProvider = new ViewOutlineProvider() {
|
private final ViewOutlineProvider mProvider = new ViewOutlineProvider() {
|
||||||
@Override
|
@Override
|
||||||
public void getOutline(View view, Outline outline) {
|
public void getOutline(View view, Outline outline) {
|
||||||
if (!mCustomOutline && getCurrentTopRoundness() == 0.0f
|
if (!mCustomOutline && !hasRoundedCorner() && !mAlwaysRoundBothCorners) {
|
||||||
&& getCurrentBottomRoundness() == 0.0f && !mAlwaysRoundBothCorners) {
|
|
||||||
// Only when translating just the contents, does the outline need to be shifted.
|
// Only when translating just the contents, does the outline need to be shifted.
|
||||||
int translation = !mDismissUsingRowTranslationX ? (int) getTranslation() : 0;
|
int translation = !mDismissUsingRowTranslationX ? (int) getTranslation() : 0;
|
||||||
int left = Math.max(translation, 0);
|
int left = Math.max(translation, 0);
|
||||||
@@ -99,14 +73,18 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RoundableState getRoundableState() {
|
||||||
|
return mRoundableState;
|
||||||
|
}
|
||||||
|
|
||||||
protected Path getClipPath(boolean ignoreTranslation) {
|
protected Path getClipPath(boolean ignoreTranslation) {
|
||||||
int left;
|
int left;
|
||||||
int top;
|
int top;
|
||||||
int right;
|
int right;
|
||||||
int bottom;
|
int bottom;
|
||||||
int height;
|
int height;
|
||||||
float topRoundness = mAlwaysRoundBothCorners
|
float topRoundness = mAlwaysRoundBothCorners ? getMaxRadius() : getTopCornerRadius();
|
||||||
? mOutlineRadius : getCurrentBackgroundRadiusTop();
|
|
||||||
if (!mCustomOutline) {
|
if (!mCustomOutline) {
|
||||||
// The outline just needs to be shifted if we're translating the contents. Otherwise
|
// The outline just needs to be shifted if we're translating the contents. Otherwise
|
||||||
// it's already in the right place.
|
// it's already in the right place.
|
||||||
@@ -130,12 +108,11 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
|||||||
if (height == 0) {
|
if (height == 0) {
|
||||||
return EMPTY_PATH;
|
return EMPTY_PATH;
|
||||||
}
|
}
|
||||||
float bottomRoundness = mAlwaysRoundBothCorners
|
float bottomRoundness = mAlwaysRoundBothCorners ? getMaxRadius() : getBottomCornerRadius();
|
||||||
? mOutlineRadius : getCurrentBackgroundRadiusBottom();
|
|
||||||
if (topRoundness + bottomRoundness > height) {
|
if (topRoundness + bottomRoundness > height) {
|
||||||
float overShoot = topRoundness + bottomRoundness - height;
|
float overShoot = topRoundness + bottomRoundness - height;
|
||||||
float currentTopRoundness = getCurrentTopRoundness();
|
float currentTopRoundness = getTopRoundness();
|
||||||
float currentBottomRoundness = getCurrentBottomRoundness();
|
float currentBottomRoundness = getBottomRoundness();
|
||||||
topRoundness -= overShoot * currentTopRoundness
|
topRoundness -= overShoot * currentTopRoundness
|
||||||
/ (currentTopRoundness + currentBottomRoundness);
|
/ (currentTopRoundness + currentBottomRoundness);
|
||||||
bottomRoundness -= overShoot * currentBottomRoundness
|
bottomRoundness -= overShoot * currentBottomRoundness
|
||||||
@@ -145,8 +122,18 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
|||||||
return mTmpPath;
|
return mTmpPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getRoundedRectPath(int left, int top, int right, int bottom,
|
/**
|
||||||
float topRoundness, float bottomRoundness, Path outPath) {
|
* Add a round rect in {@code outPath}
|
||||||
|
* @param outPath destination path
|
||||||
|
*/
|
||||||
|
public void getRoundedRectPath(
|
||||||
|
int left,
|
||||||
|
int top,
|
||||||
|
int right,
|
||||||
|
int bottom,
|
||||||
|
float topRoundness,
|
||||||
|
float bottomRoundness,
|
||||||
|
Path outPath) {
|
||||||
outPath.reset();
|
outPath.reset();
|
||||||
mTmpCornerRadii[0] = topRoundness;
|
mTmpCornerRadii[0] = topRoundness;
|
||||||
mTmpCornerRadii[1] = topRoundness;
|
mTmpCornerRadii[1] = topRoundness;
|
||||||
@@ -168,15 +155,28 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||||
canvas.save();
|
canvas.save();
|
||||||
|
Path clipPath = null;
|
||||||
|
Path childClipPath = null;
|
||||||
if (childNeedsClipping(child)) {
|
if (childNeedsClipping(child)) {
|
||||||
Path clipPath = getCustomClipPath(child);
|
clipPath = getCustomClipPath(child);
|
||||||
if (clipPath == null) {
|
if (clipPath == null) {
|
||||||
clipPath = getClipPath(false /* ignoreTranslation */);
|
clipPath = getClipPath(false /* ignoreTranslation */);
|
||||||
}
|
}
|
||||||
|
// If the notification uses "RowTranslationX" as dismiss behavior, we should clip the
|
||||||
|
// children instead.
|
||||||
|
if (mDismissUsingRowTranslationX && child instanceof NotificationChildrenContainer) {
|
||||||
|
childClipPath = clipPath;
|
||||||
|
clipPath = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child instanceof NotificationChildrenContainer) {
|
||||||
|
((NotificationChildrenContainer) child).setChildClipPath(childClipPath);
|
||||||
|
}
|
||||||
if (clipPath != null) {
|
if (clipPath != null) {
|
||||||
canvas.clipPath(clipPath);
|
canvas.clipPath(clipPath);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
boolean result = super.drawChild(canvas, child, drawingTime);
|
boolean result = super.drawChild(canvas, child, drawingTime);
|
||||||
canvas.restore();
|
canvas.restore();
|
||||||
return result;
|
return result;
|
||||||
@@ -207,73 +207,21 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
|||||||
|
|
||||||
private void initDimens() {
|
private void initDimens() {
|
||||||
Resources res = getResources();
|
Resources res = getResources();
|
||||||
mOutlineRadius = res.getDimension(R.dimen.notification_shadow_radius);
|
|
||||||
mAlwaysRoundBothCorners = res.getBoolean(R.bool.config_clipNotificationsToOutline);
|
mAlwaysRoundBothCorners = res.getBoolean(R.bool.config_clipNotificationsToOutline);
|
||||||
if (!mAlwaysRoundBothCorners) {
|
float maxRadius;
|
||||||
mOutlineRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius);
|
if (mAlwaysRoundBothCorners) {
|
||||||
|
maxRadius = res.getDimension(R.dimen.notification_shadow_radius);
|
||||||
|
} else {
|
||||||
|
maxRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius);
|
||||||
}
|
}
|
||||||
|
mRoundableState = new RoundableState(this, this, maxRadius);
|
||||||
setClipToOutline(mAlwaysRoundBothCorners);
|
setClipToOutline(mAlwaysRoundBothCorners);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setTopRoundness(float topRoundness, boolean animate) {
|
public void applyRoundness() {
|
||||||
if (mTopRoundness != topRoundness) {
|
|
||||||
float diff = Math.abs(topRoundness - mTopRoundness);
|
|
||||||
mTopRoundness = topRoundness;
|
|
||||||
boolean shouldAnimate = animate;
|
|
||||||
if (PropertyAnimator.isAnimating(this, TOP_ROUNDNESS) && diff > 0.5f) {
|
|
||||||
// Fail safe:
|
|
||||||
// when we've been animating previously and we're now getting an update in the
|
|
||||||
// other direction, make sure to animate it too, otherwise, the localized updating
|
|
||||||
// may make the start larger than 1.0.
|
|
||||||
shouldAnimate = true;
|
|
||||||
}
|
|
||||||
PropertyAnimator.setProperty(this, TOP_ROUNDNESS, topRoundness,
|
|
||||||
ROUNDNESS_PROPERTIES, shouldAnimate);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void applyRoundness() {
|
|
||||||
invalidateOutline();
|
invalidateOutline();
|
||||||
invalidate();
|
super.applyRoundness();
|
||||||
}
|
|
||||||
|
|
||||||
public float getCurrentBackgroundRadiusTop() {
|
|
||||||
return getCurrentTopRoundness() * mOutlineRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getCurrentTopRoundness() {
|
|
||||||
return mCurrentTopRoundness;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getCurrentBottomRoundness() {
|
|
||||||
return mCurrentBottomRoundness;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getCurrentBackgroundRadiusBottom() {
|
|
||||||
return getCurrentBottomRoundness() * mOutlineRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean setBottomRoundness(float bottomRoundness, boolean animate) {
|
|
||||||
if (mBottomRoundness != bottomRoundness) {
|
|
||||||
float diff = Math.abs(bottomRoundness - mBottomRoundness);
|
|
||||||
mBottomRoundness = bottomRoundness;
|
|
||||||
boolean shouldAnimate = animate;
|
|
||||||
if (PropertyAnimator.isAnimating(this, BOTTOM_ROUNDNESS) && diff > 0.5f) {
|
|
||||||
// Fail safe:
|
|
||||||
// when we've been animating previously and we're now getting an update in the
|
|
||||||
// other direction, make sure to animate it too, otherwise, the localized updating
|
|
||||||
// may make the start larger than 1.0.
|
|
||||||
shouldAnimate = true;
|
|
||||||
}
|
|
||||||
PropertyAnimator.setProperty(this, BOTTOM_ROUNDNESS, bottomRoundness,
|
|
||||||
ROUNDNESS_PROPERTIES, shouldAnimate);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setBackgroundTop(int backgroundTop) {
|
protected void setBackgroundTop(int backgroundTop) {
|
||||||
@@ -283,16 +231,6 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTopRoundnessInternal(float topRoundness) {
|
|
||||||
mCurrentTopRoundness = topRoundness;
|
|
||||||
applyRoundness();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setBottomRoundnessInternal(float bottomRoundness) {
|
|
||||||
mCurrentBottomRoundness = bottomRoundness;
|
|
||||||
applyRoundness();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDensityOrFontScaleChanged() {
|
public void onDensityOrFontScaleChanged() {
|
||||||
initDimens();
|
initDimens();
|
||||||
applyRoundness();
|
applyRoundness();
|
||||||
@@ -348,6 +286,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the dismiss behavior of the view.
|
* Set the dismiss behavior of the view.
|
||||||
|
*
|
||||||
* @param usingRowTranslationX {@code true} if the view should translate using regular
|
* @param usingRowTranslationX {@code true} if the view should translate using regular
|
||||||
* translationX, otherwise the contents will be
|
* translationX, otherwise the contents will be
|
||||||
* translated.
|
* translated.
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ import com.android.systemui.Dumpable;
|
|||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.animation.Interpolators;
|
import com.android.systemui.animation.Interpolators;
|
||||||
import com.android.systemui.statusbar.StatusBarIconView;
|
import com.android.systemui.statusbar.StatusBarIconView;
|
||||||
|
import com.android.systemui.statusbar.notification.Roundable;
|
||||||
|
import com.android.systemui.statusbar.notification.RoundableState;
|
||||||
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
|
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
|
||||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
||||||
import com.android.systemui.util.DumpUtilsKt;
|
import com.android.systemui.util.DumpUtilsKt;
|
||||||
@@ -47,9 +49,10 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* An abstract view for expandable views.
|
* An abstract view for expandable views.
|
||||||
*/
|
*/
|
||||||
public abstract class ExpandableView extends FrameLayout implements Dumpable {
|
public abstract class ExpandableView extends FrameLayout implements Dumpable, Roundable {
|
||||||
private static final String TAG = "ExpandableView";
|
private static final String TAG = "ExpandableView";
|
||||||
|
|
||||||
|
private RoundableState mRoundableState = null;
|
||||||
protected OnHeightChangedListener mOnHeightChangedListener;
|
protected OnHeightChangedListener mOnHeightChangedListener;
|
||||||
private int mActualHeight;
|
private int mActualHeight;
|
||||||
protected int mClipTopAmount;
|
protected int mClipTopAmount;
|
||||||
@@ -78,6 +81,14 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
|
|||||||
initDimens();
|
initDimens();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RoundableState getRoundableState() {
|
||||||
|
if (mRoundableState == null) {
|
||||||
|
mRoundableState = new RoundableState(this, this, 0f);
|
||||||
|
}
|
||||||
|
return mRoundableState;
|
||||||
|
}
|
||||||
|
|
||||||
private void initDimens() {
|
private void initDimens() {
|
||||||
mContentShift = getResources().getDimensionPixelSize(
|
mContentShift = getResources().getDimensionPixelSize(
|
||||||
R.dimen.shelf_transform_content_shift);
|
R.dimen.shelf_transform_content_shift);
|
||||||
@@ -440,8 +451,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
|
|||||||
int top = getClipTopAmount();
|
int top = getClipTopAmount();
|
||||||
int bottom = Math.max(Math.max(getActualHeight() + getExtraBottomPadding()
|
int bottom = Math.max(Math.max(getActualHeight() + getExtraBottomPadding()
|
||||||
- mClipBottomAmount, top), mMinimumHeightForClipping);
|
- mClipBottomAmount, top), mMinimumHeightForClipping);
|
||||||
int halfExtraWidth = (int) (mExtraWidthForClipping / 2.0f);
|
mClipRect.set(Integer.MIN_VALUE, top, Integer.MAX_VALUE, bottom);
|
||||||
mClipRect.set(-halfExtraWidth, top, getWidth() + halfExtraWidth, bottom);
|
|
||||||
setClipBounds(mClipRect);
|
setClipBounds(mClipRect);
|
||||||
} else {
|
} else {
|
||||||
setClipBounds(null);
|
setClipBounds(null);
|
||||||
@@ -455,7 +465,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
|
|||||||
|
|
||||||
public void setExtraWidthForClipping(float extraWidthForClipping) {
|
public void setExtraWidthForClipping(float extraWidthForClipping) {
|
||||||
mExtraWidthForClipping = extraWidthForClipping;
|
mExtraWidthForClipping = extraWidthForClipping;
|
||||||
updateClipping();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getHeaderVisibleAmount() {
|
public float getHeaderVisibleAmount() {
|
||||||
@@ -844,22 +853,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
|
|||||||
return mFirstInSection;
|
return mFirstInSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the topRoundness of this view.
|
|
||||||
* @return Whether the roundness was changed.
|
|
||||||
*/
|
|
||||||
public boolean setTopRoundness(float topRoundness, boolean animate) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the bottom roundness of this view.
|
|
||||||
* @return Whether the roundness was changed.
|
|
||||||
*/
|
|
||||||
public boolean setBottomRoundness(float bottomRoundness, boolean animate) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHeadsUpHeightWithoutHeader() {
|
public int getHeadsUpHeightWithoutHeader() {
|
||||||
return getHeight();
|
return getHeight();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,12 +35,15 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
import com.android.internal.widget.CachingIconView;
|
import com.android.internal.widget.CachingIconView;
|
||||||
import com.android.internal.widget.NotificationExpandButton;
|
import com.android.internal.widget.NotificationExpandButton;
|
||||||
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.animation.Interpolators;
|
import com.android.systemui.animation.Interpolators;
|
||||||
import com.android.systemui.statusbar.TransformableView;
|
import com.android.systemui.statusbar.TransformableView;
|
||||||
import com.android.systemui.statusbar.ViewTransformationHelper;
|
import com.android.systemui.statusbar.ViewTransformationHelper;
|
||||||
import com.android.systemui.statusbar.notification.CustomInterpolatorTransformation;
|
import com.android.systemui.statusbar.notification.CustomInterpolatorTransformation;
|
||||||
import com.android.systemui.statusbar.notification.FeedbackIcon;
|
import com.android.systemui.statusbar.notification.FeedbackIcon;
|
||||||
import com.android.systemui.statusbar.notification.ImageTransformState;
|
import com.android.systemui.statusbar.notification.ImageTransformState;
|
||||||
|
import com.android.systemui.statusbar.notification.Roundable;
|
||||||
|
import com.android.systemui.statusbar.notification.RoundableState;
|
||||||
import com.android.systemui.statusbar.notification.TransformState;
|
import com.android.systemui.statusbar.notification.TransformState;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||||
|
|
||||||
@@ -49,13 +52,12 @@ import java.util.Stack;
|
|||||||
/**
|
/**
|
||||||
* Wraps a notification view which may or may not include a header.
|
* Wraps a notification view which may or may not include a header.
|
||||||
*/
|
*/
|
||||||
public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
|
public class NotificationHeaderViewWrapper extends NotificationViewWrapper implements Roundable {
|
||||||
|
|
||||||
|
private final RoundableState mRoundableState;
|
||||||
private static final Interpolator LOW_PRIORITY_HEADER_CLOSE
|
private static final Interpolator LOW_PRIORITY_HEADER_CLOSE
|
||||||
= new PathInterpolator(0.4f, 0f, 0.7f, 1f);
|
= new PathInterpolator(0.4f, 0f, 0.7f, 1f);
|
||||||
|
|
||||||
protected final ViewTransformationHelper mTransformationHelper;
|
protected final ViewTransformationHelper mTransformationHelper;
|
||||||
|
|
||||||
private CachingIconView mIcon;
|
private CachingIconView mIcon;
|
||||||
private NotificationExpandButton mExpandButton;
|
private NotificationExpandButton mExpandButton;
|
||||||
private View mAltExpandTarget;
|
private View mAltExpandTarget;
|
||||||
@@ -67,12 +69,16 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
|
|||||||
private ImageView mWorkProfileImage;
|
private ImageView mWorkProfileImage;
|
||||||
private View mAudiblyAlertedIcon;
|
private View mAudiblyAlertedIcon;
|
||||||
private View mFeedbackIcon;
|
private View mFeedbackIcon;
|
||||||
|
|
||||||
private boolean mIsLowPriority;
|
private boolean mIsLowPriority;
|
||||||
private boolean mTransformLowPriorityTitle;
|
private boolean mTransformLowPriorityTitle;
|
||||||
|
|
||||||
protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
|
protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
|
||||||
super(ctx, view, row);
|
super(ctx, view, row);
|
||||||
|
mRoundableState = new RoundableState(
|
||||||
|
mView,
|
||||||
|
this,
|
||||||
|
ctx.getResources().getDimension(R.dimen.notification_corner_radius)
|
||||||
|
);
|
||||||
mTransformationHelper = new ViewTransformationHelper();
|
mTransformationHelper = new ViewTransformationHelper();
|
||||||
|
|
||||||
// we want to avoid that the header clashes with the other text when transforming
|
// we want to avoid that the header clashes with the other text when transforming
|
||||||
@@ -81,7 +87,8 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
|
|||||||
new CustomInterpolatorTransformation(TRANSFORMING_VIEW_TITLE) {
|
new CustomInterpolatorTransformation(TRANSFORMING_VIEW_TITLE) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Interpolator getCustomInterpolator(int interpolationType,
|
public Interpolator getCustomInterpolator(
|
||||||
|
int interpolationType,
|
||||||
boolean isFrom) {
|
boolean isFrom) {
|
||||||
boolean isLowPriority = mView instanceof NotificationHeaderView;
|
boolean isLowPriority = mView instanceof NotificationHeaderView;
|
||||||
if (interpolationType == TRANSFORM_Y) {
|
if (interpolationType == TRANSFORM_Y) {
|
||||||
@@ -99,11 +106,17 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
|
|||||||
protected boolean hasCustomTransformation() {
|
protected boolean hasCustomTransformation() {
|
||||||
return mIsLowPriority && mTransformLowPriorityTitle;
|
return mIsLowPriority && mTransformLowPriorityTitle;
|
||||||
}
|
}
|
||||||
}, TRANSFORMING_VIEW_TITLE);
|
},
|
||||||
|
TRANSFORMING_VIEW_TITLE);
|
||||||
resolveHeaderViews();
|
resolveHeaderViews();
|
||||||
addFeedbackOnClickListener(row);
|
addFeedbackOnClickListener(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RoundableState getRoundableState() {
|
||||||
|
return mRoundableState;
|
||||||
|
}
|
||||||
|
|
||||||
protected void resolveHeaderViews() {
|
protected void resolveHeaderViews() {
|
||||||
mIcon = mView.findViewById(com.android.internal.R.id.icon);
|
mIcon = mView.findViewById(com.android.internal.R.id.icon);
|
||||||
mHeaderText = mView.findViewById(com.android.internal.R.id.header_text);
|
mHeaderText = mView.findViewById(com.android.internal.R.id.header_text);
|
||||||
@@ -128,7 +141,9 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Shows the given feedback icon, or hides the icon if null. */
|
/**
|
||||||
|
* Shows the given feedback icon, or hides the icon if null.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
|
public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
|
||||||
if (mFeedbackIcon != null) {
|
if (mFeedbackIcon != null) {
|
||||||
@@ -193,7 +208,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
|
|||||||
// its animation
|
// its animation
|
||||||
&& child.getId() != com.android.internal.R.id.conversation_icon_badge_ring) {
|
&& child.getId() != com.android.internal.R.id.conversation_icon_badge_ring) {
|
||||||
((ImageView) child).setCropToPadding(true);
|
((ImageView) child).setCropToPadding(true);
|
||||||
} else if (child instanceof ViewGroup){
|
} else if (child instanceof ViewGroup) {
|
||||||
ViewGroup group = (ViewGroup) child;
|
ViewGroup group = (ViewGroup) child;
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
for (int i = 0; i < group.getChildCount(); i++) {
|
||||||
stack.push(group.getChildAt(i));
|
stack.push(group.getChildAt(i));
|
||||||
@@ -215,7 +230,9 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateExpandability(boolean expandable, View.OnClickListener onClickListener,
|
public void updateExpandability(
|
||||||
|
boolean expandable,
|
||||||
|
View.OnClickListener onClickListener,
|
||||||
boolean requestLayout) {
|
boolean requestLayout) {
|
||||||
mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
|
mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
|
||||||
mExpandButton.setOnClickListener(expandable ? onClickListener : null);
|
mExpandButton.setOnClickListener(expandable ? onClickListener : null);
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ import android.content.Context;
|
|||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.Path.Direction;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@@ -33,6 +36,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -43,10 +47,14 @@ import com.android.systemui.statusbar.NotificationGroupingUtil;
|
|||||||
import com.android.systemui.statusbar.notification.FeedbackIcon;
|
import com.android.systemui.statusbar.notification.FeedbackIcon;
|
||||||
import com.android.systemui.statusbar.notification.NotificationFadeAware;
|
import com.android.systemui.statusbar.notification.NotificationFadeAware;
|
||||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||||
|
import com.android.systemui.statusbar.notification.Roundable;
|
||||||
|
import com.android.systemui.statusbar.notification.RoundableState;
|
||||||
|
import com.android.systemui.statusbar.notification.SourceType;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
||||||
import com.android.systemui.statusbar.notification.row.HybridGroupManager;
|
import com.android.systemui.statusbar.notification.row.HybridGroupManager;
|
||||||
import com.android.systemui.statusbar.notification.row.HybridNotificationView;
|
import com.android.systemui.statusbar.notification.row.HybridNotificationView;
|
||||||
|
import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
|
||||||
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
|
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -56,7 +64,7 @@ import java.util.List;
|
|||||||
* A container containing child notifications
|
* A container containing child notifications
|
||||||
*/
|
*/
|
||||||
public class NotificationChildrenContainer extends ViewGroup
|
public class NotificationChildrenContainer extends ViewGroup
|
||||||
implements NotificationFadeAware {
|
implements NotificationFadeAware, Roundable {
|
||||||
|
|
||||||
private static final String TAG = "NotificationChildrenContainer";
|
private static final String TAG = "NotificationChildrenContainer";
|
||||||
|
|
||||||
@@ -100,9 +108,9 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
private boolean mEnableShadowOnChildNotifications;
|
private boolean mEnableShadowOnChildNotifications;
|
||||||
|
|
||||||
private NotificationHeaderView mNotificationHeader;
|
private NotificationHeaderView mNotificationHeader;
|
||||||
private NotificationViewWrapper mNotificationHeaderWrapper;
|
private NotificationHeaderViewWrapper mNotificationHeaderWrapper;
|
||||||
private NotificationHeaderView mNotificationHeaderLowPriority;
|
private NotificationHeaderView mNotificationHeaderLowPriority;
|
||||||
private NotificationViewWrapper mNotificationHeaderWrapperLowPriority;
|
private NotificationHeaderViewWrapper mNotificationHeaderWrapperLowPriority;
|
||||||
private NotificationGroupingUtil mGroupingUtil;
|
private NotificationGroupingUtil mGroupingUtil;
|
||||||
private ViewState mHeaderViewState;
|
private ViewState mHeaderViewState;
|
||||||
private int mClipBottomAmount;
|
private int mClipBottomAmount;
|
||||||
@@ -110,7 +118,8 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
private OnClickListener mHeaderClickListener;
|
private OnClickListener mHeaderClickListener;
|
||||||
private ViewGroup mCurrentHeader;
|
private ViewGroup mCurrentHeader;
|
||||||
private boolean mIsConversation;
|
private boolean mIsConversation;
|
||||||
|
private Path mChildClipPath = null;
|
||||||
|
private final Path mHeaderPath = new Path();
|
||||||
private boolean mShowGroupCountInExpander;
|
private boolean mShowGroupCountInExpander;
|
||||||
private boolean mShowDividersWhenExpanded;
|
private boolean mShowDividersWhenExpanded;
|
||||||
private boolean mHideDividersDuringExpand;
|
private boolean mHideDividersDuringExpand;
|
||||||
@@ -119,6 +128,8 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
private float mHeaderVisibleAmount = 1.0f;
|
private float mHeaderVisibleAmount = 1.0f;
|
||||||
private int mUntruncatedChildCount;
|
private int mUntruncatedChildCount;
|
||||||
private boolean mContainingNotificationIsFaded = false;
|
private boolean mContainingNotificationIsFaded = false;
|
||||||
|
private RoundableState mRoundableState;
|
||||||
|
private boolean mIsNotificationGroupCornerEnabled;
|
||||||
|
|
||||||
public NotificationChildrenContainer(Context context) {
|
public NotificationChildrenContainer(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
@@ -132,10 +143,14 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
this(context, attrs, defStyleAttr, 0);
|
this(context, attrs, defStyleAttr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NotificationChildrenContainer(Context context, AttributeSet attrs, int defStyleAttr,
|
public NotificationChildrenContainer(
|
||||||
|
Context context,
|
||||||
|
AttributeSet attrs,
|
||||||
|
int defStyleAttr,
|
||||||
int defStyleRes) {
|
int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
mHybridGroupManager = new HybridGroupManager(getContext());
|
mHybridGroupManager = new HybridGroupManager(getContext());
|
||||||
|
mRoundableState = new RoundableState(this, this, 0f);
|
||||||
initDimens();
|
initDimens();
|
||||||
setClipChildren(false);
|
setClipChildren(false);
|
||||||
}
|
}
|
||||||
@@ -167,6 +182,12 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
mHybridGroupManager.initDimens();
|
mHybridGroupManager.initDimens();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RoundableState getRoundableState() {
|
||||||
|
return mRoundableState;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
int childCount =
|
int childCount =
|
||||||
@@ -347,8 +368,11 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
mNotificationHeader.findViewById(com.android.internal.R.id.expand_button)
|
mNotificationHeader.findViewById(com.android.internal.R.id.expand_button)
|
||||||
.setVisibility(VISIBLE);
|
.setVisibility(VISIBLE);
|
||||||
mNotificationHeader.setOnClickListener(mHeaderClickListener);
|
mNotificationHeader.setOnClickListener(mHeaderClickListener);
|
||||||
mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
|
mNotificationHeaderWrapper =
|
||||||
mNotificationHeader, mContainingNotification);
|
(NotificationHeaderViewWrapper) NotificationViewWrapper.wrap(
|
||||||
|
getContext(),
|
||||||
|
mNotificationHeader,
|
||||||
|
mContainingNotification);
|
||||||
addView(mNotificationHeader, 0);
|
addView(mNotificationHeader, 0);
|
||||||
invalidate();
|
invalidate();
|
||||||
} else {
|
} else {
|
||||||
@@ -381,8 +405,11 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
mNotificationHeaderLowPriority.findViewById(com.android.internal.R.id.expand_button)
|
mNotificationHeaderLowPriority.findViewById(com.android.internal.R.id.expand_button)
|
||||||
.setVisibility(VISIBLE);
|
.setVisibility(VISIBLE);
|
||||||
mNotificationHeaderLowPriority.setOnClickListener(mHeaderClickListener);
|
mNotificationHeaderLowPriority.setOnClickListener(mHeaderClickListener);
|
||||||
mNotificationHeaderWrapperLowPriority = NotificationViewWrapper.wrap(getContext(),
|
mNotificationHeaderWrapperLowPriority =
|
||||||
mNotificationHeaderLowPriority, mContainingNotification);
|
(NotificationHeaderViewWrapper) NotificationViewWrapper.wrap(
|
||||||
|
getContext(),
|
||||||
|
mNotificationHeaderLowPriority,
|
||||||
|
mContainingNotification);
|
||||||
addView(mNotificationHeaderLowPriority, 0);
|
addView(mNotificationHeaderLowPriority, 0);
|
||||||
invalidate();
|
invalidate();
|
||||||
} else {
|
} else {
|
||||||
@@ -461,7 +488,9 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
return mAttachedChildren;
|
return mAttachedChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** To be called any time the rows have been updated */
|
/**
|
||||||
|
* To be called any time the rows have been updated
|
||||||
|
*/
|
||||||
public void updateExpansionStates() {
|
public void updateExpansionStates() {
|
||||||
if (mChildrenExpanded || mUserLocked) {
|
if (mChildrenExpanded || mUserLocked) {
|
||||||
// we don't modify it the group is expanded or if we are expanding it
|
// we don't modify it the group is expanded or if we are expanding it
|
||||||
@@ -475,7 +504,6 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @return the intrinsic size of this children container, i.e the natural fully expanded state
|
* @return the intrinsic size of this children container, i.e the natural fully expanded state
|
||||||
*/
|
*/
|
||||||
public int getIntrinsicHeight() {
|
public int getIntrinsicHeight() {
|
||||||
@@ -539,6 +567,7 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the state of all its children based on a linear layout algorithm.
|
* Update the state of all its children based on a linear layout algorithm.
|
||||||
|
*
|
||||||
* @param parentState the state of the parent
|
* @param parentState the state of the parent
|
||||||
* @param ambientState the ambient state containing ambient information
|
* @param ambientState the ambient state containing ambient information
|
||||||
*/
|
*/
|
||||||
@@ -661,8 +690,11 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
* @param yPosition the yPosition of the view.
|
* @param yPosition the yPosition of the view.
|
||||||
* @return true if children after this one should be hidden.
|
* @return true if children after this one should be hidden.
|
||||||
*/
|
*/
|
||||||
private boolean updateChildStateForExpandedGroup(ExpandableNotificationRow child,
|
private boolean updateChildStateForExpandedGroup(
|
||||||
int parentHeight, ExpandableViewState childState, int yPosition) {
|
ExpandableNotificationRow child,
|
||||||
|
int parentHeight,
|
||||||
|
ExpandableViewState childState,
|
||||||
|
int yPosition) {
|
||||||
final int top = yPosition + child.getClipTopAmount();
|
final int top = yPosition + child.getClipTopAmount();
|
||||||
final int intrinsicHeight = child.getIntrinsicHeight();
|
final int intrinsicHeight = child.getIntrinsicHeight();
|
||||||
final int bottom = top + intrinsicHeight;
|
final int bottom = top + intrinsicHeight;
|
||||||
@@ -696,7 +728,9 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
|
return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Applies state to children. */
|
/**
|
||||||
|
* Applies state to children.
|
||||||
|
*/
|
||||||
public void applyState() {
|
public void applyState() {
|
||||||
int childCount = mAttachedChildren.size();
|
int childCount = mAttachedChildren.size();
|
||||||
ViewState tmpState = new ViewState();
|
ViewState tmpState = new ViewState();
|
||||||
@@ -768,17 +802,73 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||||
|
boolean isCanvasChanged = false;
|
||||||
|
|
||||||
|
Path clipPath = mChildClipPath;
|
||||||
|
if (clipPath != null) {
|
||||||
|
final float translation;
|
||||||
|
if (child instanceof ExpandableNotificationRow) {
|
||||||
|
ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) child;
|
||||||
|
translation = notificationRow.getTranslation();
|
||||||
|
} else {
|
||||||
|
translation = child.getTranslationX();
|
||||||
|
}
|
||||||
|
|
||||||
|
isCanvasChanged = true;
|
||||||
|
canvas.save();
|
||||||
|
if (mIsNotificationGroupCornerEnabled && translation != 0f) {
|
||||||
|
clipPath.offset(translation, 0f);
|
||||||
|
canvas.clipPath(clipPath);
|
||||||
|
clipPath.offset(-translation, 0f);
|
||||||
|
} else {
|
||||||
|
canvas.clipPath(clipPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child instanceof NotificationHeaderView
|
||||||
|
&& mNotificationHeaderWrapper.hasRoundedCorner()) {
|
||||||
|
float[] radii = mNotificationHeaderWrapper.getUpdatedRadii();
|
||||||
|
mHeaderPath.reset();
|
||||||
|
mHeaderPath.addRoundRect(
|
||||||
|
child.getLeft(),
|
||||||
|
child.getTop(),
|
||||||
|
child.getRight(),
|
||||||
|
child.getBottom(),
|
||||||
|
radii,
|
||||||
|
Direction.CW
|
||||||
|
);
|
||||||
|
if (!isCanvasChanged) {
|
||||||
|
isCanvasChanged = true;
|
||||||
|
canvas.save();
|
||||||
|
}
|
||||||
|
canvas.clipPath(mHeaderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCanvasChanged) {
|
||||||
|
boolean result = super.drawChild(canvas, child, drawingTime);
|
||||||
|
canvas.restore();
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
// If there have been no changes to the canvas we can proceed as usual
|
||||||
|
return super.drawChild(canvas, child, drawingTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called when the children expansion has changed and positions the children properly
|
* This is called when the children expansion has changed and positions the children properly
|
||||||
* for an appear animation.
|
* for an appear animation.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public void prepareExpansionChanged() {
|
public void prepareExpansionChanged() {
|
||||||
// TODO: do something that makes sense, like placing the invisible views correctly
|
// TODO: do something that makes sense, like placing the invisible views correctly
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Animate to a given state. */
|
/**
|
||||||
|
* Animate to a given state.
|
||||||
|
*/
|
||||||
public void startAnimationToState(AnimationProperties properties) {
|
public void startAnimationToState(AnimationProperties properties) {
|
||||||
int childCount = mAttachedChildren.size();
|
int childCount = mAttachedChildren.size();
|
||||||
ViewState tmpState = new ViewState();
|
ViewState tmpState = new ViewState();
|
||||||
@@ -1102,7 +1192,8 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
* Get the minimum Height for this group.
|
* Get the minimum Height for this group.
|
||||||
*
|
*
|
||||||
* @param maxAllowedVisibleChildren the number of children that should be visible
|
* @param maxAllowedVisibleChildren the number of children that should be visible
|
||||||
* @param likeHighPriority if the height should be calculated as if it were not low priority
|
* @param likeHighPriority if the height should be calculated as if it were not low
|
||||||
|
* priority
|
||||||
*/
|
*/
|
||||||
private int getMinHeight(int maxAllowedVisibleChildren, boolean likeHighPriority) {
|
private int getMinHeight(int maxAllowedVisibleChildren, boolean likeHighPriority) {
|
||||||
return getMinHeight(maxAllowedVisibleChildren, likeHighPriority, mCurrentHeaderTranslation);
|
return getMinHeight(maxAllowedVisibleChildren, likeHighPriority, mCurrentHeaderTranslation);
|
||||||
@@ -1112,10 +1203,13 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
* Get the minimum Height for this group.
|
* Get the minimum Height for this group.
|
||||||
*
|
*
|
||||||
* @param maxAllowedVisibleChildren the number of children that should be visible
|
* @param maxAllowedVisibleChildren the number of children that should be visible
|
||||||
* @param likeHighPriority if the height should be calculated as if it were not low priority
|
* @param likeHighPriority if the height should be calculated as if it were not low
|
||||||
|
* priority
|
||||||
* @param headerTranslation the translation amount of the header
|
* @param headerTranslation the translation amount of the header
|
||||||
*/
|
*/
|
||||||
private int getMinHeight(int maxAllowedVisibleChildren, boolean likeHighPriority,
|
private int getMinHeight(
|
||||||
|
int maxAllowedVisibleChildren,
|
||||||
|
boolean likeHighPriority,
|
||||||
int headerTranslation) {
|
int headerTranslation) {
|
||||||
if (!likeHighPriority && showingAsLowPriority()) {
|
if (!likeHighPriority && showingAsLowPriority()) {
|
||||||
if (mNotificationHeaderLowPriority == null) {
|
if (mNotificationHeaderLowPriority == null) {
|
||||||
@@ -1274,16 +1368,19 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
return mUserLocked;
|
return mUserLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentBottomRoundness(float currentBottomRoundness) {
|
@Override
|
||||||
|
public void applyRoundness() {
|
||||||
|
Roundable.super.applyRoundness();
|
||||||
boolean last = true;
|
boolean last = true;
|
||||||
for (int i = mAttachedChildren.size() - 1; i >= 0; i--) {
|
for (int i = mAttachedChildren.size() - 1; i >= 0; i--) {
|
||||||
ExpandableNotificationRow child = mAttachedChildren.get(i);
|
ExpandableNotificationRow child = mAttachedChildren.get(i);
|
||||||
if (child.getVisibility() == View.GONE) {
|
if (child.getVisibility() == View.GONE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
float bottomRoundness = last ? currentBottomRoundness : 0.0f;
|
child.requestBottomRoundness(
|
||||||
child.setBottomRoundness(bottomRoundness, isShown() /* animate */);
|
last ? getBottomRoundness() : 0f,
|
||||||
child.setTopRoundness(0.0f, false /* animate */);
|
/* animate = */ isShown(),
|
||||||
|
SourceType.DefaultValue);
|
||||||
last = false;
|
last = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1293,7 +1390,9 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
mCurrentHeaderTranslation = (int) ((1.0f - headerVisibleAmount) * mTranslationForHeader);
|
mCurrentHeaderTranslation = (int) ((1.0f - headerVisibleAmount) * mTranslationForHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Shows the given feedback icon, or hides the icon if null. */
|
/**
|
||||||
|
* Shows the given feedback icon, or hides the icon if null.
|
||||||
|
*/
|
||||||
public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
|
public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
|
||||||
if (mNotificationHeaderWrapper != null) {
|
if (mNotificationHeaderWrapper != null) {
|
||||||
mNotificationHeaderWrapper.setFeedbackIcon(icon);
|
mNotificationHeaderWrapper.setFeedbackIcon(icon);
|
||||||
@@ -1325,4 +1424,26 @@ public class NotificationChildrenContainer extends ViewGroup
|
|||||||
child.setNotificationFaded(faded);
|
child.setNotificationFaded(faded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow to define a path the clip the children in #drawChild()
|
||||||
|
*
|
||||||
|
* @param childClipPath path used to clip the children
|
||||||
|
*/
|
||||||
|
public void setChildClipPath(@Nullable Path childClipPath) {
|
||||||
|
mChildClipPath = childClipPath;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationHeaderViewWrapper getNotificationHeaderWrapper() {
|
||||||
|
return mNotificationHeaderWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the support for rounded corner in notification group
|
||||||
|
* @param enabled true if is supported
|
||||||
|
*/
|
||||||
|
public void enableNotificationGroupCorner(boolean enabled) {
|
||||||
|
mIsNotificationGroupCornerEnabled = enabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import com.android.systemui.R;
|
|||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
||||||
|
import com.android.systemui.statusbar.notification.Roundable;
|
||||||
|
import com.android.systemui.statusbar.notification.SourceType;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.notification.logging.NotificationRoundnessLogger;
|
import com.android.systemui.statusbar.notification.logging.NotificationRoundnessLogger;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||||
@@ -59,8 +61,8 @@ public class NotificationRoundnessManager implements Dumpable {
|
|||||||
private boolean mIsClearAllInProgress;
|
private boolean mIsClearAllInProgress;
|
||||||
|
|
||||||
private ExpandableView mSwipedView = null;
|
private ExpandableView mSwipedView = null;
|
||||||
private ExpandableView mViewBeforeSwipedView = null;
|
private Roundable mViewBeforeSwipedView = null;
|
||||||
private ExpandableView mViewAfterSwipedView = null;
|
private Roundable mViewAfterSwipedView = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
NotificationRoundnessManager(
|
NotificationRoundnessManager(
|
||||||
@@ -105,7 +107,8 @@ public class NotificationRoundnessManager implements Dumpable {
|
|||||||
|| expandableView == mViewAfterSwipedView);
|
|| expandableView == mViewAfterSwipedView);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean updateViewWithoutCallback(ExpandableView view,
|
boolean updateViewWithoutCallback(
|
||||||
|
ExpandableView view,
|
||||||
boolean animate) {
|
boolean animate) {
|
||||||
if (view == null
|
if (view == null
|
||||||
|| view == mViewBeforeSwipedView
|
|| view == mViewBeforeSwipedView
|
||||||
@@ -113,11 +116,15 @@ public class NotificationRoundnessManager implements Dumpable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final float topRoundness = getRoundnessFraction(view, true /* top */);
|
final boolean isTopChanged = view.requestTopRoundness(
|
||||||
final float bottomRoundness = getRoundnessFraction(view, false /* top */);
|
getRoundnessDefaultValue(view, true /* top */),
|
||||||
|
animate,
|
||||||
|
SourceType.DefaultValue);
|
||||||
|
|
||||||
final boolean topChanged = view.setTopRoundness(topRoundness, animate);
|
final boolean isBottomChanged = view.requestBottomRoundness(
|
||||||
final boolean bottomChanged = view.setBottomRoundness(bottomRoundness, animate);
|
getRoundnessDefaultValue(view, /* top = */ false),
|
||||||
|
animate,
|
||||||
|
SourceType.DefaultValue);
|
||||||
|
|
||||||
final boolean isFirstInSection = isFirstInSection(view);
|
final boolean isFirstInSection = isFirstInSection(view);
|
||||||
final boolean isLastInSection = isLastInSection(view);
|
final boolean isLastInSection = isLastInSection(view);
|
||||||
@@ -126,9 +133,9 @@ public class NotificationRoundnessManager implements Dumpable {
|
|||||||
view.setLastInSection(isLastInSection);
|
view.setLastInSection(isLastInSection);
|
||||||
|
|
||||||
mNotifLogger.onCornersUpdated(view, isFirstInSection,
|
mNotifLogger.onCornersUpdated(view, isFirstInSection,
|
||||||
isLastInSection, topChanged, bottomChanged);
|
isLastInSection, isTopChanged, isBottomChanged);
|
||||||
|
|
||||||
return (isFirstInSection || isLastInSection) && (topChanged || bottomChanged);
|
return (isFirstInSection || isLastInSection) && (isTopChanged || isBottomChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFirstInSection(ExpandableView view) {
|
private boolean isFirstInSection(ExpandableView view) {
|
||||||
@@ -150,42 +157,46 @@ public class NotificationRoundnessManager implements Dumpable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setViewsAffectedBySwipe(
|
void setViewsAffectedBySwipe(
|
||||||
ExpandableView viewBefore,
|
Roundable viewBefore,
|
||||||
ExpandableView viewSwiped,
|
ExpandableView viewSwiped,
|
||||||
ExpandableView viewAfter) {
|
Roundable viewAfter) {
|
||||||
final boolean animate = true;
|
final boolean animate = true;
|
||||||
|
final SourceType source = SourceType.OnDismissAnimation;
|
||||||
|
|
||||||
|
// This method requires you to change the roundness of the current View targets and reset
|
||||||
|
// the roundness of the old View targets (if any) to 0f.
|
||||||
|
// To avoid conflicts, it generates a set of old Views and removes the current Views
|
||||||
|
// from this set.
|
||||||
|
HashSet<Roundable> oldViews = new HashSet<>();
|
||||||
|
if (mViewBeforeSwipedView != null) oldViews.add(mViewBeforeSwipedView);
|
||||||
|
if (mSwipedView != null) oldViews.add(mSwipedView);
|
||||||
|
if (mViewAfterSwipedView != null) oldViews.add(mViewAfterSwipedView);
|
||||||
|
|
||||||
ExpandableView oldViewBefore = mViewBeforeSwipedView;
|
|
||||||
mViewBeforeSwipedView = viewBefore;
|
mViewBeforeSwipedView = viewBefore;
|
||||||
if (oldViewBefore != null) {
|
|
||||||
final float bottomRoundness = getRoundnessFraction(oldViewBefore, false /* top */);
|
|
||||||
oldViewBefore.setBottomRoundness(bottomRoundness, animate);
|
|
||||||
}
|
|
||||||
if (viewBefore != null) {
|
if (viewBefore != null) {
|
||||||
viewBefore.setBottomRoundness(1f, animate);
|
oldViews.remove(viewBefore);
|
||||||
|
viewBefore.requestTopRoundness(0f, animate, source);
|
||||||
|
viewBefore.requestBottomRoundness(1f, animate, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpandableView oldSwipedview = mSwipedView;
|
|
||||||
mSwipedView = viewSwiped;
|
mSwipedView = viewSwiped;
|
||||||
if (oldSwipedview != null) {
|
|
||||||
final float bottomRoundness = getRoundnessFraction(oldSwipedview, false /* top */);
|
|
||||||
final float topRoundness = getRoundnessFraction(oldSwipedview, true /* top */);
|
|
||||||
oldSwipedview.setTopRoundness(topRoundness, animate);
|
|
||||||
oldSwipedview.setBottomRoundness(bottomRoundness, animate);
|
|
||||||
}
|
|
||||||
if (viewSwiped != null) {
|
if (viewSwiped != null) {
|
||||||
viewSwiped.setTopRoundness(1f, animate);
|
oldViews.remove(viewSwiped);
|
||||||
viewSwiped.setBottomRoundness(1f, animate);
|
viewSwiped.requestTopRoundness(1f, animate, source);
|
||||||
|
viewSwiped.requestBottomRoundness(1f, animate, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpandableView oldViewAfter = mViewAfterSwipedView;
|
|
||||||
mViewAfterSwipedView = viewAfter;
|
mViewAfterSwipedView = viewAfter;
|
||||||
if (oldViewAfter != null) {
|
|
||||||
final float topRoundness = getRoundnessFraction(oldViewAfter, true /* top */);
|
|
||||||
oldViewAfter.setTopRoundness(topRoundness, animate);
|
|
||||||
}
|
|
||||||
if (viewAfter != null) {
|
if (viewAfter != null) {
|
||||||
viewAfter.setTopRoundness(1f, animate);
|
oldViews.remove(viewAfter);
|
||||||
|
viewAfter.requestTopRoundness(1f, animate, source);
|
||||||
|
viewAfter.requestBottomRoundness(0f, animate, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
// After setting the current Views, reset the views that are still present in the set.
|
||||||
|
for (Roundable oldView : oldViews) {
|
||||||
|
oldView.requestTopRoundness(0f, animate, source);
|
||||||
|
oldView.requestBottomRoundness(0f, animate, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +204,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
|||||||
mIsClearAllInProgress = isClearingAll;
|
mIsClearAllInProgress = isClearingAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getRoundnessFraction(ExpandableView view, boolean top) {
|
private float getRoundnessDefaultValue(Roundable view, boolean top) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
@@ -207,29 +218,36 @@ public class NotificationRoundnessManager implements Dumpable {
|
|||||||
&& mIsClearAllInProgress) {
|
&& mIsClearAllInProgress) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
if ((view.isPinned()
|
if (view instanceof ExpandableView) {
|
||||||
|| (view.isHeadsUpAnimatingAway()) && !mExpanded)) {
|
ExpandableView expandableView = (ExpandableView) view;
|
||||||
|
if ((expandableView.isPinned()
|
||||||
|
|| (expandableView.isHeadsUpAnimatingAway()) && !mExpanded)) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
if (isFirstInSection(view) && top) {
|
if (isFirstInSection(expandableView) && top) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
if (isLastInSection(view) && !top) {
|
if (isLastInSection(expandableView) && !top) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view == mTrackedHeadsUp) {
|
if (view == mTrackedHeadsUp) {
|
||||||
// If we're pushing up on a headsup the appear fraction is < 0 and it needs to still be
|
// If we're pushing up on a headsup the appear fraction is < 0 and it needs to
|
||||||
// rounded.
|
// still be rounded.
|
||||||
return MathUtils.saturate(1.0f - mAppearFraction);
|
return MathUtils.saturate(1.0f - mAppearFraction);
|
||||||
}
|
}
|
||||||
if (view.showingPulsing() && mRoundForPulsingViews) {
|
if (expandableView.showingPulsing() && mRoundForPulsingViews) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
final Resources resources = view.getResources();
|
if (expandableView.isChildInGroup()) {
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
final Resources resources = expandableView.getResources();
|
||||||
return resources.getDimension(R.dimen.notification_corner_radius_small)
|
return resources.getDimension(R.dimen.notification_corner_radius_small)
|
||||||
/ resources.getDimension(R.dimen.notification_corner_radius);
|
/ resources.getDimension(R.dimen.notification_corner_radius);
|
||||||
}
|
}
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
public void setExpanded(float expandedHeight, float appearFraction) {
|
public void setExpanded(float expandedHeight, float appearFraction) {
|
||||||
mExpanded = expandedHeight != 0.0f;
|
mExpanded = expandedHeight != 0.0f;
|
||||||
@@ -258,8 +276,10 @@ public class NotificationRoundnessManager implements Dumpable {
|
|||||||
mNotifLogger.onSectionCornersUpdated(sections, anyChanged);
|
mNotifLogger.onSectionCornersUpdated(sections, anyChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleRemovedOldViews(NotificationSection[] sections,
|
private boolean handleRemovedOldViews(
|
||||||
ExpandableView[] oldViews, boolean first) {
|
NotificationSection[] sections,
|
||||||
|
ExpandableView[] oldViews,
|
||||||
|
boolean first) {
|
||||||
boolean anyChanged = false;
|
boolean anyChanged = false;
|
||||||
for (ExpandableView oldView : oldViews) {
|
for (ExpandableView oldView : oldViews) {
|
||||||
if (oldView != null) {
|
if (oldView != null) {
|
||||||
@@ -289,8 +309,10 @@ public class NotificationRoundnessManager implements Dumpable {
|
|||||||
return anyChanged;
|
return anyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleAddedNewViews(NotificationSection[] sections,
|
private boolean handleAddedNewViews(
|
||||||
ExpandableView[] oldViews, boolean first) {
|
NotificationSection[] sections,
|
||||||
|
ExpandableView[] oldViews,
|
||||||
|
boolean first) {
|
||||||
boolean anyChanged = false;
|
boolean anyChanged = false;
|
||||||
for (NotificationSection section : sections) {
|
for (NotificationSection section : sections) {
|
||||||
ExpandableView newView =
|
ExpandableView newView =
|
||||||
|
|||||||
@@ -1188,7 +1188,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
if (mChildrenToAddAnimated.contains(child)) {
|
if (mChildrenToAddAnimated.contains(child)) {
|
||||||
final int startingPosition = getPositionInLinearLayout(child);
|
final int startingPosition = getPositionInLinearLayout(child);
|
||||||
final int childHeight = getIntrinsicHeight(child) + mPaddingBetweenElements;
|
final int childHeight = getIntrinsicHeight(child) + mPaddingBetweenElements;
|
||||||
@@ -1658,7 +1658,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
// find the view under the pointer, accounting for GONE views
|
// find the view under the pointer, accounting for GONE views
|
||||||
final int count = getChildCount();
|
final int count = getChildCount();
|
||||||
for (int childIdx = 0; childIdx < count; childIdx++) {
|
for (int childIdx = 0; childIdx < count; childIdx++) {
|
||||||
ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
|
ExpandableView slidingChild = getChildAtIndex(childIdx);
|
||||||
if (slidingChild.getVisibility() != VISIBLE
|
if (slidingChild.getVisibility() != VISIBLE
|
||||||
|| (ignoreDecors && slidingChild instanceof StackScrollerDecorView)) {
|
|| (ignoreDecors && slidingChild instanceof StackScrollerDecorView)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1691,6 +1691,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ExpandableView getChildAtIndex(int index) {
|
||||||
|
return (ExpandableView) getChildAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
|
public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
|
||||||
getLocationOnScreen(mTempInt2);
|
getLocationOnScreen(mTempInt2);
|
||||||
return getChildAtPosition(touchX - mTempInt2[0], touchY - mTempInt2[1]);
|
return getChildAtPosition(touchX - mTempInt2[0], touchY - mTempInt2[1]);
|
||||||
@@ -2276,7 +2280,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
if (child.getVisibility() != View.GONE && !child.willBeGone() && child != mShelf) {
|
if (child.getVisibility() != View.GONE && !child.willBeGone() && child != mShelf) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@@ -2496,7 +2500,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
private ExpandableView getLastChildWithBackground() {
|
private ExpandableView getLastChildWithBackground() {
|
||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
for (int i = childCount - 1; i >= 0; i--) {
|
for (int i = childCount - 1; i >= 0; i--) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
if (child.getVisibility() != View.GONE && !(child instanceof StackScrollerDecorView)
|
if (child.getVisibility() != View.GONE && !(child instanceof StackScrollerDecorView)
|
||||||
&& child != mShelf) {
|
&& child != mShelf) {
|
||||||
return child;
|
return child;
|
||||||
@@ -2509,7 +2513,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
private ExpandableView getFirstChildWithBackground() {
|
private ExpandableView getFirstChildWithBackground() {
|
||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
if (child.getVisibility() != View.GONE && !(child instanceof StackScrollerDecorView)
|
if (child.getVisibility() != View.GONE && !(child instanceof StackScrollerDecorView)
|
||||||
&& child != mShelf) {
|
&& child != mShelf) {
|
||||||
return child;
|
return child;
|
||||||
@@ -2523,7 +2527,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
ArrayList<ExpandableView> children = new ArrayList<>();
|
ArrayList<ExpandableView> children = new ArrayList<>();
|
||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
if (child.getVisibility() != View.GONE
|
if (child.getVisibility() != View.GONE
|
||||||
&& !(child instanceof StackScrollerDecorView)
|
&& !(child instanceof StackScrollerDecorView)
|
||||||
&& child != mShelf) {
|
&& child != mShelf) {
|
||||||
@@ -2882,7 +2886,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
}
|
}
|
||||||
int position = 0;
|
int position = 0;
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
boolean notGone = child.getVisibility() != View.GONE;
|
boolean notGone = child.getVisibility() != View.GONE;
|
||||||
if (notGone && !child.hasNoContentHeight()) {
|
if (notGone && !child.hasNoContentHeight()) {
|
||||||
if (position != 0) {
|
if (position != 0) {
|
||||||
@@ -2936,7 +2940,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
}
|
}
|
||||||
mAmbientState.setLastVisibleBackgroundChild(lastChild);
|
mAmbientState.setLastVisibleBackgroundChild(lastChild);
|
||||||
// TODO: Refactor SectionManager and put the RoundnessManager there.
|
// TODO: Refactor SectionManager and put the RoundnessManager there.
|
||||||
mController.getNoticationRoundessManager().updateRoundedChildren(mSections);
|
mController.getNotificationRoundnessManager().updateRoundedChildren(mSections);
|
||||||
mAnimateBottomOnLayout = false;
|
mAnimateBottomOnLayout = false;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
@@ -3968,7 +3972,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
|
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
|
||||||
private void clearUserLockedViews() {
|
private void clearUserLockedViews() {
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
if (child instanceof ExpandableNotificationRow) {
|
if (child instanceof ExpandableNotificationRow) {
|
||||||
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
|
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
|
||||||
row.setUserLocked(false);
|
row.setUserLocked(false);
|
||||||
@@ -3981,7 +3985,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
// lets make sure nothing is transient anymore
|
// lets make sure nothing is transient anymore
|
||||||
clearTemporaryViewsInGroup(this);
|
clearTemporaryViewsInGroup(this);
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
if (child instanceof ExpandableNotificationRow) {
|
if (child instanceof ExpandableNotificationRow) {
|
||||||
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
|
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
|
||||||
clearTemporaryViewsInGroup(row.getChildrenContainer());
|
clearTemporaryViewsInGroup(row.getChildrenContainer());
|
||||||
@@ -4230,7 +4234,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
if (hideSensitive != mAmbientState.isHideSensitive()) {
|
if (hideSensitive != mAmbientState.isHideSensitive()) {
|
||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
ExpandableView v = (ExpandableView) getChildAt(i);
|
ExpandableView v = getChildAtIndex(i);
|
||||||
v.setHideSensitiveForIntrinsicHeight(hideSensitive);
|
v.setHideSensitiveForIntrinsicHeight(hideSensitive);
|
||||||
}
|
}
|
||||||
mAmbientState.setHideSensitive(hideSensitive);
|
mAmbientState.setHideSensitive(hideSensitive);
|
||||||
@@ -4265,7 +4269,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
private void applyCurrentState() {
|
private void applyCurrentState() {
|
||||||
int numChildren = getChildCount();
|
int numChildren = getChildCount();
|
||||||
for (int i = 0; i < numChildren; i++) {
|
for (int i = 0; i < numChildren; i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
child.applyViewState();
|
child.applyViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4285,7 +4289,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
|
|
||||||
// Lefts first sort by Z difference
|
// Lefts first sort by Z difference
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
if (child.getVisibility() != GONE) {
|
if (child.getVisibility() != GONE) {
|
||||||
mTmpSortedChildren.add(child);
|
mTmpSortedChildren.add(child);
|
||||||
}
|
}
|
||||||
@@ -4512,7 +4516,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
public void setClearAllInProgress(boolean clearAllInProgress) {
|
public void setClearAllInProgress(boolean clearAllInProgress) {
|
||||||
mClearAllInProgress = clearAllInProgress;
|
mClearAllInProgress = clearAllInProgress;
|
||||||
mAmbientState.setClearAllInProgress(clearAllInProgress);
|
mAmbientState.setClearAllInProgress(clearAllInProgress);
|
||||||
mController.getNoticationRoundessManager().setClearAllInProgress(clearAllInProgress);
|
mController.getNotificationRoundnessManager().setClearAllInProgress(clearAllInProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean getClearAllInProgress() {
|
boolean getClearAllInProgress() {
|
||||||
@@ -4555,7 +4559,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
final int count = getChildCount();
|
final int count = getChildCount();
|
||||||
float max = 0;
|
float max = 0;
|
||||||
for (int childIdx = 0; childIdx < count; childIdx++) {
|
for (int childIdx = 0; childIdx < count; childIdx++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(childIdx);
|
ExpandableView child = getChildAtIndex(childIdx);
|
||||||
if (child.getVisibility() == GONE) {
|
if (child.getVisibility() == GONE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -4586,7 +4590,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
public boolean isBelowLastNotification(float touchX, float touchY) {
|
public boolean isBelowLastNotification(float touchX, float touchY) {
|
||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
for (int i = childCount - 1; i >= 0; i--) {
|
for (int i = childCount - 1; i >= 0; i--) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
if (child.getVisibility() != View.GONE) {
|
if (child.getVisibility() != View.GONE) {
|
||||||
float childTop = child.getY();
|
float childTop = child.getY();
|
||||||
if (childTop > touchY) {
|
if (childTop > touchY) {
|
||||||
@@ -5052,7 +5056,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
ExpandableView child = (ExpandableView) getChildAt(i);
|
ExpandableView child = getChildAtIndex(i);
|
||||||
child.dump(pw, args);
|
child.dump(pw, args);
|
||||||
pw.println();
|
pw.println();
|
||||||
}
|
}
|
||||||
@@ -5341,7 +5345,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
float wakeUplocation = -1f;
|
float wakeUplocation = -1f;
|
||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
ExpandableView view = (ExpandableView) getChildAt(i);
|
ExpandableView view = getChildAtIndex(i);
|
||||||
if (view.getVisibility() == View.GONE) {
|
if (view.getVisibility() == View.GONE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -5380,7 +5384,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
public void setController(
|
public void setController(
|
||||||
NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
|
NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
|
||||||
mController = notificationStackScrollLayoutController;
|
mController = notificationStackScrollLayoutController;
|
||||||
mController.getNoticationRoundessManager().setAnimatedChildren(mChildrenToAddAnimated);
|
mController.getNotificationRoundnessManager().setAnimatedChildren(mChildrenToAddAnimated);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSwipedOutView(View v) {
|
void addSwipedOutView(View v) {
|
||||||
@@ -5391,31 +5395,22 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
if (!(viewSwiped instanceof ExpandableNotificationRow)) {
|
if (!(viewSwiped instanceof ExpandableNotificationRow)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final int indexOfSwipedView = indexOfChild(viewSwiped);
|
|
||||||
if (indexOfSwipedView < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mSectionsManager.updateFirstAndLastViewsForAllSections(
|
mSectionsManager.updateFirstAndLastViewsForAllSections(
|
||||||
mSections, getChildrenWithBackground());
|
mSections,
|
||||||
View viewBefore = null;
|
getChildrenWithBackground()
|
||||||
if (indexOfSwipedView > 0) {
|
);
|
||||||
viewBefore = getChildAt(indexOfSwipedView - 1);
|
|
||||||
if (mSectionsManager.beginsSection(viewSwiped, viewBefore)) {
|
RoundableTargets targets = mController.getNotificationTargetsHelper().findRoundableTargets(
|
||||||
viewBefore = null;
|
(ExpandableNotificationRow) viewSwiped,
|
||||||
}
|
this,
|
||||||
}
|
mSectionsManager
|
||||||
View viewAfter = null;
|
);
|
||||||
if (indexOfSwipedView < getChildCount()) {
|
|
||||||
viewAfter = getChildAt(indexOfSwipedView + 1);
|
mController.getNotificationRoundnessManager()
|
||||||
if (mSectionsManager.beginsSection(viewAfter, viewSwiped)) {
|
|
||||||
viewAfter = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mController.getNoticationRoundessManager()
|
|
||||||
.setViewsAffectedBySwipe(
|
.setViewsAffectedBySwipe(
|
||||||
(ExpandableView) viewBefore,
|
targets.getBefore(),
|
||||||
(ExpandableView) viewSwiped,
|
targets.getSwiped(),
|
||||||
(ExpandableView) viewAfter);
|
targets.getAfter());
|
||||||
|
|
||||||
updateFirstAndLastBackgroundViews();
|
updateFirstAndLastBackgroundViews();
|
||||||
requestDisallowInterceptTouchEvent(true);
|
requestDisallowInterceptTouchEvent(true);
|
||||||
@@ -5426,7 +5421,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
|
|
||||||
void onSwipeEnd() {
|
void onSwipeEnd() {
|
||||||
updateFirstAndLastBackgroundViews();
|
updateFirstAndLastBackgroundViews();
|
||||||
mController.getNoticationRoundessManager()
|
mController.getNotificationRoundnessManager()
|
||||||
.setViewsAffectedBySwipe(null, null, null);
|
.setViewsAffectedBySwipe(null, null, null);
|
||||||
// Round bottom corners for notification right before shelf.
|
// Round bottom corners for notification right before shelf.
|
||||||
mShelf.updateAppearance();
|
mShelf.updateAppearance();
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ public class NotificationStackScrollLayoutController {
|
|||||||
private int mBarState;
|
private int mBarState;
|
||||||
private HeadsUpAppearanceController mHeadsUpAppearanceController;
|
private HeadsUpAppearanceController mHeadsUpAppearanceController;
|
||||||
private final FeatureFlags mFeatureFlags;
|
private final FeatureFlags mFeatureFlags;
|
||||||
|
private final NotificationTargetsHelper mNotificationTargetsHelper;
|
||||||
|
|
||||||
private View mLongPressedView;
|
private View mLongPressedView;
|
||||||
|
|
||||||
@@ -642,7 +643,8 @@ public class NotificationStackScrollLayoutController {
|
|||||||
StackStateLogger stackLogger,
|
StackStateLogger stackLogger,
|
||||||
NotificationStackScrollLogger logger,
|
NotificationStackScrollLogger logger,
|
||||||
NotificationStackSizeCalculator notificationStackSizeCalculator,
|
NotificationStackSizeCalculator notificationStackSizeCalculator,
|
||||||
FeatureFlags featureFlags) {
|
FeatureFlags featureFlags,
|
||||||
|
NotificationTargetsHelper notificationTargetsHelper) {
|
||||||
mStackStateLogger = stackLogger;
|
mStackStateLogger = stackLogger;
|
||||||
mLogger = logger;
|
mLogger = logger;
|
||||||
mAllowLongPress = allowLongPress;
|
mAllowLongPress = allowLongPress;
|
||||||
@@ -679,6 +681,7 @@ public class NotificationStackScrollLayoutController {
|
|||||||
mRemoteInputManager = remoteInputManager;
|
mRemoteInputManager = remoteInputManager;
|
||||||
mShadeController = shadeController;
|
mShadeController = shadeController;
|
||||||
mFeatureFlags = featureFlags;
|
mFeatureFlags = featureFlags;
|
||||||
|
mNotificationTargetsHelper = notificationTargetsHelper;
|
||||||
updateResources();
|
updateResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,7 +1383,7 @@ public class NotificationStackScrollLayoutController {
|
|||||||
return mView.calculateGapHeight(previousView, child, count);
|
return mView.calculateGapHeight(previousView, child, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationRoundnessManager getNoticationRoundessManager() {
|
NotificationRoundnessManager getNotificationRoundnessManager() {
|
||||||
return mNotificationRoundnessManager;
|
return mNotificationRoundnessManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1537,6 +1540,10 @@ public class NotificationStackScrollLayoutController {
|
|||||||
mNotificationActivityStarter = activityStarter;
|
mNotificationActivityStarter = activityStarter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NotificationTargetsHelper getNotificationTargetsHelper() {
|
||||||
|
return mNotificationTargetsHelper;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum for UiEvent logged from this class
|
* Enum for UiEvent logged from this class
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package com.android.systemui.statusbar.notification.stack
|
||||||
|
|
||||||
|
import androidx.core.view.children
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.flags.FeatureFlags
|
||||||
|
import com.android.systemui.flags.Flags
|
||||||
|
import com.android.systemui.statusbar.notification.Roundable
|
||||||
|
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
|
||||||
|
import com.android.systemui.statusbar.notification.row.ExpandableView
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class that helps us find the targets of an animation, often used to find the notification
|
||||||
|
* ([Roundable]) above and below the current one (see [findRoundableTargets]).
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class NotificationTargetsHelper
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
featureFlags: FeatureFlags,
|
||||||
|
) {
|
||||||
|
private val isNotificationGroupCornerEnabled =
|
||||||
|
featureFlags.isEnabled(Flags.NOTIFICATION_GROUP_CORNER)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method looks for views that can be rounded (and implement [Roundable]) during a
|
||||||
|
* notification swipe.
|
||||||
|
* @return The [Roundable] targets above/below the [viewSwiped] (if available). The
|
||||||
|
* [RoundableTargets.before] and [RoundableTargets.after] parameters can be `null` if there is
|
||||||
|
* no above/below notification or the notification is not part of the same section.
|
||||||
|
*/
|
||||||
|
fun findRoundableTargets(
|
||||||
|
viewSwiped: ExpandableNotificationRow,
|
||||||
|
stackScrollLayout: NotificationStackScrollLayout,
|
||||||
|
sectionsManager: NotificationSectionsManager,
|
||||||
|
): RoundableTargets {
|
||||||
|
val viewBefore: Roundable?
|
||||||
|
val viewAfter: Roundable?
|
||||||
|
|
||||||
|
val notificationParent = viewSwiped.notificationParent
|
||||||
|
val childrenContainer = notificationParent?.childrenContainer
|
||||||
|
val visibleStackChildren =
|
||||||
|
stackScrollLayout.children
|
||||||
|
.filterIsInstance<ExpandableView>()
|
||||||
|
.filter { it.isVisible }
|
||||||
|
.toList()
|
||||||
|
if (notificationParent != null && childrenContainer != null) {
|
||||||
|
// We are inside a notification group
|
||||||
|
|
||||||
|
if (!isNotificationGroupCornerEnabled) {
|
||||||
|
return RoundableTargets(null, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
val visibleGroupChildren = childrenContainer.attachedChildren.filter { it.isVisible }
|
||||||
|
val indexOfParentSwipedView = visibleGroupChildren.indexOf(viewSwiped)
|
||||||
|
|
||||||
|
viewBefore =
|
||||||
|
visibleGroupChildren.getOrNull(indexOfParentSwipedView - 1)
|
||||||
|
?: childrenContainer.notificationHeaderWrapper
|
||||||
|
|
||||||
|
viewAfter =
|
||||||
|
visibleGroupChildren.getOrNull(indexOfParentSwipedView + 1)
|
||||||
|
?: visibleStackChildren.indexOf(notificationParent).let {
|
||||||
|
visibleStackChildren.getOrNull(it + 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Assumption: we are inside the NotificationStackScrollLayout
|
||||||
|
|
||||||
|
val indexOfSwipedView = visibleStackChildren.indexOf(viewSwiped)
|
||||||
|
|
||||||
|
viewBefore =
|
||||||
|
visibleStackChildren.getOrNull(indexOfSwipedView - 1)?.takeIf {
|
||||||
|
!sectionsManager.beginsSection(viewSwiped, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewAfter =
|
||||||
|
visibleStackChildren.getOrNull(indexOfSwipedView + 1)?.takeIf {
|
||||||
|
!sectionsManager.beginsSection(it, viewSwiped)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RoundableTargets(
|
||||||
|
before = viewBefore,
|
||||||
|
swiped = viewSwiped,
|
||||||
|
after = viewAfter,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object contains targets above/below the [swiped] (if available). The [before] and [after]
|
||||||
|
* parameters can be `null` if there is no above/below notification or the notification is not part
|
||||||
|
* of the same section.
|
||||||
|
*/
|
||||||
|
data class RoundableTargets(
|
||||||
|
val before: Roundable?,
|
||||||
|
val swiped: ExpandableNotificationRow?,
|
||||||
|
val after: Roundable?,
|
||||||
|
)
|
||||||
@@ -31,6 +31,7 @@ import com.android.systemui.R;
|
|||||||
import com.android.systemui.animation.ShadeInterpolation;
|
import com.android.systemui.animation.ShadeInterpolation;
|
||||||
import com.android.systemui.statusbar.EmptyShadeView;
|
import com.android.systemui.statusbar.EmptyShadeView;
|
||||||
import com.android.systemui.statusbar.NotificationShelf;
|
import com.android.systemui.statusbar.NotificationShelf;
|
||||||
|
import com.android.systemui.statusbar.notification.SourceType;
|
||||||
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
|
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
||||||
@@ -804,7 +805,7 @@ public class StackScrollAlgorithm {
|
|||||||
row.isLastInSection() ? 1f : (mSmallCornerRadius / mLargeCornerRadius);
|
row.isLastInSection() ? 1f : (mSmallCornerRadius / mLargeCornerRadius);
|
||||||
final float roundness = computeCornerRoundnessForPinnedHun(mHostView.getHeight(),
|
final float roundness = computeCornerRoundnessForPinnedHun(mHostView.getHeight(),
|
||||||
ambientState.getStackY(), getMaxAllowedChildHeight(row), originalCornerRadius);
|
ambientState.getStackY(), getMaxAllowedChildHeight(row), originalCornerRadius);
|
||||||
row.setBottomRoundness(roundness, /* animate= */ false);
|
row.requestBottomRoundness(roundness, /* animate = */ false, SourceType.OnScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|||||||
@@ -147,8 +147,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mFirst, mSecond),
|
createSection(mFirst, mSecond),
|
||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(1.0f, mSecond.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mSecond.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mSecond.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mSecond.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -170,13 +170,13 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
when(testHelper.getStatusBarStateController().isDozing()).thenReturn(true);
|
when(testHelper.getStatusBarStateController().isDozing()).thenReturn(true);
|
||||||
row.setHeadsUp(true);
|
row.setHeadsUp(true);
|
||||||
mRoundnessManager.updateView(entry.getRow(), false);
|
mRoundnessManager.updateView(entry.getRow(), false);
|
||||||
Assert.assertEquals(1f, row.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(1f, row.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(1f, row.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(1f, row.getTopRoundness(), 0.0f);
|
||||||
|
|
||||||
row.setHeadsUp(false);
|
row.setHeadsUp(false);
|
||||||
mRoundnessManager.updateView(entry.getRow(), false);
|
mRoundnessManager.updateView(entry.getRow(), false);
|
||||||
Assert.assertEquals(mSmallRadiusRatio, row.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, row.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(mSmallRadiusRatio, row.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, row.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -185,8 +185,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mFirst, mFirst),
|
createSection(mFirst, mFirst),
|
||||||
createSection(null, mSecond)
|
createSection(null, mSecond)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(1.0f, mSecond.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mSecond.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mSecond.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mSecond.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -195,8 +195,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mFirst, mFirst),
|
createSection(mFirst, mFirst),
|
||||||
createSection(mSecond, null)
|
createSection(mSecond, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mSecond.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mSecond.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(1.0f, mSecond.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mSecond.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -205,8 +205,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mFirst, null),
|
createSection(mFirst, null),
|
||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -215,8 +215,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mSecond, mSecond),
|
createSection(mSecond, mSecond),
|
||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -226,8 +226,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mSecond, mSecond),
|
createSection(mSecond, mSecond),
|
||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -238,8 +238,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mSecond, mSecond),
|
createSection(mSecond, mSecond),
|
||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -250,8 +250,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mSecond, mSecond),
|
createSection(mSecond, mSecond),
|
||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -262,8 +262,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mSecond, mSecond),
|
createSection(mSecond, mSecond),
|
||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -274,8 +274,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mSecond, mSecond),
|
createSection(mSecond, mSecond),
|
||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -286,8 +286,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(mSecond, mSecond),
|
createSection(mSecond, mSecond),
|
||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
Assert.assertEquals(0.5f, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(0.5f, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(0.5f, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(0.5f, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -298,8 +298,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
createSection(null, null)
|
createSection(null, null)
|
||||||
});
|
});
|
||||||
mFirst.setHeadsUpAnimatingAway(true);
|
mFirst.setHeadsUpAnimatingAway(true);
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -312,8 +312,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
});
|
});
|
||||||
mFirst.setHeadsUpAnimatingAway(true);
|
mFirst.setHeadsUpAnimatingAway(true);
|
||||||
mFirst.setHeadsUpAnimatingAway(false);
|
mFirst.setHeadsUpAnimatingAway(false);
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mFirst.getCurrentBottomRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f);
|
||||||
Assert.assertEquals(mSmallRadiusRatio, mFirst.getCurrentTopRoundness(), 0.0f);
|
Assert.assertEquals(mSmallRadiusRatio, mFirst.getTopRoundness(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
|
|||||||
@Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
|
@Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
|
||||||
@Mock private ShadeTransitionController mShadeTransitionController;
|
@Mock private ShadeTransitionController mShadeTransitionController;
|
||||||
@Mock private FeatureFlags mFeatureFlags;
|
@Mock private FeatureFlags mFeatureFlags;
|
||||||
|
@Mock private NotificationTargetsHelper mNotificationTargetsHelper;
|
||||||
|
|
||||||
@Captor
|
@Captor
|
||||||
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
|
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
|
||||||
@@ -177,7 +178,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
|
|||||||
mStackLogger,
|
mStackLogger,
|
||||||
mLogger,
|
mLogger,
|
||||||
mNotificationStackSizeCalculator,
|
mNotificationStackSizeCalculator,
|
||||||
mFeatureFlags
|
mFeatureFlags,
|
||||||
|
mNotificationTargetsHelper
|
||||||
);
|
);
|
||||||
|
|
||||||
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
|
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
|||||||
mStackScroller.setCentralSurfaces(mCentralSurfaces);
|
mStackScroller.setCentralSurfaces(mCentralSurfaces);
|
||||||
mStackScroller.setEmptyShadeView(mEmptyShadeView);
|
mStackScroller.setEmptyShadeView(mEmptyShadeView);
|
||||||
when(mStackScrollLayoutController.isHistoryEnabled()).thenReturn(true);
|
when(mStackScrollLayoutController.isHistoryEnabled()).thenReturn(true);
|
||||||
when(mStackScrollLayoutController.getNoticationRoundessManager())
|
when(mStackScrollLayoutController.getNotificationRoundnessManager())
|
||||||
.thenReturn(mNotificationRoundnessManager);
|
.thenReturn(mNotificationRoundnessManager);
|
||||||
mStackScroller.setController(mStackScrollLayoutController);
|
mStackScroller.setController(mStackScrollLayoutController);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package com.android.systemui.statusbar.notification.stack
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.testing.TestableLooper
|
||||||
|
import android.testing.TestableLooper.RunWithLooper
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.flags.FakeFeatureFlags
|
||||||
|
import com.android.systemui.flags.Flags
|
||||||
|
import com.android.systemui.statusbar.notification.row.NotificationTestHelper
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
|
import junit.framework.Assert.assertEquals
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
/** Tests for {@link NotificationTargetsHelper}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@RunWithLooper
|
||||||
|
class NotificationTargetsHelperTest : SysuiTestCase() {
|
||||||
|
lateinit var notificationTestHelper: NotificationTestHelper
|
||||||
|
private val sectionsManager: NotificationSectionsManager = mock()
|
||||||
|
private val stackScrollLayout: NotificationStackScrollLayout = mock()
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
allowTestableLooperAsMainThread()
|
||||||
|
notificationTestHelper =
|
||||||
|
NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun notificationTargetsHelper(
|
||||||
|
notificationGroupCorner: Boolean = true,
|
||||||
|
) =
|
||||||
|
NotificationTargetsHelper(
|
||||||
|
FakeFeatureFlags().apply {
|
||||||
|
set(Flags.NOTIFICATION_GROUP_CORNER, notificationGroupCorner)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun targetsForFirstNotificationInGroup() {
|
||||||
|
val children = notificationTestHelper.createGroup(3).childrenContainer
|
||||||
|
val swiped = children.attachedChildren[0]
|
||||||
|
|
||||||
|
val actual =
|
||||||
|
notificationTargetsHelper()
|
||||||
|
.findRoundableTargets(
|
||||||
|
viewSwiped = swiped,
|
||||||
|
stackScrollLayout = stackScrollLayout,
|
||||||
|
sectionsManager = sectionsManager,
|
||||||
|
)
|
||||||
|
|
||||||
|
val expected =
|
||||||
|
RoundableTargets(
|
||||||
|
before = children.notificationHeaderWrapper, // group header
|
||||||
|
swiped = swiped,
|
||||||
|
after = children.attachedChildren[1],
|
||||||
|
)
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun targetsForMiddleNotificationInGroup() {
|
||||||
|
val children = notificationTestHelper.createGroup(3).childrenContainer
|
||||||
|
val swiped = children.attachedChildren[1]
|
||||||
|
|
||||||
|
val actual =
|
||||||
|
notificationTargetsHelper()
|
||||||
|
.findRoundableTargets(
|
||||||
|
viewSwiped = swiped,
|
||||||
|
stackScrollLayout = stackScrollLayout,
|
||||||
|
sectionsManager = sectionsManager,
|
||||||
|
)
|
||||||
|
|
||||||
|
val expected =
|
||||||
|
RoundableTargets(
|
||||||
|
before = children.attachedChildren[0],
|
||||||
|
swiped = swiped,
|
||||||
|
after = children.attachedChildren[2],
|
||||||
|
)
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun targetsForLastNotificationInGroup() {
|
||||||
|
val children = notificationTestHelper.createGroup(3).childrenContainer
|
||||||
|
val swiped = children.attachedChildren[2]
|
||||||
|
|
||||||
|
val actual =
|
||||||
|
notificationTargetsHelper()
|
||||||
|
.findRoundableTargets(
|
||||||
|
viewSwiped = swiped,
|
||||||
|
stackScrollLayout = stackScrollLayout,
|
||||||
|
sectionsManager = sectionsManager,
|
||||||
|
)
|
||||||
|
|
||||||
|
val expected =
|
||||||
|
RoundableTargets(
|
||||||
|
before = children.attachedChildren[1],
|
||||||
|
swiped = swiped,
|
||||||
|
after = null,
|
||||||
|
)
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user